TCP клиентский сокет, не блокируется при выборе ()

#c #select #tcpclient

#c #выберите #tcpclient

Вопрос:

Следующий код представляет собой тестовую программу, написанную для понимания поведения select() вызова в клиентской программе TCP.
Что я наблюдаю, так это то, что выбор не блокируется, вместо этого программа блокирует включение recv() . Вывод выглядит следующим образом:

 Wait on select.
Wait on recv.
...
  

Мой вопрос в том, почему select() возвращает успех? В идеале он должен блокировать select() вместо recv() .
TCP-сервер отправляет символьную строку из 15 байт один раз в 3 секунды.

 int clientfd = -1;
int dummyfd = -1;
int maxfd = -1;
struct sockaddr_in server_addr;

char recv_buf[100] = {0};
int msg_len = 0;
int bytes_recv = 0;
fd_set readfd;
int retval = 0;


/* Open the socket and a dummy socket */.
clientfd = socket(AF_INET, SOCK_STREAM, 0);
dummyfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == clientfd || -1 == dummyfd)
{
    perror("socket error: ");
    exit(1);
}
printf("Socket opened : %dn", clientfd);

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);
//server_addr.sin_addr.s_addr = INADDR_ANY;
inet_aton("127.0.0.1", amp;(server_addr.sin_addr));
memset(amp;(server_addr.sin_zero), 0, 8);

/* Connect to server */
if(connect(clientfd, (struct sockaddr *)amp;server_addr, sizeof(struct sockaddr)))
{
    perror("connect error: ");
    exit(1);
}
printf("Connect Successn");
maxfd = (clientfd > dummyfd) ? (clientfd   1) : (dummyfd   1);
while(1)
{
    FD_ZERO(amp;readfd);
    FD_SET(clientfd, amp;readfd);
    FD_SET(dummyfd, amp;readfd);
    printf("Wait on selectn");
    retval = select(maxfd , amp;readfd, NULL, NULL, NULL);
    if(retval <= 0)
    {
        printf("select failedn");
    }
    else
    {
            printf("Wait on recvn");
            /* ... The process waits here ... */
            bytes_recv = recv(clientfd, recv_buf, 100, 0);
            printf("%d: Bytes recv = %dt%sn", retval, bytes_recv, recv_buf);
            memset(recv_buf, 0 ,100);
    }
}

close(clientfd);
return 0;
}
  

Редактировать: Без dummyfd программа работает так, как задумано.
Последующий вопрос:
Когда сервер внезапно закрывается, как это определить с помощью select() ?
Можно ли изменить программу так, чтобы она блокировалась select() , скажем, при сбое на стороне сервера?

Ответ №1:

Используйте следующее, чтобы убедиться, что это то, clientfd что возвращается из select :

 else if (FD_ISSET(clientfd, amp;readfd)) {
  

У меня нет времени на тестирование, но я подозреваю, что dummyfd возвращается как EOF из select, а не из clientfd .

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

1. Я удалил dummyfd. Теперь он ожидает выбора.

2. Каково поведение, когда сервер внезапно закрывается? Теперь, будет ли clientfd возвращать EOF?

3. Да, вы всегда должны проверять EOF при возврате select, и если это так, удалите этот fd из вашего списка выбора.

Ответ №2:

После возврата select () вы захотите условно получить от clientfd. Я предполагаю, что в dummyfd могут быть данные, которые инициируют завершение выбора, но получение происходит на clientfd.

 retval = select(maxfd , amp;readfd, NULL, NULL, NULL);
if(retval <= 0)
{
    printf("select failedn");
}
else
{
    if (FD_ISSET(clientfd, amp;readfd))
    {
        bytes_recv = recv(clientfd, recv_buf, 100, 0);
        ...
    }

    if (FD_ISSET(dummyfd, amp;readfd))
    {
        /* "dummyfd" processing */
    }