1. 程式人生 > >Windows網路程式設計(五):多執行緒訊息處理

Windows網路程式設計(五):多執行緒訊息處理

對於服務端來說,呼叫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;

}