На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Соблюдайте общие правила форума
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Указывайте точные версии Delphi и используемых сетевых библиотек.

Не приветствуется поднятие старых тем. Если ваш вопрос перекликается со старой темой, то для вопроса лучше создать новую тему, а старую указать в первом сообщении с описанием взаимосвязи.

Внимание:
попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Krid, user posted image Rouse_

Модераторы: Krid, Rouse_
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> SendTo виснет , UDP Winsock
    Здравствуйте, прошу помочь разобраться.
    Среда Delphi7, WinXP.
    По примеру из UDP Socket
    пробую отправить данные на локальную машину, с установленой Win7(домашняя сеть, компьютеры подлючены к шлюзу/сетевому коммутатору d-link):
    ExpandedWrap disabled
      procedure TForm1.Button1Click(Sender: TObject);
      var
        FWSAData: TWSAData;
        FSockAddr: TSockAddrIn;
        FSocket: HWND;
        data:array of byte;
      begin
        setlength(data,3000);
        WSAStartup($0101, FWSAData);
        FSocket := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        with FSockAddr do
        begin
          sin_addr.S_addr := Inet_Addr('192.168.1.56');
          sin_port := htons(5000);
          sin_family := AF_INET;
        end;
        SendTo(FSocket, Data[0], Length(Data), 0, FSockAddr, SizeOf(FSockAddr));
        ShowMessage(SysErrorMessage(WSAGetLastError));
        closesocket(FSocket);
        WSACleanup;
      end;


    Если размер данных не превышает 1 кБайт, sendto отрабатывает "мгновенно" c любыми адресами(локальными, глобальными).
    Если больше, начинаются варианты:
    1. адрес локальный, несуществующий, sendto некоторое время "думает" и завершается с WSAGetLastError=00.
    2. адрес доставки локальный, реально существует, но отсуствует в arp-таблице, SendTo виснет надооооооооооооооооолго, и когда уже ничего вообще от неё не ждёшь, отбивается с WSAGetLastError=10004(Операция блокирования прервана вызовом WSACancelBlockingCall)
    Делаю Ctrl+F2(или дожидаюсь, пока sendto "отпустит"), запускаю повторно - операция выполнена успешно.
    Cмотрю arp -a - комп в таблице.

    Почему так происходит? Просветите, пожалуйста. В гугле ответа не нашёл.
    Спасибо.
    Сообщение отредактировано: Prince -
      У протокола есть ограничения. в педивикии про это упоминается.
      https://ru.wikipedia.org/wiki/UDP#.D0.94.D0....BB.D0.BA.D0.B8
        Какое именно ограничение вызывает описанное поведения sendto?
          Цитата Prince @
          1. адрес локальный, несуществующий, sendto некоторое время "думает" и завершается с WSAGetLastError=00.

          К сожалению, такого кода sendto() не может выдать.
          Посмотрите MSDN о кодах ошибки sendto().
          Принципиально - sendto() пошлет UDP-пакет по любому адресу. потому что эта функция лишь копирует датаграмму в буфер передачи сокета. Далее на локальном компе формируется IP-пакет с указанным IP-адресом и формируется ARP-запрос на получение МАС-адреса компа-получателя - например сервера DNS. Если получатель в локальной сети, и его IP фейковый, то дальнейшие действия как вы правильно написали упираются в получение записи из арп таблицы. Если такой записи нет, то модуль арп пытается несколько раз с увеличенным таймаутом послать очередной широковещательный запрос WHO HAS. Это может длиться например до 29-ти секунд(BSD) или более (зависит от ОС), после чего модуль говорит о том, что он не может найти такой МАС.Как эта ошибка будет зафиксирована на пользовательском уровне - это уже дело взаимодействия уровней.
          Вот примерно так.
          Так что подвисание при отсутствии нужной записи в арп-таблице вполне очевидно.
            Цитата
            К сожалению, такого кода sendto() не может выдать.

            Какое значение должна возвращать WSAGetLastError после нормального заверршение sendto? :unsure:
            Цитата
            Если получатель в локальной сети, и его IP фейковый, то дальнейшие действия как вы правильно написали упираются в получение записи из арп таблицы. Если такой записи нет, то модуль арп пытается несколько раз с увеличенным таймаутом послать очередной широковещательный запрос WHO HAS. Это может длиться например до 29-ти секунд(BSD) или более (зависит от ОС), после чего модуль говорит о том, что он не может найти такой МАС.

            Если фейковый, то sendto подвисает буквально на секунду-другую. А вот если реальный, и в arp-таблице, на момент вызова sendto, его нет, sendto виснет наглухо...
            Да, и всё это усугубляется зависимостью от размера данных. Я не понимаю.
            Сообщение отредактировано: Prince -
              Цитата Prince @
              Какое значение должна возвращать WSAGetLastError после нормального заверршение sendto? :unsure:

              Цитата
              If no error occurs, sendto returns the total number of bytes sent, which can be less than the number indicated by len. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

              Т.е.при нормальном завершении возвращает обычное целое число, которое обозначает, сколько байтов она реально скопировала в буфер передачи сокета.
              Кстати, а сколько вы отсылаете вот этим вызовом?
              SendTo(FSocket, Data[0], Length(Data), 0, FSockAddr, SizeOf(FSockAddr));
              Ноль что ли? Или один первый байт?
              Т.е. что означает Data[0], если
              data:array of byte;
              setlength(data,3000);
              Если один - то Length(Data) как то...
              Может я в паскале и не очень силен, но тут мне что то непонятно.

              Цитата Prince @
              А вот если реальный, и в arp-таблице, на момент вызова sendto, его нет, sendto виснет наглухо...

              По идее так не должно быть. Ведь UDP к ARP не имеет никакого отношения.
              Цитата Prince @
              А вот если реальный, и в arp-таблице, на момент вызова sendto, его нет, sendto виснет наглухо...

              Что значит - наглухо? На всю жизнь???
              Есть правда и такой вариант - дельфовые сетевые компоненты порой ведут себя глючно, может это один из глюков - "нет в арп - не буду работать"??? :wacko:

              Цитата Prince @
              Да, и всё это усугубляется зависимостью от размера данных.

              Структура WSADATA при WSAStartup возвращает поле MAX UDP Datagram, в которой записан максимальный размер udp-пакета допускаемый данной системой. Гляньте это поле.
              Сообщение отредактировано: Oleg2004 -
                Похоже, это у sendto аллергия на касперский NDIS Filter.
                  Цитата Prince @
                  Похоже, это у sendto аллергия на касперский NDIS Filter.

                  Аааааааааааааааа!!!
                  Мого быть...про файер я как-то не подумал...
                  Про это
                  что означает Data[0]
                  Я так понял, вы указали только адрес начала массива.
                  Тогда все ок.
                  Сообщение отредактировано: Oleg2004 -
                    Цитата
                    Т.е.при нормальном завершении возвращает обычное целое число, которое обозначает, сколько байтов она реально скопировала в буфер передачи сокета.

                    Мне кажется, вы меня не поняли. sendto в случае нормального завершения возвращает количество байт, при этом WSAGetLastError=0(по крайней мере, у меня так). :-?
                    Цитата
                    SendTo(FSocket, Data[0], Length(Data), 0, FSockAddr, SizeOf(FSockAddr));

                    Начиная с 0-го элемента, размер равен размеру массива (3000 байт).
                    Цитата
                    По идее так не должно быть. Ведь UDP к ARP не имеет никакого отношения.

                    Вот я и не понял. Всюду пишут, что UDP не требует установления соединения, хоть на деревню дедушке отправь - всё равно улетит. И тут такое.
                    Цитата
                    Что значит - наглухо? На всю жизнь???

                    На ооооочень долго, как минимум. Потом socket_error с WSAGetLastError=10004(Операция блокирования прервана вызовом WSACancelBlockingCall).
                    Было, что я так и не смог дождаться WSACancelBlockingCall. Т.е., можно сказать, на всю жизнь.
                    Цитата
                    Структура WSADATA при WSAStartup возвращает поле MAX UDP Datagram, в которой записан максимальный размер udp-пакета допускаемый данной системой. Гляньте это поле.

                    iMaxUpdDg = 65467
                    Сообщение отредактировано: Prince -
                      Цитата Prince @
                      Мне кажется, вы меня не поняли. sendto в случае нормального завершения возвращает количество байт, при этом WSAGetLastError=0(по крайней мере, у меня так). :-?

                      Да нет все понятно, за исключением "завершается с WSAGetLastError=00."
                      Вот про два нуля мне и не было понятно :)
                      Цитата Prince @
                      На ооооочень долго, как минимум. Потом socket_error с WSAGetLastError=10004(Операция блокирования прервана вызовом WSACancelBlockingCall).
                      Было, что я так и не смог дождаться WSACancelBlockingCall. Т.е., можно сказать, на всю жизнь.

                      Ну что тут можно сказать...
                      Во первых, по моему мнению, sendto()нельзя причислить к блокирующим функциям. Операция копирования из буфера приложения в буфер отправки сокета выполняется ровно столько, сколько затрачивает времени ассемблерный код. Единственный вариант, когда эта функция может реально блокировать - это отсутствие места в буфере отправки.
                      Поэтому я бы советовал такое - определить размер буфера отправки сокета, и при необходимости тупо его увеличить.
                      Как может не оказаться места в буфере?
                      Один вариант - сеть перегружена и карточка не смогла отправить данные, а тут опять sendto()/ В вашем варианте этого вроде бы не должно быть. Или задержка арп-ответа - может дать такой эффект. Или глюк дельфи...
                      Фиг его знает.
                      Во всяком случае я бы увеличил размер буфера.
                        Саппорт касперского:
                        Цитата
                        Не рекомендуется отключать использование Kaspersky Anti-Virus NDIS Filter снятием флага в окне свойств Local Area Connection. NDIS Filter переходит в такой режим работы, который может привести к некорректной работе всей операционной системы (например, к падению в "синий экран").

                        А я уже такую операцию проделал, потом вернул галочку на место. И теперь не могу воспроизвести глючную ситуацию!
                        То ли касперский стал работать как нужно, то ли я его сломал и он больше пакеты не перехватывает. <_<

                        Цитата
                        Поэтому я бы советовал такое - определить размер буфера отправки сокета, и при необходимости тупо его увеличить.

                        8192.

                        Добавлено
                        Вопрос как бы и решён и не решён. <_<
                        Сообщение отредактировано: Prince -
                          Понятно.
                          Уже как бы поздновато, обсудим позже... :)
                            Oleg2004
                            Цитата Oleg2004 @
                            SendTo(FSocket, Data[0], Length(Data), 0, FSockAddr, SizeOf(FSockAddr));
                            Ноль что ли? Или один первый байт?

                            В данном случае передается как ссылка на нулевой элемент. Это такая особенность паскаля, неявная передача по ссылке.


                            Prince
                            Вроде подобные симтомы были от файрвола касперского. Что-то он не корректно большьшие максимальные пакеты UDP обрабатывал. Предлагаю ограничить размер пакета 1434 байт и пробовать увеличивать пока не пойдут сбои или уменьшать.

                            Цитата Oleg2004 @
                            По идее так не должно быть. Ведь UDP к ARP не имеет никакого отношения.

                            Я уже ничему не удивляюсь. Для определения интерфейса с которого отправлять есть 4 механизма.
                            Метка приоритета, IP адрес и маска, ARP адрес, прочий способ.
                            На разных ОС и в разных железках оно работает по разному. Не говоря уже про межсетевойэкран(фаервол), который определяет маршрут пакета так как ему угодно.
                            Сообщение отредактировано: Pavia -
                              Цитата Pavia @
                              Я уже ничему не удивляюсь.

                              А я как раз таки постоянно удивляюсь - ну как это можно такое глюкавое выпускать???
                                Цитата
                                Вроде подобные симтомы были от файрвола касперского.

                                Вот я уже почти поверил, что это фильтр касперского виноват. Был.
                                Только у меня не кис, а антивирус.
                                Цитата
                                Предлагаю ограничить размер пакета 1434 байт и пробовать увеличивать пока не пойдут сбои или уменьшать.

                                Да уже всё, не могу воспроизвести сбой. Я на него столько времени угрохал. :wall: Может, завтра снова появится(с надеждой).
                                Было так: отправляю больше 1 кБайта(>1024 байт) - глюк. Если <=1024) - всё нормально.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0.0957 ]   [ 15 queries used ]   [ Generated: 25.08.26, 14:57 GMT ]