Windows網路程式設計(五):多執行緒訊息處理
阿新 • • 發佈:2018-11-27
對於服務端來說,呼叫accept()函式同意客戶端連線的請求後,需要處理完與這個客戶端的通訊後回到accept()繼續等待下一個客戶端的連線,如果一個客戶端請求連線時服務端並沒有在accept()處等待,客戶端是無法成功連上服務端的,因此併發客戶端連線的服務端必然是多執行緒的。
服務端:
#include <WinSock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <winbase.h>
#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 <WinSock2.h>
#include <windows.h>
#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;
}