前言
不得不承認作為一個前端開發,仍有一個后台開發的夢。從socket通信開始學習,在工作之余補充學習點相關知識,記錄下學習的過程。
服務端
服務器代碼如下,在設置listen之后,通過accept獲取對應的socket連接並創建線程進行通信,通信完成后關閉對應線程。
// socket_service.cpp : 定義控制台應用程序的入口點。 // #include "stdafx.h" #include <stdio.h> #include <Winsock2.h> #pragma comment(lib, "ws2_32.lib") #define LISTEN_MAX_COUNT 5 DWORD WINAPI AnswerThread(LPVOID lparam) { printf("Thread ID:%4d create!\n", GetCurrentThreadId()); int ret; char buf[50] = { 0 }; char sendBuf[80] = { 0 }; SOCKET clientSocket = (SOCKET)(LPVOID)lparam; while (true) { memset(buf, 0, sizeof(buf)); ret = recv(clientSocket, buf, sizeof(buf), 0); if (ret<=0) { break; } printf("revc: %s\n", buf); sprintf_s(sendBuf, "Thread ID:%4d revced", GetCurrentThreadId()); ret = send(clientSocket, sendBuf, strlen(sendBuf) + sizeof(char), 0); if (ret <= 0) { break; } } printf("Thread ID:%4d stop!\n", GetCurrentThreadId()); closesocket(clientSocket); return 1; } int _tmain(int argc, _TCHAR* argv[]) { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(1, 1); if (WSAStartup(wVersionRequested, &wsaData) == INVALID_SOCKET) { return 0; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return 0; } SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); int len = sizeof(SOCKADDR); SOCKADDR_IN clientAddr; SOCKADDR_IN serviceAddr; serviceAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); serviceAddr.sin_family = AF_INET; serviceAddr.sin_port = htons(27015); if (bind(sockSrv, (SOCKADDR*)&serviceAddr, len) == INVALID_SOCKET) { printf("failed bind!\n"); closesocket(sockSrv); WSACleanup(); return 0; } if (listen(sockSrv, LISTEN_MAX_COUNT) == SOCKET_ERROR) { printf("Listen failed with error: %ld\n", WSAGetLastError()); closesocket(sockSrv); WSACleanup(); return 0; } SOCKET sockClient; HANDLE hThread = NULL; DWORD dwThreadId; while (1) { sockClient = accept(sockSrv, (SOCKADDR*)&clientAddr, &len); Sleep(1000); hThread = CreateThread(NULL, NULL, AnswerThread, (LPVOID)sockClient, 0, &dwThreadId); if (hThread == NULL) { printf("CreatThread AnswerThread() failed.\n"); } } closesocket(sockSrv); WSACleanup(); return 0; }
客戶端
客戶端代碼如下,在連接成功后,循環輸入進行通信對話。
// socket_client.cpp : 定義控制台應用程序的入口點。 // #include "stdafx.h" #include <stdio.h> #include <Winsock2.h> #pragma comment( lib, "ws2_32.lib" ) int _tmain(int argc, _TCHAR* argv[]) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); if (WSAStartup(wVersionRequested, &wsaData) == INVALID_SOCKET) { return -1; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return -1; } SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); int len = sizeof(SOCKADDR); SOCKADDR_IN local; local.sin_addr.S_un.S_addr = inet_addr("192.168.1.15"); local.sin_family = AF_INET; local.sin_port = htons(27015); if (connect(sockClient, (SOCKADDR*)&local, len) == INVALID_SOCKET) { printf("connect error/n"); return 0; } char inputBuf[30]; char recvBuf[50]; int ret; // while (scanf_s("%s", inputBuf, sizeof(inputBuf)) != EOF) while (gets_s(inputBuf)) { if (strcmp(inputBuf, "stop") ==0) { break; } ret = send(sockClient, inputBuf, strlen(inputBuf) + sizeof(char), 0); if (ret<=0) { printf("send failed!\n"); break; } ret = recv(sockClient, recvBuf, sizeof(recvBuf), 0); if (ret <= 0) { printf("recv failed!\n"); break; } printf("my reply is : %s\n", recvBuf); //printf("%s\n", inet_ntoa(local.sin_addr)); } closesocket(sockClient); WSACleanup(); return 0; }
測試
Hello World!!
1、開啟多個客戶端,可以看到服務器如下輸出多個線程的創建。
2、客戶端輸入hello world!,可以得到服務器回復,並告知哪個服務器線程接收了消息。
3、關閉其中一個客戶端,可以看到對應線程也關閉了。
4、關閉服務端后,可以端輸入任意內容,可以看到客戶端也收到提示發送失敗並關閉。