2016-02-19 6 views
0

я могу ясно видеть, что recvbuf имеет все данные, я ожидал еще select() продолжает возвращающийся 1.Почему select() возвращает 1, но recv() возвращает 0?

Прямо сейчас он застрял в чистилище else if (iBuffer == 0) {}.

SOCKET m_ConnectSocket; 
/* The socket setup is done elsewhere but just adding this for clarity 
    This socket is responsible for sending from the client to the server 
    and also receives anything the server sends back. 

    This socket is doing the connect() & initial send() 
*/ 

fd_set set; 
struct timeval timeout; 

// Set up the file descriptor set. 
FD_ZERO(&set); 
FD_SET(m_ConnectSocket, &set); 

// Set up the struct timeval for the timeout. 
timeout.tv_sec = RECV_DELAY_SEC; 
timeout.tv_usec = RECV_DELAY_USEC; 

int iBuffer = 0; 

do 
{ 
    iResult = select(m_ConnectSocket, &set, NULL, NULL, &timeout); 
    if (iResult > 0) 
    { 
     iBuffer = recv(m_ConnectSocket, recvbuf, DEFAULT_BUFLEN, 0); 
     if (iBuffer > 0) 
     { 
      string sRecv(recvbuf); 

      STrace = String::Format("Bytes Received: {0}", iBuffer); 
      Trace(STrace, TRACE_INFO); 

      STrace = String::Format("Data Received: [{0}]", gcnew String(sRecv.c_str())); 
      Trace(STrace, TRACE_INFO); 
     } 
     else if (iBuffer == 0) 
     { 
      STrace = String::Format("iBuffer empty"); 
      Trace(STrace, TRACE_INFO); 
     } 
     else 
     { 
      STrace = String::Format("recv failed: {0}", WSAGetLastError()); 
      Trace(STrace, TRACE_ERROR); 
     } 
    } 
    else if (iResult == 0) 
    { 
     STrace = String::Format("No data left in buffer"); 
     Trace(STrace, TRACE_INFO); 

     pMessage->Data(recvbuf); 
     if (iSentType != pMessage->Type()) 
     { 
      STrace = String::Format("Message type mismatch: {0} | Expected: {1}", (int)pMessage->Type(), (int)iSentType); 
      Trace(STrace, TRACE_WARNING); 
     } 
    } 
    else if (iResult == -1) 
    { 
     STrace = String::Format("select() error"); 
     Trace(STrace, TRACE_ERROR); 
    } 
} while (iResult > 0); 
+0

Выбирает ли возвращение 1 первое или последующее время вокруг цикла? –

+0

Это соединение UDP? Какова ценность DEFAULT_BUFLEN? Почему вы передаете 'm_connectSocket' для выбора вместо' 1'? (первым параметром select должно быть количество проверяемых файловых дескрипторов). – kfsone

+0

AFAIR, первый аргумент 'select()' - это количество слотов в наборах, которые нужно зашить, а не число наибольшего дескриптора в них. Поэтому iff 'm_ConnectSocket' является наивысшим fd в наборах, я думаю, вы должны сделать' select (m_ConnectSocket + 1, ...) '. – Paulo1205

ответ

2

Как select имеет его параметры передаются как указатель и эти структуры данных получить измененные select поместить

fd_set set; 
struct timeval timeout; 

// Set up the file descriptor set. 
FD_ZERO(&set); 
FD_SET(m_ConnectSocket, &set); 

// Set up the struct timeval for the timeout. 
timeout.tv_sec = RECV_DELAY_SEC; 
timeout.tv_usec = RECV_DELAY_USEC; 

Непосредственно перед select заявления т.е. внутри цикла.

+0

Итак, я сделал это, но я все же иногда вхожу в ситуацию навсегда. Теперь мне интересно, если это имеет какое-то отношение к состоянию сокета на противоположной стороне. – Enigma

+0

Это происходит довольно необычно и (я думаю), только когда у меня есть точки останова, попадающие в поток. – Enigma

+0

Когда он возвращает 1, recv может возвращать -1. Поэтому эта розетка закрылась. –

1

Вы неправильно используете select(). Пожалуйста, ознакомьтесь с documentation:

Параметры

nfds [в]
игнорируемые. Параметр nfds включен только для совместимости с сокетами Berkeley.

...

После возвращения структуры обновляются, чтобы отразить подмножество этих гнезд, которые удовлетворяют заданному условию.

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

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

Кроме того, ваша обработка ошибок в целом также может улучшить некоторые улучшения.

Попробуйте что-то больше, как это вместо:

fd_set set; 
struct timeval timeout; 

string sBuffer; 
int iBuffer; 

do 
{ 
    // Set up the file descriptor set. 
    FD_ZERO(&set); 
    FD_SET(m_ConnectSocket, &set); 

    // Set up the struct timeval for the timeout. 
    timeout.tv_sec = RECV_DELAY_SEC; 
    timeout.tv_usec = RECV_DELAY_USEC; 

    iResult = select(0, &set, NULL, NULL, &timeout); 
    if (iResult > 0) 
    { 
     iBuffer = recv(m_ConnectSocket, recvbuf, DEFAULT_BUFLEN, 0); 
     if (iBuffer > 0) 
     { 
      string sRecv(recvbuf, iBuffer); 

      STrace = String::Format("Bytes Received: {0}", iBuffer); 
      Trace(STrace, TRACE_INFO); 

      STrace = String::Format("Data Received: [{0}]", gcnew String(sRecv.c_str())); 
      Trace(STrace, TRACE_INFO); 

      sBuffer += sRecv; 
     } 
     else 
     { 
      if (iBuffer == 0) 
      { 
       STrace = String::Format("Connection closed"); 
       Trace(STrace, TRACE_INFO); 
      } 
      else 
      { 
       STrace = String::Format("recv failed: {0}", WSAGetLastError()); 
       Trace(STrace, TRACE_ERROR); 
      } 
      break; 
     } 
    } 
    else if (iResult == 0) 
    { 
     STrace = String::Format("No data left in buffer"); 
     Trace(STrace, TRACE_INFO); 

     pMessage->Data(sBuffer.c_str()); 
     if (iSentType != pMessage->Type()) 
     { 
      STrace = String::Format("Message type mismatch: {0} | Expected: {1}", (int)pMessage->Type(), (int)iSentType); 
      Trace(STrace, TRACE_WARNING); 
     } 
    } 
    else 
    { 
     STrace = String::Format("select failed: {0}", WSAGetLastError()); 
     Trace(STrace, TRACE_ERROR); 
    } 
} 
while (iResult > 0); 
1

Все ответы до сих пор являются правильными в том, что они говорят о сбросе множества FD, но ни один из них фактически не определили основную проблему.

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

не средний «буфер пустой».

Смежные вопросы