Количество извлечённых байт через recv()

Тема в разделе "WASM.NETWORKS", создана пользователем s3dworld, 4 сен 2011.

  1. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Получение:

    Код (Text):
    1. int Socket::SockRecv(unsigned int _needRecvBytes,unsigned int* _recvBytes)
    2. {
    3.     int result=0;
    4.     int recvResult=0;
    5.     int recvBytes=0;
    6.     char* data=0;
    7.  
    8.     EnterCriticalSection(&csSocket);
    9.  
    10.     if(!isConnected || !isAccessRecv || !isPossibleRecv)
    11.     {
    12.         LeaveCriticalSection(&csSocket);
    13.         return DNET_TCP_ERROR_ACCESS;
    14.     }
    15.  
    16.     if(!_needRecvBytes || !_recvBytes)
    17.     {
    18.         LeaveCriticalSection(&csSocket);
    19.         return DNET_TCP_ERROR_PARAM;
    20.     }
    21.  
    22.     isPossibleRecv=false;
    23.  
    24.     data=new (std::nothrow) char[_needRecvBytes];
    25.  
    26.     if(!data)
    27.     {
    28.         LeaveCriticalSection(&csSocket);
    29.         return DNET_TCP_ERROR_MEMORY;
    30.     }
    31.  
    32.     memset(data,0,_needRecvBytes);
    33.  
    34.     recvBytes=recv(entitySocket,data,_needRecvBytes,0);
    35.  
    36.     if(recvBytes==SOCKET_ERROR)
    37.     {
    38.         result=WSAGetLastError();
    39.         delete[] data;
    40.         LeaveCriticalSection(&csSocket);
    41.         return result;
    42.     }
    43.  
    44.     if(recvBytes)
    45.     {
    46.         recvResult=AddDataInEnd(&dataRecv,&dataRecvLength,data,recvBytes);
    47.  
    48.         if(recvResult!=DNET_TCP_OK)
    49.         {
    50.             delete[] data;
    51.             LeaveCriticalSection(&csSocket);
    52.             return recvResult;
    53.         }
    54.     }
    55.  
    56.     delete[] data;
    57.  
    58.     *_recvBytes=recvBytes;
    59.  
    60.     LeaveCriticalSection(&csSocket);
    61.  
    62.     return DNET_TCP_OK;
    63. }
    Отправка:

    Код (Text):
    1. int Socket::SockSend(unsigned int _needSendBytes,unsigned int* _sendBytes)
    2. {
    3.     int result=0;
    4.     int sendResult=0;
    5.     int sendBytes=0;
    6.     unsigned int i=0;
    7.     unsigned int dataLength=0;
    8.     char* data=0;
    9.     char* dataReturn=0;
    10.  
    11.     EnterCriticalSection(&csSocket);
    12.  
    13.     if(!isConnected || !isAccessSend)
    14.     {
    15.         LeaveCriticalSection(&csSocket);
    16.         return DNET_TCP_ERROR_ACCESS;
    17.     }
    18.  
    19.     if(!_needSendBytes || !_sendBytes)
    20.     {
    21.         LeaveCriticalSection(&csSocket);
    22.         return DNET_TCP_ERROR_PARAM;
    23.     }
    24.  
    25.     if(_needSendBytes>dataSendLength)
    26.         dataLength=dataSendLength;
    27.     else
    28.         dataLength=_needSendBytes;
    29.  
    30.     result=DelDataFromBegin(&dataSend,&dataSendLength,&data,dataLength);
    31.  
    32.     if(result!=DNET_TCP_OK)
    33.     {
    34.         LeaveCriticalSection(&csSocket);
    35.         return sendResult;
    36.     }
    37.  
    38.     sendBytes=send(entitySocket,data,dataLength,0);
    39.  
    40.     if(sendBytes==SOCKET_ERROR)
    41.     {
    42.         sendResult=WSAGetLastError();
    43.         result=AddDataInBegin(&dataSend,&dataSendLength,data,dataLength);
    44.  
    45.         if(result!=DNET_TCP_OK)
    46.         {
    47.             delete[] data;
    48.             LeaveCriticalSection(&csSocket);
    49.             return result;
    50.         }
    51.  
    52.         delete[] data;
    53.         LeaveCriticalSection(&csSocket);
    54.         return sendResult;
    55.     }
    56.  
    57.     if(sendBytes!=dataLength)
    58.     {
    59.         dataLength-=sendBytes;
    60.         dataReturn=new (std::nothrow) char[dataLength];
    61.  
    62.         if(!dataReturn)
    63.         {
    64.             delete[] data;
    65.             LeaveCriticalSection(&csSocket);
    66.             return DNET_TCP_ERROR_MEMORY;
    67.         }
    68.  
    69.         for(i=0;i<dataLength;i++)
    70.         {
    71.             dataReturn[i]=data[sendBytes+i];
    72.         }
    73.  
    74.         result=AddDataInBegin(&dataSend,&dataSendLength,dataReturn,dataLength);
    75.  
    76.         if(result!=DNET_TCP_OK)
    77.         {
    78.             delete[] data;
    79.             delete[] dataReturn;
    80.             LeaveCriticalSection(&csSocket);
    81.             return result;
    82.         }
    83.  
    84.         delete[] dataReturn;
    85.     }
    86.  
    87.     delete[] data;
    88.  
    89.     *_sendBytes=sendBytes;
    90.  
    91.     LeaveCriticalSection(&csSocket);
    92.  
    93.     return DNET_TCP_OK;
    94. }
     
  2. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    Мда.. ну и свистопляски у вас. Промолчу про критикал секшн, но зачем каждый раз выделять, копировать и удалять память? Почему просто не передвинуть указатель? Перемудрили. Будьте проще, ошибок меньше будет.
     
  3. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Aspire
    А что именно с критическими сессиями? Просто впервые ими пользуюсь (никогда раньше не писал многопоточные программы). Есть какие-то советы?

    На счёт памяти. Просто в голове возникла такая идея. Вместо того чтобы иметь один большой буфер с указателем, я каждый раз подчищаю память. Утечки нет.
     
  4. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    Если вы пользуюетесь неблокирующими сокетами, то нередко прогу можно организовать так, что она красиво будет работать в одном потоке (если сама реакция на получение цельного сообщения моментальна). ТОлько надо организовать так, чтоб в итоге получалась обслуживающая функция (или метод объекта, соответствующего конкретному TCP-соединению), принимающая в качестве аргумента точно одно сообщение, быстро делающая свою работу по обработке сообщения - и отдающая управление.
     
  5. Phyber

    Phyber New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    96
    Эм... хм... ну по логике, сколько отправляет, столько и получает.
    В отладчике когда смотрели, точно передавалось то кол-во байт, которое вы хотели отправить?
     
  6. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    s3dworld код ужасен, бесполезные манипуляции с буферами по изнасилованию cpu, особенно SockSend(), из-за которых у вас и получается косяк.
     
  7. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Хорошо. Перепишу. Но я же говорю, проблема с приёмом того, чего не пересылали пропала когда я изменил размер буферов приёма и отправки самого сокета, а не тех буферов, которые вы видели в коде выше. Значит советуете выделить один большой буфер и в него всё записывать и считывать, установив указатель на текущем символе и длину данных. Хорошо. Но а что с критическими секциями не понравилось? Пользуюсь не блокирующими сокетами.
     
  8. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    Я в свое время работал с асинхронными сокетами, формат сообщений был длина-сообщение. Никаких лишних данных в соединение не попадало, если б попадало - в формате длина-сообщение вообще нихрена бы не работало. Работал на самом низком уровне, через send, recv и WSAAsyncSelect.
    recv в ответ на сообщение от FD_READ пытался получить то количество байт, которое надо было до конца сообщения, если получал меньше - дописывал в буфер и передвигал указатель, если дополучал целиком - то буфер как цельное сообщение скармливал основной функции-обработчику.

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