当前位置:首页 > 行业动态 > 正文

c 语言 多线程服务器 windows

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类型的值。

可以定义一个简单的线程函数来处理客户端连接:

c 语言 多线程服务器 windows

 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、接受客户端连接并创建线程

c 语言 多线程服务器 windows

使用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()函数来实现,将所有子线程的句柄传递给它。

c 语言 多线程服务器 windows

示例代码(假设我们有一个线程句柄数组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;
}

上述代码是一个简化的示例,实际生产环境中的服务器可能需要更多的错误处理和资源管理逻辑,根据具体的应用场景和需求,还可能需要实现更复杂的协议处理和线程同步机制。