Как мне обрабатывать запросы сокетов в отдельных потоках, поток, похоже, блокирует основной процесс

#c #multithreading #sockets #unix

#c #многопоточность #розетки #unix

Вопрос:

Я пытаюсь создать простой HTTP — сервер на C . Я хочу, чтобы каждый запрос обрабатывался одновременно в отдельных потоках, но когда я создаю поток и ставлю простой sleep(10) в начале, чтобы вызвать некоторую задержку, другой запрос к серверу не может быть выполнен до завершения первого потока. Что я делаю не так?

Вот мой код до сих пор:

 #include lt;unistd.hgt; #include lt;stdio.hgt; #include lt;sys/socket.hgt; #include lt;stdlib.hgt; #include lt;netinet/in.hgt; #include lt;stringgt; #include lt;ostreamgt; #include lt;iostreamgt; #include lt;threadgt;  using namespace std;  void send_response (int socket) {  sleep (10);   char buffer[2048] = {0};   int request = recv (socket, buffer, 2048, 0);   if (request == -1) {  perror ("error");  }   string message = "Hello from server";  string length = to_string (message.length ());   string hello = "HTTP/1.1 200 OKnContent-Type: text/plainnContent-Length: "   length   "nn"   message;   send (socket, hello.c_str (), hello.length (), 0);   close (socket); }  int main(int argc, char const *argv[]) {  struct sockaddr_in address;  int opt = 1;  socklen_t addrlen = sizeof (address);   int server_fd = socket (AF_INET, SOCK_STREAM, 0);   if (server_fd == 0) {  perror ("socket failed");  exit (EXIT_FAILURE);  }   if (setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, amp;opt, sizeof (opt))) {  perror ("setsockopt");  exit (EXIT_FAILURE);  }   address.sin_family = AF_INET;  address.sin_addr.s_addr = INADDR_ANY;  address.sin_port = htons (8080);   if (bind (server_fd, (struct sockaddr *)(amp;address), sizeof (address)) lt; 0) {  perror ("bind failed");  exit (EXIT_FAILURE);  }   if (listen (server_fd, 3) lt; 0) {  perror ("listen");  exit (EXIT_FAILURE);  }   while (true) {  int new_socket = accept (server_fd, (struct sockaddr *)(amp;address), amp;addrlen);   if (new_socket lt; 0) {  perror ("accept");  exit (EXIT_FAILURE);  }   thread response (amp;send_response, new_socket);   response.detach ();   cout lt;lt; "request handled" lt;lt; endl;  }   return 0; }  

Мне не нужно ждать завершения потока или получать какие-либо данные из потока, я просто хочу, чтобы он запустился, выполнил некоторую работу и отправил что-то обратно клиенту. Я ожидаю, что каждый поток будет выполнять приличный объем работы, поэтому я использовал sleep.

Изменить: Похоже, что цикл готов и ожидает второго подключения и успешно примет новое соединение и создаст новый поток для его обработки, но только если второе соединение с другого IP-адреса. Поэтому, если я зайду на сервер по адресу 127.0.0.1:8080 и с другого локального IP-адреса, например 192.168.1.91, оба соединения будут выполняться двумя потоками одновременно. Однако, если я просто открою две вкладки, обе в 127.0.0.1:8080, одновременно будет приниматься только одно соединение, другое остановится. Похоже, мне нужен код для обработки нескольких подключений с одного и того же IP-адреса, но поиск такого рода проблем в Google не дал мне никаких хороших результатов.

Комментарии:

1. Я ожидаю, что каждый поток будет выполнять приличный объем работы, вот почему я использовал sleep , что вы имеете в виду?

2. Я думаю, что проблема заключается в области объекта потока — он находится внутри цикла while. Таким образом, после одной итерации объект выходит за пределы области видимости.

3. Я имею в виду, что завершение каждого потока займет несколько секунд, и я бы предпочел, чтобы клиенты не ждали только потому, что одно ядро в системе 12 занято обработкой одного запроса.

4. Вы правы, функцию не нужно передавать по адресу. Я сделал это, потому что в документации говорится, что первый параметр-это «указатель на функцию, указатель на элемент или любой вид объекта функции, который можно перемещать», поэтому я передал адрес. Однако это не имеет значения для того, работает код или нет.

5. Можете ли вы подключить отладчик и прервать работу, пока висит второй запрос? Это должно рассказать вам, чем занимается основная тема.

Ответ №1:

Ладно, моя вина, все работает так, как ожидалось. Использование wget для отправки нескольких запросов с одного и того же IP-адреса приводит к созданию нескольких потоков и одновременной обработке запросов. В Chrome по какой-то причине открытие нескольких вкладок с одного и того же IP-адреса приводит к их последовательной отправке, но в Firefox они отправляются параллельно, поступают и обрабатываются одновременно. Это странно, но я добавлю в него странности Хрома.