sendto на Tru64 возвращается ENOBUF - PullRequest
2 голосов
/ 11 мая 2010

В настоящее время я использую старую систему на Tru64, которая использует множество сокетов UDP с использованием функции sendto (). Сокеты используются в нашем коде для отправки сообщений в / из различных процессов и затем в конечном итоге в приложение толстого клиента, которое подключается удаленно. Иногда гнездо для толстого клиента застревает, это может привести к созданию некоторых из этих сообщений. У меня вопрос, как я могу определить текущий размер буфера и как определить максимальный размер буфера сообщений. Приведенный ниже код дает фрагмент того, как я настраиваю порт и использую функцию sendto.

/* need to adjust the maximum size we can send on this */
/* as it needs to be able to cope with the biggest     */
/* messages we send                                    */

lenlen = sizeof(len) ;

/* allow double for when the system is under load */
int                 lenlen, len ;
lenlen = sizeof(len) ;
len = 2 * 32000;

msg_socket = socket( AF_UNIX,SOCK_DGRAM, 0);

 result = setsockopt(msg_socket, SOL_SOCKET, SO_SNDBUF, (char *)&len, lenlen) ;

    result = sendto( msg_socket,
                         (char *)message,
                         (int)message_len,
                         flags,
                         dest_addr,
                         addrlen);

Примечание. Мы портировали это приложение на Linux, и проблема, похоже, там не появляется.

Любая помощь будет принята с благодарностью.

Привет

Ответы [ 2 ]

2 голосов
/ 11 сентября 2010

Размер буфера отправки UDP отличается от TCP - он просто ограничивает размер дейтаграммы. Цитируя Стивенса UNP Vol. 1:

... У сокета UDP есть размер буфера отправки (который мы можем изменить с помощью опции сокета SO_SNDBUF, раздел 7.5), но это просто верхний предел дейтаграммы UDP максимального размера, которую можно записать в сокет. Если приложение записывает датаграмму больше, чем размер буфера отправки сокета, возвращается EMSGSIZE. Поскольку UDP ненадежен, ему не нужно хранить копию данных приложения и не требуется фактический буфер отправки. (Данные приложения обычно копируются в буфер ядра некоторой формы при передаче по стеку протоколов, но эта копия отбрасывается уровнем канала передачи данных после передачи данных.)
UDP просто добавляет 8-байтовый заголовок и передает дейтаграмму в IP. IPv4 или IPv6 предварительно добавляет свой заголовок, определяет исходящий интерфейс, выполняя функцию маршрутизации, а затем либо добавляет дейтаграмму в выходную очередь канала данных (если она соответствует MTU), либо фрагментирует дейтаграмму и добавляет каждый фрагмент в выходную очередь канала данных. Если приложение UDO отправляет большие дейтаграммы (скажем, 2000-байтовые дейтаграммы), вероятность фрагментации гораздо выше, чем с TCP. потому что TCP разбивает данные приложения на куски размера MSS, что не имеет аналогов в UDP.
Успешный возврат из write в сокет UDP говорит нам о том, что либо датаграмма, либо все фрагменты дейтаграммы были добавлены в очередь вывода канала данных. Если в очереди нет места для дейтаграммы или одного из ее фрагментов, ENOBUFS часто возвращается в приложение.
К сожалению, некоторые реализации не возвращают эту ошибку, не давая приложению никаких указаний на то, что дейтаграмма была отброшена даже без передачи.

Последняя сноска требует внимания - но похоже, что Tru64 имеет этот код ошибки, указанный на странице руководства .

Тем не менее, правильный способ сделать это состоит в том, чтобы поставить в очередь ваши ожидающие сообщения в самом приложении и тщательно проверять возвращаемые значения и errno после каждого системного вызова. Это все еще не гарантирует доставку (так как получатели UDP могут отбрасывать пакеты без какого-либо уведомления отправителей). Проверьте счетчики сброса пакетов UDP с netstat -s на обеих / всех сторонах, посмотрите, растут ли они. На самом деле нет никакого способа обойти это, кроме переключения на TCP или реализации собственной логики тайм-аута / подтверждения и повторной передачи.

0 голосов
/ 11 сентября 2010

Вероятно, вам следует использовать какой-либо контроль перегрузки, чтобы избежать перегрузки сети. Безусловно, самый простой способ сделать это - использовать TCP вместо UDP.

В Linux это происходит не так часто, потому что UDP-сокеты ждут места в очереди локального сетевого интерфейса в Linux (если вы не установили их неблокирующими). Однако в любой операционной системе, если очередь переполнения отсутствует в локальной системе, пакет будет отброшен без уведомления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...