2015-09-08 1 views
3

Я пытаюсь проверить, отправил ли клиент некоторые новые данные. На самом деле это говорит мне, что я всегда есть новые данные:FD_ISSET всегда верен, даже если новых данных нет?

bool ClientHandle::hasData() 
{ 
    fd_set temp; 
    FD_ZERO(&temp); 
    FD_SET(m_sock, &temp); 

    //setup the timeout to 1000ms 
    struct timeval tv; 
    tv.tv_sec = 0; 
    tv.tv_usec = 1000; 
    //temp.fd_count possible? 
    if (select(m_sock+1, &temp, nullptr, nullptr, &tv) == -1) 
    { 
     return false; 
    } 

    if (FD_ISSET(m_sock, &temp)) 
     return true; 

    return false; 
} 

Я соединяющий с клиентом Java и отправить сообщение «соединение», которое я прочитал внутри CTOR:

ClientHandle::ClientHandle(SOCKET s) : m_sock(s) 
{ 
    while (!hasData()) 
    { 
    } 
    char buffer[5]; 
    recv(m_sock, buffer, 4, NULL); 
    auto i = atoi(buffer); 
    LOG_INFO << "Byte to receive: " << i; 
    auto dataBuffer = new char[i + 1]{'\0'}; 
    recv(m_sock, dataBuffer, i, NULL); 
    LOG_INFO << dataBuffer; 
    //clean up 
    delete[] dataBuffer; 
} 

Это кажется работа право. После этого я продолжаю проверять, есть ли новые данные, которые всегда верны, даже если java-клиент не отправляет никаких новых данных.

Вот клиент java. Не судите меня, это просто проверка связей. Он не останется таким, чтобы отправить информацию о размере как char [].

public static void main(String[] args) throws UnknownHostException, 
     IOException { 
    Socket soc = null; 

    soc = new Socket("localhost", 6060); 
    PrintWriter out = new PrintWriter(soc.getOutputStream(), true); 
    BufferedReader in = new BufferedReader(new InputStreamReader(
      soc.getInputStream())); 

    if (soc != null) 
     System.out.println("Connected"); 
    out.write("10\0"); 
    out.flush(); 
    out.write("newCon\0"); 
    out.flush();  
    out.close(); 
    in.close(); 
    soc.close(); 
} 

Так что же случилось с методом hasData FD_ISSET?

ответ

1

В чем проблема с методом hasData FD_ISSET?

Фактически нет. Существует проблема с использованием recv().

recv() вернет 0, если клиент отключен и вернет его до тех пор, пока вы не получите close сокет (на стороне сервера). Вы можете найти эту информацию in the manual. Даже если recv() возвращает 0, он будет «триггером» select().

Зная, что это легко понять, вы никогда не проверяете возвращаемое значение recv(), и поэтому вы не можете сказать, подключен ли клиент по-прежнему. Однако вы все равно добавляете его с FD_SET!

#include <sys/types.h> // for ssize_t 
#include <stdio.h> // for perror() 
ClientHandle::ClientHandle(SOCKET s) : m_sock(s) 
{ 
    while (!hasData()) 
    { 
    } 
    char buffer[5]; 
    ssize_t ret = recv(m_sock, buffer, 4, NULL); 
    if (ret == -1) // error 
    { 
     perror("recv"); 
     return ; 
    } 
    else if (ret == 0) // m_sock disconnects 
    { 
     close(m_sock); 
     // DO NOT FD_SET m_sock since the socket is now closed 
    } 
    else 
    { 
     auto i = atoi(buffer); 
     LOG_INFO << "Byte to receive: " << i; 
     auto dataBuffer = new char[i + 1]{'\0'}; 
     recv(m_sock, dataBuffer, i, NULL); 
     LOG_INFO << dataBuffer; 
     //clean up 
     delete[] dataBuffer; 
    } 
} 
+0

, поэтому данные имеют прекрасный результат, но, как я вижу из других ответов, он вернется в другие условия. (а не только если он содержит новые данные, что я думал), поэтому метод hasdata не подходит. Поэтому мне нужно как-то добавить это. – BennX

+0

@BennX 'hasData()' почти правильно: вы не должны использовать 'FD_SET' в отключенном сокете. 'recv()' возвращает положительное число, если оно получает данные, '0', если клиент отключается и' -1', если произошла ошибка. Я обновил свой ответ, чтобы добавить больше объяснений. – nouney

+0

Итак, чтобы проверить, есть ли у меня данные, я просто recv и обрабатываю его, если есть новый? Я решил, что могу проверить его с помощью select, прежде чем попытаться получить данные. – BennX

1

Из книги UNIX Networking Программирование Стивенса:

Сокет готов для чтения, если любой из следующих четырех условий:

  • Количество байт данных в сокет получить буфер больше или равно текущему размеру метки низкого уровня для буфера приема сокета. Операция чтения в сокете не будет блокироваться и вернет значение больше 0 (то есть данные, которые готовы к чтению). Мы можем установить эту отметку с низким уровнем воды, используя опцию SO_RCVLOWAT. Он по умолчанию равен 1 для сокетов TCP и UDP.

  • Полученная половина соединения закрыта (то есть TCP-соединение, получившее FIN). Операция чтения в сокете не будет блокироваться и вернет 0 (то есть EOF).

  • Сокет представляет собой гнездо для прослушивания, а количество завершенных соединений отличное от нуля. Прием на слушающий сокет, как правило, не блокируется, хотя мы опишем условие синхронизации в Разделе 16.6, под которым может блокировать accept.

  • Ошибка сокета в ожидании. Операция чтения в сокете не будет блокироваться и вернет ошибку (-1) с ошибкой, установленной для конкретного условия ошибки. Эти ожидающие ошибки также могут быть извлечены и очищены, вызвав getockopt и указав опцию сокета SO_ERROR.

ISSET вернёт истину во всех случаях выше. После того, как ваш клиент Java закроет соединение, сокет будет готов для чтения на сервере.

В ClientHandle :: ClientHandle вы не проверяете возвращаемое значение recv и если какие-либо данные возвращаются.

Заблокирован ли он во втором вызове recv?

+0

Я вижу, поэтому hasData на самом деле неверна. Можете ли вы опубликовать правильный способ проверки наличия новых данных у клиента? Он должен блокироваться, но поскольку я сбрасываю эти вызовы, он не блокируется и работает нормально. – BennX

+1

@BennX, просто проверьте возвращаемое значение первого recv для ошибки или для 0 (нулевых) данных. Если возвращаемое значение равно 0, и оно считывает 0 данных, соединение закрывается. Если возвращаемое значение равно! = 0, проверьте наличие ошибки. Вызывайте второй recv только в том случае, если первое было успешным, прочитав> 0 байт – rodolk

1

Вы не проверяете возвращаемое значение recv и не обрабатываете получение меньшего количества байтов, чем вы просили. Итак, что вы ожидаете, когда соединение будет закрыто?