Как ускорить работу сервера http c при большей нагрузке? - PullRequest
0 голосов
/ 27 января 2019

У меня есть http c server Я получил от https://rosettacode.org. Я пытался проверить его на типичные размеры веб-страниц при загрузке текста от 1 МБ до 3 МБ. Однако, по-видимому, с увеличением полезной нагрузки производительность сервера снижается с точки зрения максимально возможного количества запросов, которые он может обработать.

Я ожидаю, что сеть будет той, которая должна быть насыщенной, поскольку процессор просто передает адрес памяти ответа сети.

Как повысить производительность этого сервера при обработке больших нагрузок? Рассмотрим только один базовый сценарий процессора.

Соответствующая часть кода написана ниже

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>

char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html><html><head><title>Bye-bye baby bye-bye</title>"
"<style>body { background-color: #111 }"
"h1 { font-size:4cm; text-align: center; color: black;"
" text-shadow: 0 0 2mm red}</style></head>"
"<body><h1>Goodbye, world!</h1></body></html>\r\n";

int main()
{
  int one = 1, client_fd;
  struct sockaddr_in svr_addr, cli_addr;
  socklen_t sin_len = sizeof(cli_addr);

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    err(1, "can't open socket");

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));

  int port = 8080;
  svr_addr.sin_family = AF_INET;
  svr_addr.sin_addr.s_addr = INADDR_ANY;
  svr_addr.sin_port = htons(port);

  if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
    close(sock);
    err(1, "Can't bind");
  }

  listen(sock, 5);
  while (1) {
    client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
    printf("got connection\n");

    if (client_fd == -1) {
      perror("Can't accept");
      continue;
    }

    write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/
    close(client_fd);
  }
} 

Обновление:

Часть в response[] может быть обновлена ​​с помощью открытого текста размером 1–3 МБ для использования в качестве полезной нагрузки.

Тесты проводились на локальном хосте. Keepalive состояние не изменилось на малых или больших полезных нагрузках.

1 Ответ

0 голосов
/ 27 января 2019

В качестве примечания, ваш код не имеет ничего общего с HTTP, поэтому он не является "http-сервером", но вопрос не в этом.

Ваш вопрос в том, что производительность низкая.И ответ прост - звонок на write() блокируется.Он не просто «передает адрес памяти ответа сети» - он также ждет, пока не будет доставлен!Таким образом, как написан этот код, вы на самом деле просто обрабатываете один запрос за раз.Не удивительно, что ваши запросы в секунду сбрасываются при увеличении полезной нагрузки.

Вам нужна «асинхронная» (также известная как «неблокирующая») обработка - ваши «чтения» и «записи» должны немедленно вернуться, не дожидаясь, пока данные будут доставлены.Таким образом, вы можете обслуживать несколько сокетов параллельно, даже без нескольких потоков.Недостатком, однако, является то, что манипулирование ими все станет довольно сложным.Но если вы все сделаете правильно, вы переполните свой процессор и / или сеть до предела.

Подробности об этом довольно длинные, и я не буду повторять их здесь снова.Поиск в Google для «примера неблокирующих сокетов linux», похоже, приносит много хороших результатов, а также известное Руководство Beej по сетевому программированию очень хорошо описывает все важные моменты.Прочитайте это!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...