2015-03-17 5 views
0

Я использую winsock2 api, tcp сокеты с сервером и клиентом. Я использую блокировку send и recv. Коммуникация такова: Сервер отправляет запрос ответам клиента и клиента обратно. Каждый запрос имеет буфер 1024 байта, а клиент также использует буфер того же размера. Фактические данные для отправки могут отличаться для каждого запроса и ответа.Сокетная связь выходит из строя

То, что я наблюдаю, иногда, сообщение выходит из строя. Сервер получает некоторые данные о мусоре. Несмотря на то, что вызов recv блокируется, он идет с некоторыми данными мусора, полученными в буфере recv.

Почему причина такого поведения? Какое решение для этого?

Код сниппета:

SOCKET ListenSocket=(SOCKET)arg; 
int iResult; 
int CMD_SIZE = 1024; 
u_long iMode; 
SOCKET ClientSocket; 
CbClient *tempClient = NULL; 

// Listen to incoming connetion 
iResult = listen(ListenSocket, 5); 
if (iResult == SOCKET_ERROR) 
{ 
    LOG(ERROR) << "Listen failed with error "<< iResult; 
    AfxMessageBox(TEXT("Listen Failed..!")); 
    closesocket(ListenSocket); 
    return 1; 
} 
// Valid Socket 
// Accept a client socket 
ClientSocket = accept(ListenSocket, NULL, NULL); 
if (ClientSocket == INVALID_SOCKET) 
{ 
    LOG(ERROR) << "Client Socket not created "; 
    AfxMessageBox(TEXT("Accept Failed..!")); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 
else 
{ 
    iMode = 0; 
    iResult = ioctlsocket(ClientSocket, FIONBIO, &iMode); 
    if (iResult != NO_ERROR) 
    { 
     LOG(ERROR) << "IoctlSocket failed with error "<< iResult; 
    } 

    //disable nagle 
    char value = 1; 
    if(setsockopt(ClientSocket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)) == 0) 
    { 
     LOG(DEBUG) << "Disabled Nagle's Algorithm."; 
    } 

    int serverVerion   = SERVER_VERSION_NUMERIC; 
    int clientVersion   = 0; 
    char ver[CMD_SIZE]  = {0}; 
    char recvbuf[CMD_SIZE] = {0}; 

    // Send Server Version 
    sprintf_s(ver, "%d", serverVerion); 
    iResult = send(ClientSocket, ver, CMD_SIZE, 0); 
    // Receive client version 
    ZeroMemory(recvbuf,CMD_SIZE); 
    iResult=recv(ClientSocket, recvbuf, CMD_SIZE, 0); 
    clientVersion = atoi(recvbuf); 

    // Match Versions to Check Compatibility 
    if(serverVerion != clientVersion) 
    { 
     LOG(ERROR) << "Client-Server Version does not match, Client denied "<< iResult; 
     AfxMessageBox(_T("\nWarning : Client-Server Version does not match. Please Use Same Version")); 
    } 
    else 
    {    
     // Send Server details 
     char hostName[CMD_SIZE]; 
     DWORD dwCompNameLen = CMD_SIZE; 

     if (0 != GetComputerNameA(hostName, &dwCompNameLen)) 
     { 
      iResult = send(ClientSocket, hostName, CMD_SIZE, 0); 
     } 
     else 
     { 
      iResult = send(ClientSocket, "UNKNOWN", CMD_SIZE, 0); 
     } 
     // Receive Client Host Name 
     ZeroMemory(recvbuf, CMD_SIZE); 
     iResult=recv(ClientSocket, recvbuf, CMD_SIZE, 0); 

     //Send Query and Recv replied back Results on seperate thread 
    } 
} 

код для запроса и Recv ответа: SendCommand (ClientSocket, DataBuffer, размер, флаги, дополнительный PARAMS) и recvCommand (ClientSocket, DataBuffer, размер, флаги, дополнительный PARAMS) являются обертка через вызовы send() и recv().

My проблема воспроизведение скорость ~ 1 из 10 раз.

if(currentSendCmd->iCmd == CMD_ONE) 
{ 
    // Send the Command over the Socket 
    if(sendCommand(clientSocket, currentSendCmd, CMD_SIZE , 0, Client)) 
    { 
     // Receiving response from client 
     if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client)) 
     { 
      if(currentRecvCmd->iCmd == CMD_ONE) 
      { 
       LOG(DEBUG) << "CMD_ONE command positive acknowledgement recieved"; 
       for(i = 0; i< Client->GetSomeCount(); i++) 
       { 
        for(j = 0; j < CMD_ONE_REPLY_CMD_COUNT; j++) 
        { 
         // Receiving responses from client w.r.t. Gpu Info 
         if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client)) 
         { 
          LOG(DEBUG) << "CMD_ONE command response no : " << i <<" recieved successfully"; 
          flag = Client->UpdateClient(currentRecvCmd); 
          if(flag == FALSE) 
          { 
           LOG(DEBUG) << "CMD_ONE update no :"<<i<<" failed"; 
          } 
         } 
         else 
         { // Recv failed, updated in log 
          LOG(WARNING) << "CMD_ONE response no :"<<i<<" not recieved"; 
         } 
        }// For CMD_ONE_REPLY_CMD_COUNT cmds 
       }// For some count 

       //Recieving CL_CMD_TWO info 
       if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client)) 
       { 
        LOG(DEBUG) << "CL_CMD_TWO recieved successfully"; 
        flag = Client->UpdateClient(currentRecvCmd); 

        if(flag == FALSE) 
        { 
         LOG(DEBUG) << "CL_CMD_TWO update failed"; 
        }            
       } 
       else 
       { // Recv failed, updated in log 
        LOG(WARNING) << "CL_CMD_TWO not recieved"; 
       } 

       // Recieving CL_CMD_THREE Info            
       if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client)) 
       { 
        LOG(DEBUG) << "CL_CMD_THREE recieved successfully"; 
        flag = Client->UpdateClient(currentRecvCmd); 

        if(flag == FALSE) 
        { 
         LOG(ERROR) << "CL_CMD_THREE Update failed"; 
        }            
       } 
       else 
       { // Recv failed, updated in log 
        LOG(ERROR) << "CL_CMD_THREE not recieved"; 
       } 
      }//CL_CMD_ONE : End 
      else 
      { // Recv failed, updated in log 
       LOG(ERROR) << "Unrecognised command"; 
      } 
     }//CL_CMD_ONE send, recv if 
     else 
     { // Recv failed, updated in log 
      LOG(ERROR) << "Recv failed : CL_CMD_ONE"; 
     }      
    } 
+2

Предоставьте [MCVE] (http://stackoverflow.com/help/mcve). – TobiMcNamobi

+0

Вы указываете 'MSG_WAITALL' среди флагов, переданных' recv() '? –

+0

Для получения я передаю '0' в качестве флага. –

ответ

1

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

+0

В первом фрагменте кода я не проверяю возвращаемые значения send() и recv(). Во втором фрагменте кода я это делаю. Что делает MSG_WAITALL? Вся нить должна ждать, пока текущая нить не прочитает? –

+0

На данный момент я добавляю проверку ошибок в первом фрагменте кода и «MSG_WAITALL» для всех вызовов recv/ –

+0

В [документах] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121% 28v = vs.85% 29.aspx), флаг 'MSG_WAITALL' делает блок' recv() 'до тех пор, пока он не заполнит предоставленный буфер (до указанного предела), соединение не будет закрыто или произойдет ошибка. Другими словами, он предотвращает получение частичного сообщения, которое иначе может случиться. –

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