Ошибка сокета: WSAEWOULDBLOCK
, Из-за чего? Как Избежать?
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.105] |
|
|
Ошибка сокета: WSAEWOULDBLOCK
, Из-за чего? Как Избежать?
|
Сообщ.
#1
,
|
|
|
|
Добрый день.
Возникла такая проблема: я создаю обычный блокирующий сокет и пытаюсь передать в цикле буфер message: ![]() ![]() int shift = 0, sending_len = 0, sent_count = 0, msg_len = 0, err_code = 0; BYTE message[MESSAGE_LEN] = {0}; //составление message и получение msg_len .............. while(shift < msg_len) { if(shift + SENDING_SUBPART_SIZE < msg_len) sending_len = SENDING_SUBPART_SIZE; else sending_len = msg_len - shift; sent_count = send(sock, (char*)(message + shift), sending_len, 0); if( sent_count != sending_len ){ err_code = WSAGetLastError(); Sleep(100); continue; } shift += sending_len; } Цикл, вообщем, отрабатывает, но довольно часто send возвращает -1, а WSAGetLastError - WSAEWOULDBLOCK. В МСДНе пишут: Цитата A non-blocking socket operation could not be completed immediately. Но как избавиться от ошибки я так и не понял. Если кто-нибудь встречался с подобным, подскажите пожалуйста, как избавиться. -------------------------------- WinXP, VS .NET |
|
Сообщ.
#2
,
|
|
|
|
Чаше всего такое происходит, когда принимающая сторона не успевает считывать данные. Либо переходи на асинхр. работу с сокетами и с удобствами FD_WRITE для таких затыков. Либо придумывай таймаут на всю операцию отсылки, и в случае блокирования сокета пытайся отправлять до истечения этого таймаута. Причем, учитывай ещё один не маловажный момент - в мсдн есть предупреждение, что в случае НЕ успеха операции send (истечение сокетного таймаута), состояние сокета становится НЕ предсказуемым и дальнейшая работа с ним НЕ рекомендуется
|
|
Сообщ.
#3
,
|
|
|
|
а зачем ты отправляешь буффер кусками?
Отправляй все сразу , стек сам разобъет пакет на нужное число.. |
|
Сообщ.
#4
,
|
|
|
|
Ace, ок, спасибо. У меня кстати, недавно возникал вопрос, зачем вообще нужен FD_WRITE
. Теперь ясно.LuckLess, а если у меня буфер боьшой - несколько мегабайт, то всё равно передавать в send весь буфер и всё будет ок? Я проверил. Всё замечательно бьётся и WSAEWOULDBLOCK перестал появляться. |
|
Сообщ.
#5
,
|
|
|
|
Цитата For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying provider, which can be obtained by using getsockopt to retrieve the value of socket option SO_MAX_MSG_SIZE. If the data is too long to pass atomically through the underlying protocol, the error WSAEMSGSIZE is returned, and no data is transmitted. зависит от используемого протокола.. какой сокет у тебя? Добавлено форум чтото подвисает... |
|
Сообщ.
#6
,
|
|
|
|
sham6215
Цитата а если у меня буфер большой send() и будет "висеть", пока все не передаст Согласно Стивенсу: "Когда приложение вызывает функцию write()[читай send()], ядро копирует данные из буфера приложения в буфер отправки сокета. Если для всех данных приложения недостаточно места в буфере сокета (либо буфер приложения больше буфера отправки сокета, либо в буфере отправки сокета уже имеются данные), этот процесс приостанавливается (переходит в состояние ожидания - те висит.) Подразумевается, что мы используем обычный блокируемый сокет" Мне почему то кажется, что ваша проблема в (message + shift) Для разбивки буфера на две и более частей в Unix используют writev() В Windows - это WSASend() + надо заказывать winsock 2.0 |
|
Сообщ.
#7
,
|
|
|
|
Oleg2004
а разве для connection-orientied протоколов send() автоматом большой буфер на части не разложит? |
|
Сообщ.
#8
,
|
|
|
|
LuckLess
Думаю нет - у него руки связаны. Он должен как чурка переслать все что в его буфере - в буфер TCP - и он это делает "своими" частями - указывает наверно индекс и "ползет по памяти" и тд - но никогда не разбивает. За сколько времени - ему тоже все равно, и возвратит управление только тогда, когда все отослано. А -1 - это только чисто при ошибке, и проверка тут на длину я думаю ничего полезного не даст. А тут (message + shift) - я не могу точно сказать, как это будет интерпретироваться |
|
Сообщ.
#9
,
|
|
|
|
Oleg2004
странно тогда что пишут Цитата For message-oriented sockets вечерком попробую... |
|
Сообщ.
#10
,
|
|
|
|
Цитата LuckLess @ зависит от используемого протокола.. какой сокет у тебя? Обычный блокирующий сокет. Протокол TCP (SOCK_STREAM). Цитата Oleg2004 @ В Windows - это WSASend() + надо заказывать winsock 2.0 Значит ли это, что в Windows следует отказываться от send в пользу WSASend? Цитата LuckLess @ а разве для connection-orientied протоколов send() автоматом большой буфер на части не разложит? Цитата Oleg2004 @ Думаю нет - у него руки связаны. Я проверял снифером прогу (которая является прототипом того, что делаю я) и увидел, что буфер разбивается на части. По-этому и затеял всё с разбивкой буфера. А когда стал передавать буфер целиком, то результат получился такой же, как в программе-прототипе (снифер показал, что моё сообщение отправляется несколькими пакетами) и исчезли ошибки. Цитата Oleg2004 @ А тут (message + shift) - я не могу точно сказать, как это будет интерпретироваться message - буфер, shift - количество байт уже переданных. (message + shift) - адрес, с которого следует считывать данные. Тут, ИМХО, всё нормально. |
|
Сообщ.
#11
,
|
|
|
|
sham6215
Цитата А когда стал передавать буфер целиком, то результат получился такой же, как в программе-прототипе (снифер показал, что моё сообщение отправляется несколькими пакетами) и исчезли ошибки. Что и требовалось доказать Если ваш TCP-сегмент меньше чем 1460 байт - все уйдет в одном IP- пакете - если вы находитесь в сети Ethernet - все зависит от MTU сети. Если больше чем 1460б - тогда send() из своего буфера - цельного - сам, без вашей помощи, нарезает куски нужной длины и отдает в буфер модуля TCP Вы должны точно себе представлять - буфер send() - сам по себе - это буфер программы пользовательского уровня А буфер TCP - это буфер системный, и на него можно влиять только через setsockopt() Цитата Значит ли это, что в Windows следует отказываться от send в пользу WSASend? Cовсем не значит. send() прекрасно работает в Windows. WSASend() имеет просто несколько важных преимуществ, первое из которых - это асинхронная функция, а второе - больше параметров - значит возможностей. А также надо иметь в виду, что в Windows 6 моделей сетевого ввода/вывода, и для некоторых можно работать только с WSASend() - например модель с перекрытием overlapped I/O (или ее самый мощный вариант - completion port) - вы запускаете на одном сокете несколько WSASend() одновременно. Цитата message - буфер, shift - количество байт уже переданных. (message + shift) - адрес, с которого следует считывать данные. Тут, ИМХО, всё нормально. Тут как раз ненормально Вы пытаетесь в функции send() реализовать ее-же функциональность - подсказать send(), откуда надо работать - нонсенс. Она сама это прекрасно знает - что вы думаете, ее ламеры делали??? |
|
Сообщ.
#12
,
|
|
|
|
Цитата Oleg2004 @ Она сама это прекрасно знает - что вы думаете, ее ламеры делали??? , нет, просто не знал, что:Цитата Oleg2004 @ Если больше чем 1460б - тогда send() из своего буфера - цельного - сам, без вашей помощи, нарезает куски нужной длины и отдает в буфер модуля TCP Спасибо, за исчерпывающее объяснение. |
|
Сообщ.
#13
,
|
|
|
|
Цитата sham6215 @ Я проверял снифером прогу (которая является прототипом того, что делаю я) и увидел, что буфер разбивается на части. По-этому и затеял всё с разбивкой буфера. А когда стал передавать буфер целиком, то результат получился такой же, как в программе-прототипе (снифер показал, что моё сообщение отправляется несколькими пакетами) и исчезли ошибки. хорошо что отписал. а то у меня все времени небыло проверить))). Oleg2004 Цитата Oleg2004 @ Если больше чем 1460б - тогда send() из своего буфера - цельного - сам, без вашей помощи, нарезает куски нужной длины и отдает в буфер модуля TCP а под nix-ами другой результат будет? |
|
Сообщ.
#14
,
|
|
|
|
LuckLess
Цитата а под nix-ами другой результат будет? Не думаю - ведь send() - это юниксовая функция Просто портирована в Windows |