线程池的编程步骤(基于Windows下的编程)

本文详细描述了如何使用线程池模型创建服务器,包括初始化线程池、任务队列、监听端口、接受连接请求以及线程池的管理和关闭过程,以提高并发连接的效率。
摘要由CSDN通过智能技术生成

线程池模型的服务器通常用于处理并发连接,它通过预先创建一组线程来处理传入的连接请求,从而避免了频繁创建和销毁线程的开销。以下是创建线程池模型服务器的一般步骤:

1. 初始化线程池: 创建一个包含固定数量线程的线程池。这些线程等待从任务队列中获取任务并执行。
2. 初始化任务队列: 创建一个任务队列,用于存储客户端的连接请求或需要处理的任务。
3. 监听端口: 创建一个监听套接字,并将其绑定到服务器的地址和端口。开始监听传入的连接请求。
4. 接受连接请求: 当客户端尝试连接时,服务器接受连接请求,并将客户端套接字添加到任务队列中。
5. 任务处理: 线程池中的线程从任务队列中取出任务,并执行相应的处理,例如处理客户端连接或执行其他任务。
6. 线程池管理: 线程池需要管理线程的生命周期,包括线程的创建、销毁和复用等。
7. 关闭服务器: 当不再需要服务器时,关闭监听套接字,停止接受新的连接请求,并等待线程池中的所有任务执行完成后,释放资源并关闭线程池。
#include <iostream>
#include <cstring>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>

#pragma comment(lib, "Ws2_32.lib")

// 任务结构体,包含了客户端连接套接字
struct Task {
    SOCKET clientSocket;
    Task() : clientSocket() {}
    Task(SOCKET socket) : clientSocket(socket) {}
};

// 线程池类
class ThreadPool {
public:
    // 构造函数,初始化线程池
    ThreadPool(size_t numThreads) : stop(false) {
        // 创建指定数量的线程,并启动线程执行任务
        for (size_t i = 0; i < numThreads; ++i) {
            threads.emplace_back([this] {
                while (true) {
                    Task task;
                    {
                        // 锁定任务队列
                        std::unique_lock<std::mutex> lock(queueMutex);
                        // 等待任务队列不为空的条件变量
                        condition.wait(lock, [this] { return stop || !tasks.empty(); });
                        // 如果线程池停止并且任务队列为空,则退出线程
                        if (stop && tasks.empty()) return;
                        // 从队列中取出任务
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    // 处理任务
                    handleTask(task);
                }
                });
        }
    }

    // 析构函数,停止线程池并等待所有线程结束
    ~ThreadPool() {
        {
            // 锁定任务队列
            std::unique_lock<std::mutex> lock(queueMutex);
            // 设置停止标志为true
            stop = true;
        }
        // 通知所有线程停止
        condition.notify_all();
        // 等待所有线程结束
        for (auto& thread : threads) {
            thread.join();
        }
    }

    // 添加任务到任务队列
    void addTask(Task task) {
        {
            // 锁定任务队列
            std::lock_guard<std::mutex> lock(queueMutex);
            // 将任务添加到队列
            tasks.push(std::move(task));
        }
        // 通知等待中的线程有新任务可执行
        condition.notify_one();
    }

private:
    std::vector<std::thread> threads; // 存储线程的容器
    std::queue<Task> tasks;           // 任务队列
    std::mutex queueMutex;            // 任务队列的互斥量
    std::condition_variable condition; // 任务队列非空的条件变量
    bool stop;                         // 停止标志,用于通知线程池停止

    // 处理任务的函数
    void handleTask(Task& task) {
        // 处理客户端连接
        std::cout << "处理客户端连接的线程: " << std::this_thread::get_id() << std::endl;

        // 从客户端接收数据
        char buffer[1024] = { 0 };
        int bytesRead = recv(task.clientSocket, buffer, sizeof(buffer), 0);
        if (bytesRead == SOCKET_ERROR) {
            std::cerr << "错误: 无法从客户端接收数据" << std::endl;
            closesocket(task.clientSocket);
            return;
        }
        std::cout << "从客户端接收到数据: " << buffer << std::endl;

        // 发送响应到客户端
        const char* response = "你好,来自服务器的消息";
        int bytesSent = send(task.clientSocket, response, strlen(response), 0);
        if (bytesSent == SOCKET_ERROR) {
            std::cerr << "错误: 无法向客户端发送响应" << std::endl;
        }
        else {
            std::cout << "响应已发送到客户端" << std::endl;
        }

        // 关闭客户端套接字
        closesocket(task.clientSocket);
    }
};

int main() {
    // 初始化Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        std::cerr << "错误: WSAStartup 失败" << std::endl;
        return 1;
    }

    // 创建线程池
    ThreadPool pool(4); // 使用4个线程的线程池

    // 创建服务器套接字
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serverSocket == INVALID_SOCKET) {
        std::cerr << "错误: 无法创建服务器套接字" << std::endl;
        WSACleanup();
        return 1;
    }

    // 设置服务器地址
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(8080); // 设置端口号为8080

    // 绑定服务器套接字到地址
    if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "错误: 无法绑定服务器套接字" << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    // 监听传入连接
    if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
        std::cerr << "错误: 无法监听服务器套接字" << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    std::cout << "服务器已启动,正在监听端口 8080..." << std::endl;

    // 接受连接并添加到任务队列中
    while (true) {
        sockaddr_in clientAddr;
        int clientAddrLen = sizeof(clientAddr);
        SOCKET clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrLen);
        if (clientSocket == INVALID_SOCKET) {
            std::cerr << "错误: 无法接受客户端连接" << std::endl;
            closesocket(serverSocket);
            WSACleanup();
            return 1;
        }

        // 将任务添加到线程池的任务队列中
        pool.addTask(Task(clientSocket));
    }

    // 关闭服务器套接字
    closesocket(serverSocket);

    // 清理Winsock
    WSACleanup();

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值