c,#include,#include,#include#pragma comment(lib, "ws2_32.lib")void clientHandler(int clientSocket) {, char buffer[1024];, int bytesReceived;, while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0)) > 0) {, printf("Received: %s,", buffer);, send(clientSocket, buffer, bytesReceived, 0);, }, closesocket(clientSocket);,}void serverThread(void* arg) {, SOCKET serverSocket = *(SOCKET*)arg;, SOCKET clientSocket;, struct sockaddr_in clientAddr;, int addrSize = sizeof(clientAddr); while ((clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &addrSize))) {, _beginthread(clientHandler, 0, (void*)(intptr_t)clientSocket);, },}int main() {, WSADATA wsaData;, SOCKET serverSocket;, struct sockaddr_in serverAddr; WSAStartup(MAKEWORD(2, 2), &wsaData);, serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);, serverAddr.sin_family = AF_INET;, serverAddr.sin_port = htons(8080);, serverAddr.sin_addr.s_addr = INADDR_ANY; bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));, listen(serverSocket, 5); _beginthread(serverThread, 0, (void*)(intptr_t)serverSocket); getchar(); // Keep the main thread alive, closesocket(serverSocket);, WSACleanup();, return 0;,},
“
在Windows环境下使用C语言实现多线程服务器,主要涉及到利用Windows API提供的函数和数据结构,以下是详细的步骤和示例代码:
1、包含必要的头文件
windows.h
:包含了Windows API中线程相关的函数和数据结构。
stdio.h
:用于标准输入输出。
process.h
:包含了线程相关的一些宏和函数声明(如果需要的话)。
2、定义线程函数
线程函数是每个线程执行的入口点,它必须遵循特定的原型,这个函数会接受一个LPVOID
类型的参数,并返回一个DWORD
类型的值。
可以定义一个简单的线程函数来处理客户端连接:
DWORD WINAPI ThreadFunc(LPVOID lpParam) { SOCKET clientSocket = *((SOCKET*)lpParam); char buffer[1024]; int bytesReceived; while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0)) > 0) { // 处理接收到的数据 printf("Received: %s ", buffer); // 发送响应回客户端 send(clientSocket, "ACK", strlen("ACK"), 0); } closesocket(clientSocket); return 0; }
3、创建监听套接字
使用socket()
函数创建一个流式套接字(SOCK_STREAM)。
使用bind()
函数将套接字绑定到一个本地地址和端口上。
使用listen()
函数开始监听来自客户端的连接请求。
示例代码:
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8080); serverAddr.sin_addr.s_addr = INADDR_ANY; bind(listenSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); listen(listenSocket, SOMAXCONN);
4、接受客户端连接并创建线程
使用accept()
函数接受来自客户端的连接请求。
对于每个接受的连接,创建一个新的线程来处理该连接。
可以使用CreateThread()
函数来创建线程,并将新线程的句柄存储起来以便后续管理。
示例代码:
while (1) { SOCKET clientSocket = accept(listenSocket, NULL, NULL); if (clientSocket != INVALID_SOCKET) { HANDLE threadHandle = CreateThread(NULL, 0, ThreadFunc, &clientSocket, 0, NULL); if (threadHandle == NULL) { // 处理线程创建失败的情况 fprintf(stderr, "Failed to create thread "); closesocket(clientSocket); } } }
5、等待线程结束
主线程可以等待所有子线程结束后再退出,这可以通过调用WaitForMultipleObjects()
函数来实现,将所有子线程的句柄传递给它。
示例代码(假设我们有一个线程句柄数组threadHandles
):
WaitForMultipleObjects(numThreads, threadHandles, TRUE, INFINITE);
6、关闭套接字和清理资源
在程序结束前,确保关闭所有打开的套接字并释放其他资源。
以下是一个简化的多线程服务器示例,它接受来自客户端的连接,并为每个连接创建一个新线程来处理:
#include <winsock2.h> #include <windows.h> #include <stdio.h> #include <process.h> #pragma comment(lib, "ws2_32.lib") // 链接WS2_32.lib库 DWORD WINAPI ThreadFunc(LPVOID lpParam) { SOCKET clientSocket = *((SOCKET*)lpParam); char buffer[1024]; int bytesReceived; while ((bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0)) > 0) { printf("Received: %s ", buffer); send(clientSocket, "ACK", strlen("ACK"), 0); } closesocket(clientSocket); return 0; } int main() { WSADATA wsaData; SOCKET listenSocket; struct sockaddr_in serverAddr; HANDLE threadHandles[10]; // 假设最多支持10个并发连接 int numThreads = 0; // 初始化Winsock if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { fprintf(stderr, "WSAStartup failed "); return 1; } // 创建监听套接字 listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSocket == INVALID_SOCKET) { fprintf(stderr, "socket failed with error: %ld ", WSAGetLastError()); WSACleanup(); return 1; } serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8080); serverAddr.sin_addr.s_addr = INADDR_ANY; if (bind(listenSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { fprintf(stderr, "bind failed with error: %ld ", WSAGetLastError()); closesocket(listenSocket); WSACleanup(); return 1; } if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) { fprintf(stderr, "listen failed with error: %ld ", WSAGetLastError()); closesocket(listenSocket); WSACleanup(); return 1; } printf("Server is listening on port 8080... "); // 接受客户端连接并创建线程 while (1) { SOCKET clientSocket = accept(listenSocket, NULL, NULL); if (clientSocket == INVALID_SOCKET) { fprintf(stderr, "accept failed with error: %ld ", WSAGetLastError()); continue; } HANDLE threadHandle = CreateThread(NULL, 0, ThreadFunc, &clientSocket, 0, NULL); if (threadHandle == NULL) { fprintf(stderr, "Failed to create thread for client socket %d ", clientSocket); closesocket(clientSocket); } else { threadHandles[numThreads++] = threadHandle; // 存储线程句柄以便后续管理 } } // 等待所有线程结束(理论上不会到达这里,因为服务器是无限循环运行的) WaitForMultipleObjects(numThreads, threadHandles, TRUE, INFINITE); // 关闭监听套接字和清理资源 closesocket(listenSocket); WSACleanup(); return 0; }
上述代码是一个简化的示例,实际生产环境中的服务器可能需要更多的错误处理和资源管理逻辑,根据具体的应用场景和需求,还可能需要实现更复杂的协议处理和线程同步机制。