'select' может быть прочитан клиентский сокет keep find

0

Мне трудно описать мой вопрос, хотя название выше, может быть, почему-то непонятно.

У меня есть обычный tcp-сервер, у которого есть сокет для прослушивания, и он может принимать до 32 клиентов, я создал сокеты для каждого клиента, и я использую select system call, чтобы контролировать, какой клиент может быть прочитан, следующий код является фрагментом моей программы,

где, rset является переменной-членом моего класса, а его тип - fd_set. Я обнулял его с помощью FD_ZERO в конструкторе.

timeo также является переменной-членом, тип - struct timeval инициализированный 10 секундами.

this->sock снова является переменной-членом, используемой для прослушивания и приема новых клиентов. Я уже вызвал FD_SET(this->sock, &rset).

print_trace - это просто макрос, который печатает сообщение и добавляет '\n'.

 while(1) {
     int count = select(FD_SETSIZE, &rset, /*&wset*/ NULL, NULL, &timeo);
     printf("%d fds\n", count);

     if(count) {     
        if(FD_ISSET(this->sock, &rset)) {
            // new connection comes and now this line will not blocked 
            if((csocks[sock_count] = accept(this->sock, NULL, NULL))) {
                FD_SET(csocks[sock_count], &rset);

                ++sock_count;
            }           
         } else {  
             print_trace("there are clients can be read.");      
             for(int i = 0 ; i < sock_count ; ++i) {
                if(FD_ISSET(csocks[i], &rset)) {
                    char buffer[512] = {0};
                    recv(csocks[i], buffer, 512, 0);
                    printf("here client socket number: %d, i=%d, message: %s\n", csocks[i], i, buffer);
                }
             }
         }
     }

     timeo.tv_sec = 10;
     timeo.tv_usec = 0;
 }

Я знаю, что я не повторно this->sock используя FD_SET, для выбора будет очищать все биты при тайм-ауте, но это не касается моей проблемы.

моя проблема в том, что когда я запускаю серверную программу, и через 10 секунд я запускаю клиентскую программу для подключения к этому серверу, select возвращает 1 нормально, так что клиентский сокет будет создан и добавлен в rset, а затем сервер переходит к следующему циклу, осторожно! сейчас, прямо сейчас, прекратить программу клиента сразу, не ждать, select возвраты.

Хорошо, теперь проблема снова появится, программа сервера сохранит следующую информацию:

1 fds
there are clients can be read.
here client socket number: 6, i=2, message: 
1 fds
there are clients can be read. 
here client socket number: 6, i=2, message:  
1 fds
there are clients can be read.
here client socket number: 6, i=2, message: 
1 fds
there are clients can be read.
here client socket number: 6, i=2, message: 
...
...

Я использую tcpdump мониторинга соединения, когда он завершает работу клиента, он просто отправляет пакет FIN, а серверная программа просто отправляет ACK-пакет, никаких других данных, связанных с соединением, нет.

почему select продолжает находить клиентский сокет, может быть прочитан, пока он просто читает пустое сообщение (как показывает сообщение печати)?

Любая помощь будет оценена.

update: Я знаю, что использование метода select ясно, я думал, что не использую этот метод правильно, поэтому я потратил около часа на изучение этого метода, чтобы решить мою проблему, но не нашел результата.

  • 0
    К вашему сведению, не используйте FD_SETSIZE в вашем select . Отслеживать дескрипторы файлов немного сложнее, но это избавляет от необходимости просматривать весь набор.
  • 0
    @ Да, спасибо за напоминание :)
Теги:
sockets
tcp

1 ответ

3
Лучший ответ

Вы игнорируете результат, возвращаемый recv(), который сам по себе является ошибкой, и, в частности, вы игнорируете возможность того, что он равен нулю, который является концом потока, на котором вы должны закрыть сокет, поэтому вы не просто снова выберите EOS.

  • 0
    Спасибо! это ответ! Кажется, я все усложняю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню