Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > send возвращает ошибку, но код ошибки 0


Автор: Alexeis 27.9.2011, 12:58
Соединение активно, TCP/IP клиентский сокет в режиме блокировки. Передает блоки по 4кб. После передачи ~20кб данных функция send неожиданно выдает результат -1, т.е. SOCKET_ERROR, но когда смотрим WSAGetLastError() , то код ошибки 0, т.е. успех  smile . Так есть ошибка или нет?

Код

    WSASetLastError(0);
    int len = send(sock, Buffer, Len, 0);
    if (len == SOCKET_ERROR) 
           {
            int r = WSAGetLastError();
            String s = SysErrorMessage(r);
...


Опытным путем было установлено, что если слать данные серверу реже, то ошибка не возникает. Отсюда возникло предположение о том, что переполняется либо буфер отправки клиента, либо буфер приема сервера, но в этом случае WSAGetLastError не должен возвращать успех. Вообще, если не вызывать WSASetLastError(0); то код ошибки получается от вызова другой функции, т.е. функция send вообще не устанавливает код ошибки, так как будто ошибка и не происходила вовсе (так описано в документации по send). 
  Все таки ошибка была или нет? А если была, то как узнать ее описание?

Автор: Alexeis 27.9.2011, 16:07
В чем причина отсутствия кода ошибки узнать не удалось, но предполагая что ошибка таки WSAENOBUFS, использовав статью http://support.microsoft.com/kb/201213/en-us , удалось избавиться от появления ошибки. 
Фактически я отключил буферизацию сокета на отправку
Код

    int val = 0;
    setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, sizeof(val));

Вероятнее всего дело было в переполнении буфера отправки. Нет буфера, нет переполнения smile .

Автор: Олег2005 27.9.2011, 20:28
Странно, почему вы использовали третий способ:
    Use the socket in nonblocking or asynchronous mode.
    Break large-size data blocks into small ones and specify a relatively small buffer in send for blocking sockets, preferably no larger than 64K.
    Set the SO_SNDBUF socket option to 0 (zero) to allow the stack to send from your application buffer directly.

Цитата

Передает блоки по 4кб. После передачи ~20кб данных функция send неожиданно выдает результат -1, т.е. SOCKET_ERROR, но когда смотрим WSAGetLastError() , то код ошибки 0, т.е. успех. 

Стандартный буфер сокета для TCP в винде - Default: 17520 байт
Вот отсюда и проблемы около 20Кб.
Есть несколько вариантов
посмотреть getsockopt() размер буфера и убедиться, что он достаточен.
Установить больший - если надо.
У вас же передаются блоки по 4 к - это очень мало для переполнения стандартного буфера. 
Единственный вариант - модуль TCP - не может передать в буфер сетевой карты - потому как она еще не отправила предыдущие данные. Это может быть при сильной перегрузке сети.
Во всяком случае не все так очевидно.
Можно еще слать с задержкой - скажем 10 миллисекунд в sleep

Автор: Alexeis 27.9.2011, 22:34
Цитата(Олег2005 @  27.9.2011,  21:28 Найти цитируемый пост)
Стандартный буфер сокета для TCP в винде - Default: 17520 байт

  Проверял, там размер 8кб, видимо он сравнял его с буфером приема сервера, потому что там тоже 8кб. Это как раз и странно, что успевает отправиться больше чем размер буфера. Загрузки сети ни какой, потому что сервер соединен с клиентом напрямую витой парой. 
>Break large-size data blocks into small ones and specify a relatively small buffer in send for blocking sockets, preferably no larger than 64K
 Так 4Кб как раз и соответствует описанию. Так что тут нечего было менять.

Цитата(Олег2005 @  27.9.2011,  21:28 Найти цитируемый пост)
Можно еще слать с задержкой - скажем 10 миллисекунд в sleep

  Делал, именно так и выяснил. Если задержка 50мс, то нормально отправляется, если 10мс, то успевает переполниться. Однако в режиме с отключенным буфером скорость передачи выше чем с задержкой 50мс. Вообще, не охота играть с таймерами, поскольку задержки по пересылу врядли стабильны во времени. Когда больше, когда меньше. 

Автор: Олег2005 27.9.2011, 22:55
В общем проблема понята и решена. smile 

Автор: Alexeis 27.9.2011, 22:58
Цитата(Олег2005 @  27.9.2011,  23:55 Найти цитируемый пост)
В общем проблема понята и решена.

  Не совсем. Меня мучает вопрос, почему код ошибки не возвращается никакой. Слабо вериться что это глюк семерки, пусть даже 64х битной. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)