【问题标题】:How to make a multipart server in C ++. How to start a thread without waiting for it to complete?如何在 C++ 中制作多部分服务器。如何在不等待完成的情况下启动线程?
【发布时间】:2021-04-30 09:32:14
【问题描述】:

我想在套接字上创建一个多线程服务器。我创建了一个线程,但是我事先不知道会有多少个线程,我不能在循环中启动一个线程,因为有一个暂停

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <thread>

#define PORT 8000


class ConnectSocket {
public:
    explicit ConnectSocket(int socket) {
        std::cout << "New connect: " << this << std::endl;
        this->buffer = new char[1024];
        this->bytes_read = new int;
        this->socket = new int;
        *(this->socket) = socket;
        while (true) {
            if (get_content() == -1) {
                break;
            }
            send_content(this->buffer);
            std::cout << "content: " << this->buffer << std::endl;
        }
        close_connection();

    }
    ~ConnectSocket(){
        std::cout << "End connect " << this << std::endl;
        delete[] this->buffer;
        delete this->bytes_read;
        delete this->socket;
    }
private:
    char *buffer;
    int *bytes_read;
    int *socket;

    int get_content() {
        if (this->buffer != nullptr && this->socket != nullptr) {
            *(this->bytes_read) = recv(*(this->socket), this->buffer, 1024, 0);
            if(*(this->bytes_read) <= 0) return -1;
            return 0;
        } else return -1;

    }

    int send_content(char *content){
        if (this->buffer != nullptr && this->socket != nullptr) {
            send(*(this->socket), content, strlen(content), 0);
            return 0;
        } else return -1;
    }

    void close_connection() {
        close(*(this->socket));
        delete this;
    }
};


void runConnection(int sock) {
    ConnectSocket *connect_socket = new ConnectSocket(sock);
}
int main()
{
    int sock, listener;
    struct sockaddr_in addr;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        exit(1);
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }

    listen(listener, 1);
    while(1)
    {
        sock = accept(listener, NULL, NULL);
        if(sock < 0)
        {
            perror("accept");
            exit(3);
        }
        std::thread thr(runConnection, sock);
        thr.join();
    }

    return 0;
}

如何让 ConnectSocket 类在每个连接的单独线程中运行? 现在服务器只能处理一个连接

【问题讨论】:

    标签: c++ c multithreading sockets


    【解决方案1】:

    如果您真的想为每个请求创建一个新线程,您可以这样做。只需将accept 调用放入线程函数中,而不是放入您的事件循环中。如果accept 成功,则线程函数应在处理请求之前生成一个新线程(它将接受下一个请求)。在这种情况下可能不需要join;在一个简单的实现中,线程将是detached。

    但您可能会发现结果并不理想,原因如下:

    1. 无法控制创建的线程数。

    2. 为每个请求创建一个线程和一个请求处理器需要大量开销。

    一个更常见的实现策略,仍然很简单,是产生预定数量的线程,每个线程执行一个循环,accepts 并处理一个请求。 (这是安全的,因为accept() 是线程安全的;每个线程将获得一个不同的连接。但你不能假设每个accept 都会成功而不阻塞,或者完全成功。)

    这通常称为线程池,您会发现各种用于生产目的的库实现。不过自己滚也不算太复杂,是一次很好的学习体验。

    您不一定需要一次生成所有线程。如果您使用某种共享数据(如信号量)来计算活动线程的数量,您可以让每个线程决定是否在成功accept 后生成一个新线程。如果线程可能过早终止(见下文),此策略将很有用。

    不过,简单的线程池也可能不是最理想的。对于更复杂的策略,您可能需要注意以下几点:

    1. 请求处理器中的错误无法释放资源。 (“内存泄漏”是一个典型的例子,但还有其他资源。)服务器必须能够永远运行,资源泄漏会慢慢地让它屈服。避免此问题的一种策略是让每个线程在处理了一定数量的请求后终止。

    2. 此解决方案依赖于操作系统(或线程库)在竞争线程之间公平分配负载。这可能不是一个现实的期望,您可能会发现在高负载下,一些内核被超额订阅,而另一些则保持空闲。一些服务器实现了自己的调度程序来解决这个问题。

    对于一些可能有趣的阅读,您可能想看看:

    【讨论】:

      猜你喜欢
      • 2022-08-22
      • 1970-01-01
      • 2022-11-23
      • 2019-04-10
      • 2015-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-26
      相关资源
      最近更新 更多