На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Ошибка сокета: WSAEWOULDBLOCK , Из-за чего? Как Избежать?
    Добрый день.

    Возникла такая проблема: я создаю обычный блокирующий сокет и пытаюсь передать в цикле буфер message:
    ExpandedWrap disabled
      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
    Сообщение отредактировано: sham6215 -
      Чаше всего такое происходит, когда принимающая сторона не успевает считывать данные. Либо переходи на асинхр. работу с сокетами и с удобствами FD_WRITE для таких затыков. Либо придумывай таймаут на всю операцию отсылки, и в случае блокирования сокета пытайся отправлять до истечения этого таймаута. Причем, учитывай ещё один не маловажный момент - в мсдн есть предупреждение, что в случае НЕ успеха операции send (истечение сокетного таймаута), состояние сокета становится НЕ предсказуемым и дальнейшая работа с ним НЕ рекомендуется :)
        а зачем ты отправляешь буффер кусками?
        Отправляй все сразу , стек сам разобъет пакет на нужное число..
          Ace, ок, спасибо. У меня кстати, недавно возникал вопрос, зачем вообще нужен FD_WRITE :) . Теперь ясно.

          LuckLess, а если у меня буфер боьшой - несколько мегабайт, то всё равно передавать в send весь буфер и всё будет ок?

          Я проверил. Всё замечательно бьётся и WSAEWOULDBLOCK перестал появляться.
          Сообщение отредактировано: sham6215 -
            Цитата
            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.


            зависит от используемого протокола..
            какой сокет у тебя?

            Добавлено
            форум чтото подвисает...
              sham6215
              Цитата
              а если у меня буфер большой

              send() и будет "висеть", пока все не передаст
              Согласно Стивенсу:
              "Когда приложение вызывает функцию write()[читай send()], ядро копирует данные из буфера приложения в буфер отправки сокета. Если для всех данных приложения недостаточно места в буфере сокета (либо буфер приложения больше буфера отправки сокета, либо в буфере отправки сокета уже имеются данные), этот процесс приостанавливается (переходит в состояние ожидания - те висит.) Подразумевается, что мы используем обычный блокируемый сокет"
              Мне почему то кажется, что ваша проблема в (message + shift)
              Для разбивки буфера на две и более частей в Unix используют writev()
              В Windows - это WSASend() + надо заказывать winsock 2.0
                Oleg2004
                а разве для connection-orientied протоколов send() автоматом большой буфер на части не разложит?
                  LuckLess
                  Думаю нет - у него руки связаны.
                  Он должен как чурка переслать все что в его буфере - в буфер TCP - и он это делает "своими" частями - указывает наверно индекс и "ползет по памяти" и тд - но никогда не разбивает.
                  За сколько времени - ему тоже все равно, и возвратит управление только тогда, когда все отослано.
                  А -1 - это только чисто при ошибке, и проверка тут на длину я думаю ничего полезного не даст.
                  А тут (message + shift) - я не могу точно сказать, как это будет интерпретироваться
                    Oleg2004
                    странно тогда что пишут
                    Цитата

                    For message-oriented sockets


                    вечерком попробую...
                      Цитата 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) - адрес, с которого следует считывать данные. Тут, ИМХО, всё нормально.
                        sham6215
                        Цитата
                        А когда стал передавать буфер целиком, то результат получился такой же, как в программе-прототипе (снифер показал, что моё сообщение отправляется несколькими пакетами) и исчезли ошибки.

                        Что и требовалось доказать :yes:
                        Если ваш 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) - адрес, с которого следует считывать данные. Тут, ИМХО, всё нормально.

                        Тут как раз ненормально :yes:
                        Вы пытаетесь в функции send() реализовать ее-же функциональность - подсказать send(), откуда надо работать - нонсенс.
                        Она сама это прекрасно знает - что вы думаете, ее ламеры делали??? :wacko:
                        Сообщение отредактировано: Oleg2004 -
                          Цитата Oleg2004 @
                          Она сама это прекрасно знает - что вы думаете, ее ламеры делали???

                          :no: , нет, просто не знал, что:
                          Цитата Oleg2004 @
                          Если больше чем 1460б - тогда send() из своего буфера - цельного - сам, без вашей помощи, нарезает куски нужной длины и отдает в буфер модуля TCP


                          Спасибо, за исчерпывающее объяснение.
                            Цитата sham6215 @
                            Я проверял снифером прогу (которая является прототипом того, что делаю я) и увидел, что буфер разбивается на части. По-этому и затеял всё с разбивкой буфера. А когда стал передавать буфер целиком, то результат получился такой же, как в программе-прототипе (снифер показал, что моё сообщение отправляется несколькими пакетами) и исчезли ошибки.

                            хорошо что отписал.
                            а то у меня все времени небыло проверить))).

                            Oleg2004
                            Цитата Oleg2004 @
                            Если больше чем 1460б - тогда send() из своего буфера - цельного - сам, без вашей помощи, нарезает куски нужной длины и отдает в буфер модуля TCP

                            а под nix-ами другой результат будет?
                              LuckLess
                              Цитата
                              а под nix-ами другой результат будет?

                              Не думаю - ведь send() - это юниксовая функция
                              Просто портирована в Windows
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0.0860 ]   [ 16 queries used ]   [ Generated: 14.07.26, 08:58 GMT ]