Розетки и нити с использованием C - PullRequest
3 голосов
/ 15 сентября 2010

Я новичок и в сокетах, и в нитках.У меня есть этот код:

listen(socket_fd, 20);

/* Looooop */
  while (1) {
    newsocket_fd = accept(socket_fd, 
                          (struct sockaddr *) &client_addr, 
                          &client_len);
    if (newsocket_fd < 0) {
      error("ERROR on accept");
    }
    pthread_t thread;
    pthread_create(&thread, NULL, run_thread, (void *) newsocket_fd);
    pthread_join(thread, NULL);
  }

Как создать новый поток для каждого нового подключения, а не для каждого запроса?Эти потоки должны быть запущены при установлении нового соединения, и затем эти потоки должны ждать запросов, обрабатывать эти запросы и, наконец, возвращаться при закрытии соединения. Для каждого соединения должен быть один поток. Вот код для run_thread:

void
*run_thread(void *ptr) {
  char buffer[256];
  bzero(buffer, 256);
  int n;
  n = read((int) ptr, buffer, 255);
  if (n < 0) error("ERROR Reading from socket");
  printf("%s\n\n**********\n\n", buffer);

  /* Parse buffer and return result */
  char *result;
  {
    /* First, determine command, 4 characters */
    /* (much code) */
  }

  n = write((int) ptr, result, strlen(result));
  if (n < 0) error("ERROR Writing to socket");
}

Кто-нибудь может мне помочь?Благодаря.

Ответы [ 3 ]

7 голосов
/ 15 сентября 2010

Вы почти правильно поняли.Проблема, однако, в том, что вы присоединяетесь к потоку сразу после создания, а pthread_join на самом деле является блокирующим вызовом, ожидающим завершения потока.Это означает, что вы не сможете больше принимать соединения, пока работает один поток.Чтобы решить эту проблему, вы можете использовать отдельные темы.Вам не нужно вступать в отдельные темы.Для этого вам необходимо создать атрибуты потока, используя функцию pthread_attr_init , и передать эти атрибуты в pthread_create .

.приложение может исчерпать ресурсы.Итак, в реальном мире вы должны управлять пулом потоков.Но лучший сценарий для серверных приложений TCP / IP - использовать асинхронный ввод-вывод .Я не знаю о C, но в C ++ есть очень хорошая библиотека для приложения асинхронного ввода-вывода, которая называется boost :: asio .

6 голосов
/ 15 сентября 2010

Существует также другая критическая ошибка.

Вы приводите int к (void *).Это не имеет смысла.Кроме того, вы не можете передать адрес напрямую, поскольку переменная может быть изменена при следующем вызове accept (), прежде чем поток сможет скопировать переменную в свой локальный стек.Один из способов написать это будет примерно так:

while (1) {
    newsocket_fd = accept(socket_fd, 
                          (struct sockaddr *) &client_addr, 
                          &client_len);
    if (newsocket_fd < 0) {
      error("ERROR on accept");
    }
    pthread_t thread;
    int *newsock = malloc(sizeof(int));
    *newsock = newsocket_fd;
    pthread_create(&thread, NULL, run_thread, newsock);
    pthread_detach(thread);
  }

При таком подходе поток обязательно освободит () newsock.Например, простое

void *handler(void *thread_data) {
   int fd = *(int *) thread_data;
   free(thread_data);
   ....
}

Кроме того, я предполагаю, что pthread_detach () - это нормально, если основная программа не заботится о синхронизации с потоком позже с помощью pthread_join ().

0 голосов
/ 15 сентября 2010

У Влада есть хороший совет.

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

РЕДАКТИРОВАТЬ: Игнорировать этот комментарий, я неправильно прочитал вашу ошибку.Другие дали правильные исправления для вашей обработки newsocket_fd.

...