Выберите блоки при попытке прочитать активность из файловых дескрипторов - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь создать сервер, который принимает несколько клиентов.Вот часть моего кода.Мой сервер должен listen до двух ports.sockets, которые достигают этого, это fd_serv и fd_comm.

Использование файловых дескрипторов select и nonblock, к сожалению, не дает желаемого результата.Проблема в том, что select accepts первый client, а затем блокируется и не читает сообщения от других clients.

Также по какой-то причине, если я не использую usleep(100000) команда, моя программа успешно принимает, но не продолжается.

Любая помощь приветствуется.

FD_ZERO(&set);
FD_SET(fd_serv, &set);
FD_SET(fd_comm, &set); 
while (1)
    {
    if (select (max_fd + 1, &set, NULL, NULL, NULL) < 0)
    {
        perror ("select");
        exit (EXIT_FAILURE);
    }

    for (i = 1; i < max_fd + 1; i++)
    {
        usleep(100000);
        if (FD_ISSET (i, &set))
        {
            if (i == fd_serv)       //Connection request on original socket.
            {
                new_serv = accept (fd_serv, (struct sockaddr *) &client_serv_addr, &sin_len_serv);
                if (new_serv < 0){ perror ("accept"); exit (EXIT_FAILURE); }
                fd_set_blocking(new_serv, 0);
                FD_SET(new_serv, &set);
                max_fd = max(max_fd, new_serv);
            }
            else if (i == fd_comm)  //Connection request on original socket.
            {
                new_comm = accept (fd_comm, (struct sockaddr *) &client_comm_addr, &sin_len_comm);
                if (new_comm < 0){ perror ("accept"); exit (EXIT_FAILURE); }
                fd_set_blocking(new_comm, 0);
                FD_SET (new_comm, &set);
                max_fd = max(max_fd, new_comm);
            }
            else if (i == new_comm) //Activity on already connected socket
            {
                if (read_command(fd_comm, i, start_time) == 1)
                {
                    close(i);
                    FD_CLR(i, &set);
                    return SHUTDOWN;
                }
            }
            else if (i == new_serv) //Activity on already connected socket
            {
                read_service(i);
                close(i);
                FD_CLR(i, &set);
            }
        }
    }
}

1 Ответ

0 голосов
/ 23 мая 2018

Ваша проблема здесь:

FD_ZERO(&set);
FD_SET(fd_serv, &set);
FD_SET(fd_comm, &set); 
while (1) 
{
   [...]

Вы настраиваете fd_set только один раз, но ваш fd_set будет изменен вызовом select(), поэтому вам нужно настроить егоодин раз за итерацию вашего цикла.Попробуйте вместо этого:

while (1) 
{
   FD_ZERO(&set);
   FD_SET(fd_serv, &set);
   FD_SET(fd_comm, &set); 
   const int max_fd = (fd_serve > fd_comm) ? fd_serve : fd_comm;
   [...]

... после вызова select() единственная вещь, связанная с select(), которую вы должны вызывать, это FD_ISSET().Все остальное бессмысленно, поскольку ваши дополнительные вызовы FD_SET() и FD_CLR() изменяют fd_set, который вы просто собираетесь стереть с помощью вызова FD_ZERO() в начале следующей итерации цикла while.

Кроме того, в качестве дополнительного примечания: вызов usleep(10000) должен прекратиться - если вы правильно звоните select(), то спать в течение произвольных периодов времени вне select() не нужно и не желательно.

...