Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
155 views
in Technique[技术] by (71.8m points)

c++ - How to make a multipart server in C ++. How to start a thread without waiting for it to complete?

I want to create a multithreaded server on sockets. I create a thread, but I don’t know in advance how many threads there will be and I can’t start a thread in a loop, since there is a pause

#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;
}

How do I make the class ConnectSocket run in a separate thread on each connection? Now the server can only handle one connection

question from:https://stackoverflow.com/questions/65904064/how-to-make-a-multipart-server-in-c-how-to-start-a-thread-without-waiting-fo

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If you really wanted to create a new thread for each request, you could just do that. Just put the accept call into the thread function, rather in your event loop. If the accept succeeds, the thread function should then spawn a new thread (which will accept the next request) before processing the request. There may be no need for join in this scenario; in a simple implementation, the threads would be detached.

But you're likely to find that the result is suboptimal, for several reasons:

  1. There's no way to control the number of threads created.

  2. Creating a thread and a request processor for each request is a lot of overhead.

A more common implementation strategy, which is still quite simple, is to spawn a predetermined number of threads, each of which executes a loop which accepts and processes a request. (This is safe because accept() is thread-safe; each thread will be handed a different connection. But you can't assume that every accept will succeed without blocking, or succeed at all.)

That's usually called a thread pool and you'll find a variety of library implementations for production purposes. But rolling your own is not too complicated, and it's a good learning experience.

You don't necessarily need to spawn all of the threads at once. If you used some kind of shared data (like a semaphore) to count the number of active threads, you could let each thread decide whether to spawn a new thread after a successful accept. This strategy will be useful if threads might terminate prematurely (and see below).

A naive thread pool might also be suboptimal, though. Things you might want to watch out for, for a more sophisticated strategy, are:

  1. Bugs in request processors which fail to release resources. ("Memory leaks" are a prime example, but there are other resources as well.) A server must be able to run forever and resource leaks will slowly bring it to its knees. One strategy to avoid this problem is to let each thread die after it has processed some number of requests.

  2. This solution depends on the operating system (or thread library) to fairly distribute load between the competing threads. That might not be a realistic expectation, and you might find that under high load, some cores are oversubscribed and others are remaining idle. Some servers implement their own schedulers to solve this problem.

For some possibly interesting reading, you might want to take a look at:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...