基於非阻塞socket的多執行緒伺服器的實現------一個伺服器如何與多個客戶端進行通訊?
阿新 • • 發佈:2019-01-03
我們首先來看服務端(涉及非阻塞socket和多執行緒):
不多解釋。 先把服務端執行起來吧。#include <stdio.h> #include <winsock2.h> #include <windows.h> #pragma comment(lib, "ws2_32.lib") #define BUF_SIZE 100 sockaddr_in addrClient; // 為了讓通訊執行緒獲取ip // 通訊執行緒 DWORD WINAPI CommThread(LPVOID lp) { SOCKET sClient = (SOCKET)(LPVOID)lp; while(1) { char buf[BUF_SIZE] = {0}; int retVal = recv(sClient, buf, BUF_SIZE, 0); if(SOCKET_ERROR == retVal) { int err = WSAGetLastError(); if(WSAEWOULDBLOCK == err) // 暫時沒有資料 { Sleep(100); continue; } } // 輸出客戶端連線資訊 SYSTEMTIME st; GetLocalTime(&st); char sDateTime[100] = {0}; sprintf(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); printf("%s, The client is [%s:%d]. Msg from client is : %s\n", sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf); char msg[BUF_SIZE] = {0}; sprintf(msg, "Message received is : %s", buf); while(1) { retVal = send(sClient, msg, strlen(msg), 0); // 回顯 if(SOCKET_ERROR == retVal) { int err = WSAGetLastError(); if(err == WSAEWOULDBLOCK) { Sleep(500); continue; } } break; } } closesocket(sClient); } int main() { WSADATA wsd; WSAStartup(MAKEWORD(2, 2), &wsd); SOCKET sServer = socket(AF_INET, SOCK_STREAM, 0); // 設定套接字為非阻塞模式 int iMode = 1; ioctlsocket(sServer, FIONBIO, (u_long FAR*) &iMode); // 設定伺服器套接字地址 SOCKADDR_IN addrServ; addrServ.sin_family = AF_INET; addrServ.sin_port = htons(8888); addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); bind(sServer,(const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN)); listen(sServer, 10); printf("Server start...\n"); int addrClientlen = sizeof(addrClient); while(1) { SOCKET sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen); if(INVALID_SOCKET == sClient) { int err = WSAGetLastError(); if(WSAEWOULDBLOCK == err) // 無法立即完成非阻塞套接字上的操作 { Sleep(100); continue; } } // 建立通訊執行緒 CreateThread(NULL, NULL, CommThread, (LPVOID)sClient, 0, NULL); } // 釋放套接字 closesocket(sServer); WSACleanup(); getchar(); return 0; }
下面, 我們來看看客戶端:
然後同時執行多個客戶端程序(請注意, 如果關掉某一個客戶端程序, 則會引起一些異常, 為了簡便起見, 本文就先不考慮這個情況了)。#include <winsock2.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") int main() { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup( wVersionRequested, &wsaData ); SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(8888); connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); send(sockClient, "hello world", strlen("hello world") + 1, 0); char recvBuf[100] = {0}; recv(sockClient, recvBuf, 100, 0); printf("%s\n", recvBuf); while(1); closesocket(sockClient); WSACleanup(); return 0; }
通過觀察服務端和客戶端的結果, 我們可以理解多執行緒伺服器(非阻塞socket).
好, 先這樣, 睡覺去。