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;

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章