InputStream input = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(input));
while(true){
br.readLine();
}
其中,Sender 是一个实现了 Runnable 接口的类,用它来专门负责发送数据,主线程只需要不听地接受数据就行。Sender 类中的 run() 方法应该具有以下代码:
PrintWriter pw = new PrintWriter(socket.getOutputStream());
while(true){
pw.println(数据);
}
即使按上面的方式做了,程序还是有问题,因为它只能在一个时间内为一个客户服务,不能同时为多个客户服务,如多要想同时为多个客户服务,服务器应具有类似以下的代码:
ServerSocker ss = new ServerSocker(端口号);
socket = null;
while(true){
socket = ss.accept();
Thread thread1 = new Thread(new Sender());
thread1.start();
Thread thread2 = new Thread(new Receiver());
thread2.start();
}
在这里,新开启了 2 个线程分别负责接收和发送。Receiver 是一个与 Sender 非常相似的类,它主要用来接收数据。在客户端,我们同样应开启 2 个线程:
Socket socket = new Socket(服务器 IP, 端口号);
Sender sender = new Sender(socket);
Thread thread1 = new Thread(sender);
thread1.start();
Receiver receiver = new Receiver(socket);
Thread thread2 = new Thread(receiver);
thread2.start();
我们来亲自动手实现案例
实现客户端
- /* 头文件 */
- #include < stdio.h > #include "winsock2.h"
- /* 常量 */
- #define RECV_BUFFER_SIZE 8192
- /*************************************
- * main
- * 功能 socket通信客户端
- **************************************/
- void main(int argc, char * argv[]) {
- // 变量定义
- SOCKADDR_IN clientService; // 地址
- SOCKET ConnectSocket; // socket
- WSADATA wsaData; // 库
- LPVOID recvbuf; // 接收缓存
- int bytesSent;
- int bytesRecv = 0;
- char sendbuf[32] = "get information"; // 默认发送的数据
- // 初始化socket库, 保存ws2_32.dll已经加载
- int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != NO_ERROR) printf("Error at WSAStartup()\n");
- // 创建socket
- ConnectSocket = socket(AF_INET, // IPv4
- SOCK_STREAM, // 顺序的、可靠的、基于连接的、双向的数据流通信
- IPPROTO_TCP // 使用TCP协议
- );
- if (ConnectSocket == INVALID_SOCKET) {
- printf("Error at socket(): %ld\n", WSAGetLastError());
- WSACleanup();
- return;
- }
- // 设置服务端的通信协议、IP地址、端口
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
- clientService.sin_port = htons(10000);
- // 连接到服务端
- if (connect(ConnectSocket, // socket
- (SOCKADDR * ) & clientService, // 地址
- sizeof(clientService) // 地址的大小
- ) == SOCKET_ERROR) {
- printf("Failed to connect(%d)\n", WSAGetLastError());
- WSACleanup();
- return;
- }
- // 准备发送数据
- // 如果输入参数是-d,那么发送的数据是"download file"否则是"get information"
- if (argc == 2 && (!lstrcmp(argv[1], "-d"))) {
- lstrcpyn(sendbuf, "download file", 32);
- }
- // 向服务端发送数据
- bytesSent = send(ConnectSocket, // socket
- sendbuf, // 发送的数据
- lstrlen(sendbuf) + 1, // 数据长度
- 0); // 无标志
- if (bytesSent == SOCKET_ERROR) {
- printf("send error (%d)\n", WSAGetLastError());
- closesocket(ConnectSocket);
- return;
- }
- printf("Bytes Sent: %ld\n", bytesSent);
- // 准备接收数据
- recvbuf = HeapAlloc(GetProcessHeap(), 0, RECV_BUFFER_SIZE);
- // 循环接收
- while (bytesRecv != SOCKET_ERROR) {
- //Sleep(50);
- bytesRecv = recv(ConnectSocket, // socket
- recvbuf, // 接收数据缓存
- RECV_BUFFER_SIZE, // 缓存大小
- 0); // 无标志
- if (bytesRecv == 0) {
- printf("Connection Closed.\n");
- break;
- }
- // TODO,处理接收的数据,这里只简单的将收到的数据大小显示
- printf("Bytes Recv: %ld\n", bytesRecv);
- }
- HeapFree(GetProcessHeap(), 0, recvbuf);
- WSACleanup();
- return;
- }
实现服务端
- /* 头文件 */
- #include < winsock2.h > #include < ws2tcpip.h > #include < stdio.h >
- /* 常量 */
- #define DEFAULT_PORT "10000" // 端口
- #define MAX_REQUEST 1024 // 接收数据的缓存大小
- #define BUF_SIZE 4096 // 发送数据的缓存大小
- /*************************************
- * CommunicationThread
- * 功能 用于接收和发送数据的线程
- * 为每一个连接的客户端创建一个接收发送数据的线程,
- * 可以使用多个客户端同时连接到服务端
- * 参数 lpParameter,SOKCET
- **************************************/
- DWORD WINAPI CommunicationThread(LPVOID lpParameter) {
- DWORD dwTid = GetCurrentThreadId();
- // 获得参数sokcet
- SOCKET socket = (SOCKET) lpParameter;
- // 为接收数据分配空间
- LPSTR szRequest = HeapAlloc(GetProcessHeap(), 0, MAX_REQUEST);
- int iResult;
- int bytesSent; // 用于保存send的返回值,实际发送的数据的大小
- // 接收数据
- iResult = recv(socket, // socket
- szRequest, // 接收缓存
- MAX_REQUEST, // 缓存大小
- 0); // 标志
- if (iResult == 0) // 接收数据失败,连接已经关闭
- {
- printf("Connection closing...\n");
- HeapFree(GetProcessHeap(), 0, szRequest);
- closesocket(socket);
- return 1;
- } else if (iResult == SOCKET_ERROR) // 接收数据失败,socket错误
- {
- printf("recv failed: %d\n", WSAGetLastError());
- HeapFree(GetProcessHeap(), 0, szRequest);
- closesocket(socket);
- return 1;
- } else if (iResult > 0) // 接收数据成功
- {
- // 显示接收到的数据
- printf("\tCommunicationThread(%d)\tBytes received: %d\n", dwTid, iResult);
- printf("\tCommunicationThread(%d)\trequest string is (%s)\n", dwTid, szRequest);
- // 如果接收到的数据是"download file"
- if (lstrcmpi(szRequest, "download file") == 0) {
- // 读取文件download.txt将发送
- HANDLE hFile;
- LPVOID lpReadBuf; // 发送缓存
- DWORD dwBytesRead;
- DWORD dwFileSize;
- DWORD dwSendFile = 0;
- hFile = CreateFile("download.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE) {
- printf("\tCommunicationThread\tCould not open file (error %d)\n", GetLastError());
- send(socket, "error", 6, 0);
- closesocket(socket);
- return 1;
- }
- // 分配发送数据缓存
- lpReadBuf = HeapAlloc(GetProcessHeap(), 0, BUF_SIZE);
- // 获取文件大小
- dwFileSize = GetFileSize(hFile, NULL);
- // 循环发送
- while (1) {
- // 读文件到缓存
- if (!ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL)) {
- printf("\tCommunicationThread\tCould not read from file (error %d)\n", GetLastError());
- closesocket(socket);
- CloseHandle(hFile);
- return 1;
- }
- // 发送读取的文件数据
- bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);
- if (bytesSent == SOCKET_ERROR) {
- printf("\tCommunicationThread\tsend error %d\n", WSAGetLastError());
- closesocket(socket);
- CloseHandle(hFile);
- return 1;
- }
- // 显示发送数据的大小
- printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
- // 累加,已经发送的大小
- dwSendFile += dwBytesRead;
- // 如果所有文件数据都已经发送
- if (dwSendFile == dwFileSize) {
- printf("\tCommunicationThread\tFile download ok\n");
- break; // 退出循环
- }
- }
- // 释放内存、关闭连接,关闭文件
- HeapFree(GetProcessHeap(), 0, lpReadBuf);
- CloseHandle(hFile);
- closesocket(socket);
- }
- // 如果接收到的数据是"get information"
- else if (lstrcmpi(szRequest, "get information") == 0) {
- // 发送数据
- bytesSent = send(socket, // socket
- "this is information", // 数据
- lstrlen("this is information") + 1, // 数据长度
- 0); // 标志
- // 判断是否成功
- if (bytesSent == SOCKET_ERROR) {
- printf("\tCommunicationThread\tsend error %d\n", WSAGetLastError());
- closesocket(socket);
- return 1;
- }
- printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
- } else // 收到未知数据
- {
- printf("unreferenced request\n");
- }
- }
- // 释放接收数据缓存,关闭socket
- HeapFree(GetProcessHeap(), 0, szRequest);
- closesocket(socket);
- return 0;
- }
- /*************************************
- * int __cdecl main(void)
- * 功能 socket服务端
- **************************************/
- int __cdecl main(void) {
- WSADATA wsaData;
- SOCKET ListenSocket = INVALID_SOCKET; // 监听socket
- SOCKET ClientSocket = INVALID_SOCKET; // 连接socket
- struct addrinfo * result = NULL,
- hints;
- int iResult; // 保存返回结果
- // 初始化Winsock,保证Ws2_32.dll已经加载
- iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != 0) {
- printf("WSAStartup failed: %d\n", iResult);
- return 1;
- }
- // 地址
- ZeroMemory( & hints, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = AI_PASSIVE;
- // 获取主机地址,保证网络协议可用等
- iResult = getaddrinfo(NULL, // 本机
- DEFAULT_PORT, // 端口
- & hints, // 使用的网络协议,连接类型等
- & result); // 结果
- if (iResult != 0) {
- printf("getaddrinfo failed: %d\n", iResult);
- WSACleanup();
- return 1;
- }
- // 创建socket,用于监听
- ListenSocket = socket(result - >ai_family, // 网络协议,AF_INET,IPv4
- result - >ai_socktype, // 类型,SOCK_STREAM
- result - >ai_protocol); // 通信协议,TCP
- if (ListenSocket == INVALID_SOCKET) {
- printf("socket failed: %ld\n", WSAGetLastError());
- freeaddrinfo(result);
- WSACleanup();
- return 1;
- }
- // 绑定到端口
- iResult = bind(ListenSocket, result - >ai_addr, (int) result - >ai_addrlen);
- if (iResult == SOCKET_ERROR) {
- printf("bind failed: %d\n", WSAGetLastError());
- freeaddrinfo(result);
- closesocket(ListenSocket);
- WSACleanup();
- return 1;
- }
- printf("bind\n");
- freeaddrinfo(result); // reuslt不再使用
- // 开始监听
- iResult = listen(ListenSocket, SOMAXCONN);
- printf("start listen......\n");
- if (iResult == SOCKET_ERROR) {
- printf("listen failed: %d\n", WSAGetLastError());
- closesocket(ListenSocket);
- WSACleanup();
- return 1;
- }
- while (1) {
- // 接收客户端的连接,accept函数会等待,直到连接建立
- printf("ready to accept\n");
- ClientSocket = accept(ListenSocket, NULL, NULL);
- // accept函数返回,说明已经有客户端连接
- // 返回连接socket
- printf("accept a connetion\n");
- if (ClientSocket == INVALID_SOCKET) {
- printf("accept failed: %d\n", WSAGetLastError());
- closesocket(ListenSocket);
- break; // 等待连接错误,退出循环
- }
- // 为每一个连接创建一个数据发送的接收线程,
- // 使服务端又可以立即接收其他客户端的连接
- if (!CreateThread(NULL, 0, CommunicationThread, // 线程函数
- (LPVOID) ClientSocket, // 将socket作为参数
- 0, NULL)) {
- printf("Create Thread error (%d)", GetLastError());
- break;
- }
- }
- // 循环退出,释放DLL。
- WSACleanup();
- return 0;
- }
- /* 头文件 */
- #include < winsock2.h > #include < ws2tcpip.h > #include < stdio.h >
- /* 常量 */
- #define DEFAULT_PORT "10000" // 端口
- #define MAX_REQUEST 1024 // 接收数据的缓存大小
- #define BUF_SIZE 4096 // 发送数据的缓存大小
- /*************************************
- * CommunicationThread
- * 功能 用于接收和发送数据的线程
- * 为每一个连接的客户端创建一个接收发送数据的线程,
- * 可以使用多个客户端同时连接到服务端
- * 参数 lpParameter,SOKCET
- **************************************/
- DWORD WINAPI CommunicationThread(LPVOID lpParameter) {
- DWORD dwTid = GetCurrentThreadId();
- // 获得参数sokcet
- SOCKET socket = (SOCKET) lpParameter;
- // 为接收数据分配空间
- LPSTR szRequest = HeapAlloc(GetProcessHeap(), 0, MAX_REQUEST);
- int iResult;
- int bytesSent; // 用于保存send的返回值,实际发送的数据的大小
- // 接收数据
- iResult = recv(socket, // socket
- szRequest, // 接收缓存
- MAX_REQUEST, // 缓存大小
- 0); // 标志
- if (iResult == 0) // 接收数据失败,连接已经关闭
- {
- printf("Connection closing...\n");
- HeapFree(GetProcessHeap(), 0, szRequest);
- closesocket(socket);
- return 1;
- } else if (iResult == SOCKET_ERROR) // 接收数据失败,socket错误
- {
- printf("recv failed: %d\n", WSAGetLastError());
- HeapFree(GetProcessHeap(), 0, szRequest);
- closesocket(socket);
- return 1;
- } else if (iResult > 0) // 接收数据成功
- {
- // 显示接收到的数据
- printf("\tCommunicationThread(%d)\tBytes received: %d\n", dwTid, iResult);
- printf("\tCommunicationThread(%d)\trequest string is (%s)\n", dwTid, szRequest);
- // 如果接收到的数据是"download file"
- if (lstrcmpi(szRequest, "download file") == 0) {
- // 读取文件download.txt将发送
- HANDLE hFile;
- LPVOID lpReadBuf; // 发送缓存
- DWORD dwBytesRead;
- DWORD dwFileSize;
- DWORD dwSendFile = 0;
- hFile = CreateFile("download.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE) {
- printf("\tCommunicationThread\tCould not open file (error %d)\n", GetLastError());
- send(socket, "error", 6, 0);
- closesocket(socket);
- return 1;
- }
- // 分配发送数据缓存
- lpReadBuf = HeapAlloc(GetProcessHeap(), 0, BUF_SIZE);
- // 获取文件大小
- dwFileSize = GetFileSize(hFile, NULL);
- // 循环发送
- while (1) {
- // 读文件到缓存
- if (!ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL)) {
- printf("\tCommunicationThread\tCould not read from file (error %d)\n", GetLastError());
- closesocket(socket);
- CloseHandle(hFile);
- return 1;
- }
- // 发送读取的文件数据
- bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);
- if (bytesSent == SOCKET_ERROR) {
- printf("\tCommunicationThread\tsend error %d\n", WSAGetLastError());
- closesocket(socket);
- CloseHandle(hFile);
- return 1;
- }
- // 显示发送数据的大小
- printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
- // 累加,已经发送的大小
- dwSendFile += dwBytesRead;
- // 如果所有文件数据都已经发送
- if (dwSendFile == dwFileSize) {
- printf("\tCommunicationThread\tFile download ok\n");
- break; // 退出循环
- }
- }
- // 释放内存、关闭连接,关闭文件
- HeapFree(GetProcessHeap(), 0, lpReadBuf);
- CloseHandle(hFile);
- closesocket(socket);
- }
- // 如果接收到的数据是"get information"
- else if (lstrcmpi(szRequest, "get information") == 0) {
- // 发送数据
- bytesSent = send(socket, // socket
- "this is information", // 数据
- lstrlen("this is information") + 1, // 数据长度
- 0); // 标志
- // 判断是否成功
- if (bytesSent == SOCKET_ERROR) {
- printf("\tCommunicationThread\tsend error %d\n", WSAGetLastError());
- closesocket(socket);
- return 1;
- }
- printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
- } else // 收到未知数据
- {
- printf("unreferenced request\n");
- }
- }
- // 释放接收数据缓存,关闭socket
- HeapFree(GetProcessHeap(), 0, szRequest);
- closesocket(socket);
- return 0;
- }
- /*************************************
- * int __cdecl main(void)
- * 功能 socket服务端
- **************************************/
- int __cdecl main(void) {
- WSADATA wsaData;
- SOCKET ListenSocket = INVALID_SOCKET; // 监听socket
- SOCKET ClientSocket = INVALID_SOCKET; // 连接socket
- struct addrinfo * result = NULL,
- hints;
- int iResult; // 保存返回结果
- // 初始化Winsock,保证Ws2_32.dll已经加载
- iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != 0) {
- printf("WSAStartup failed: %d\n", iResult);
- return 1;
- }
- // 地址
- ZeroMemory( & hints, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = AI_PASSIVE;
- // 获取主机地址,保证网络协议可用等
- iResult = getaddrinfo(NULL, // 本机
- DEFAULT_PORT, // 端口
- & hints, // 使用的网络协议,连接类型等
- & result); // 结果
- if (iResult != 0) {
- printf("getaddrinfo failed: %d\n", iResult);
- WSACleanup();
- return 1;
- }
- // 创建socket,用于监听
- ListenSocket = socket(result - >ai_family, // 网络协议,AF_INET,IPv4
- result - >ai_socktype, // 类型,SOCK_STREAM
- result - >ai_protocol); // 通信协议,TCP
- if (ListenSocket == INVALID_SOCKET) {
- printf("socket failed: %ld\n", WSAGetLastError());
- freeaddrinfo(result);
- WSACleanup();
- return 1;
- }
- // 绑定到端口
- iResult = bind(ListenSocket, result - >ai_addr, (int) result - >ai_addrlen);
- if (iResult == SOCKET_ERROR) {
- printf("bind failed: %d\n", WSAGetLastError());
- freeaddrinfo(result);
- closesocket(ListenSocket);
- WSACleanup();
- return 1;
- }
- printf("bind\n");
- freeaddrinfo(result); // reuslt不再使用
- // 开始监听
- iResult = listen(ListenSocket, SOMAXCONN);
- printf("start listen......\n");
- if (iResult == SOCKET_ERROR) {
- printf("listen failed: %d\n", WSAGetLastError());
- closesocket(ListenSocket);
- WSACleanup();
- return 1;
- }
- while (1) {
- // 接收客户端的连接,accept函数会等待,直到连接建立
- printf("ready to accept\n");
- ClientSocket = accept(ListenSocket, NULL, NULL);
- // accept函数返回,说明已经有客户端连接
- // 返回连接socket
- printf("accept a connetion\n");
- if (ClientSocket == INVALID_SOCKET) {
- printf("accept failed: %d\n", WSAGetLastError());
- closesocket(ListenSocket);
- break; // 等待连接错误,退出循环
- }
- // 为每一个连接创建一个数据发送的接收线程,
- // 使服务端又可以立即接收其他客户端的连接
- if (!CreateThread(NULL, 0, CommunicationThread, // 线程函数
- (LPVOID) ClientSocket, // 将socket作为参数
- 0, NULL)) {
- printf("Create Thread error (%d)", GetLastError());
- break;
- }
- }
- // 循环退出,释放DLL。
- WSACleanup();
- return 0;
- }
来源: http://lib.csdn.net/article/cplusplus/47353