对于服务端来说,调用accept()函数同意客户端连接的请求后,需要处理完与这个客户端的通信后回到accept()继续等待下一个客户端的连接,如果一个客户端请求连接时服务端并没有在accept()处等待,客户端是无法成功连上服务端的,因此并发客户端连接的服务端必然是多线程的。
服务端:
#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI CommunicationThread(LPVOID lpParameter)
{
SOCKET socket = (SOCKET)lpParameter;
DWORD dwTid = GetCurrentThreadId();
int bytesSent;
LPSTR szRequest = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 1024);
int iResult = recv(socket, szRequest, 1024, 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("\t CommunicationThread(%d)\t Bytes received:%d\n", dwTid, iResult);
printf("\t CommunicationThread(%d)\t request string is (%s)\n", dwTid, szRequest);
if (lstrcmpi(szRequest, "download file") == 0)
{
HANDLE hFile;
LPVOID lpReadBuf;
DWORD dwBytesRead;
DWORD dwSendFile = 0;
DWORD dwFileSize;
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;
}
dwFileSize = GetFileSize(hFile, NULL);
lpReadBuf = HeapAlloc(GetProcessHeap(), 0, 4096);
while (true)
{
if (!ReadFile(hFile, lpReadBuf, 4096, &dwBytesRead, NULL))
{
printf("\t CommunicationThread\tCould not read from file (error %d)\n", GetLastError());
closesocket(socket);
CloseHandle(hFile);
return 1;
}
bytesSent = send(socket, (const char *)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);
}
else if (lstrcmpi(szRequest, "get information") == 0)
{
bytesSent = send(socket, "this is information", sizeof("this is information") + 1, 0);
if (bytesSent == SOCKET_ERROR)
{
printf("\tCommunicationThread\t send error:%d\n", WSAGetLastError());
closesocket(socket);
return 1;
}
printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
}
else
{
printf("unreferenced request\n");
}
}
HeapFree(GetProcessHeap(), 0, szRequest);
closesocket(socket);
return 0;
}
int _tmain(int argc, _TCHAR argv[])
{
WSADATA wsaData;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
ADDRINFO hints;
ADDRINFO *result = NULL;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
printf("WSAStartup failed with error:%d\n", iResult);
return 1;
}
iResult = getaddrinfo(NULL, "12000", &hints, &result);
if (iResult != NO_ERROR)
{
printf("getaddrinfo failed with error:%d\n", iResult);
WSACleanup();
return 1;
}
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET)
{
printf("socket failed with error:%d", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
iResult = bind(ListenSocket, result->ai_addr, result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
printf("bind failed with error:%d", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
printf("listen failed with error:%d", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
while (true)
{
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET)
{
printf("accept failed with error:%d", WSAGetLastError());
closesocket(ListenSocket);
break;
}
if (!CreateThread(NULL, 0, CommunicationThread, (LPVOID)ClientSocket, 0, NULL))
{
printf("CreateThread error %d", GetLastError());
break;
}
}
WSACleanup();
return 0;
}
客户端:
#include
#include
#pragma comment(lib,"ws2_32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;// 库
SOCKET ConnectSocket;// socket
SOCKADDR_IN clientService;// 地址
int bytesSent;
int bytesRecv = 0;
LPVOID recvbuf;// 接收缓存
char sendbuf[32] = "get information";// 默认发送的数据
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(12000);
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
printf("Error at WSAStartup()\n");
return 1;
}
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
printf("Failed to connect(%d)\n", WSAGetLastError());
WSACleanup();
return 1;
}
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 1;
}
recvbuf = HeapAlloc(GetProcessHeap(), 0, 8192);
while (bytesRecv != SOCKET_ERROR)
{
//Sleep(50);
bytesRecv = recv(ConnectSocket, // socket
(char*)recvbuf, // 接收数据缓存
8192,// 缓存大小
0);// 无标志
if (bytesRecv == 0)
{
printf("Connection Closed.\n");
break;
}
// TODO,处理接收的数据,这里只简单的将收到的数据大小显示
printf("Bytes Recv: %ld\n", bytesRecv);
}
HeapFree(GetProcessHeap(), 0, recvbuf);
WSACleanup();
return 0;
}