Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2008.07.06;
Скачать: [xml.tar.bz2];

Вниз

Глюк компонента TIdUDPServer в 10м Indy? Проверьте ктонибудь.   Найти похожие ветки 

 
sniknik ©   (2007-09-14 23:48) [0]

Сделал небольшие изменения в старой, рабочей проге, с использованием 9х Indy, а с того времени уже поставил 10е... и словил глюк...
Вот интересно это только у меня так, возможно я чтото не учитываю (новые настройки например), или это глюк самого Indy?

Код проги приводить не буду, вместо этого выделил глюк в отдельный тест-пример (ниже), все задано в рантайме, и в одном месте, чтобы было нагляднее, на самом деле это в разных программах (и клиентская часть не моя), интересует серверная часть.

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IdBaseComponent, IdComponent, IdUDPBase, IdUDPServer, IdGlobal,
 IdSocketHandle, StdCtrls, IdUDPClient;

type
 TForm1 = class(TForm)
   Memo1: TMemo;
   Button1: TButton;
   Button2: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
   i1, i2: integer;
   UDPServer: TIdUDPServer;
   UDPClient: TIdUDPClient;
   procedure UDPRead(Sender: TObject; AData: TBytes; ABinding: TIdSocketHandle);
 public
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.UDPRead(Sender: TObject; AData: TBytes; ABinding: TIdSocketHandle);
begin
 Memo1.Lines.Add(PChar(AData));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 UDPServer:= TIdUDPServer.Create(self);
 with UDPServer.Bindings.Add do begin
   IP  := "0.0.0.0";
   Port:= 2500;
 end;
 with UDPServer.Bindings.Add do begin
   IP  := "0.0.0.0";
   Port:= 2501;
 end;
 UDPServer.OnUDPRead:= UDPRead;
 UDPServer.Active:= true;

 UDPClient:= TIdUDPClient.Create(self);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Inc(i1);
 UDPClient.Send("127.0.0.1", 2500, "2500 "+IntToStr(i1));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Inc(i2);
 UDPClient.Send("127.0.0.1", 2501, "2501 "+IntToStr(i2));
end;

end.


Как видно для прослушки устанавливаются 2 порта (минимум для глюка, больше будет тоже, а 1 нормально работает).
Выражается в том, что сервер не получает второе сообщение если если посылать два и более подряд на один порт. Т.е. его "клинит", "расклинивается" нажатием на другую кнопку (посылкой на другой порт) но тогда начинает задваиваться с первым... но через какоето время если жать опять только один и его "клинит".

В общем потыкайте в кнопки, в приведенной программке, адекватное поведение получается?
(indy должен быть 10, в 9ке это точно работало)
И можно ли это исправить? (В смысле сделать нормально, а не "залечкой" типа вместо одного 2(/3...n) компонента поставить с одним портом)


 
Сергей М. ©   (2007-09-16 11:12) [1]

Не знаю как в 10-ке, но и в 9-ке этот код нормально работать не должен, ибо обрабортчик OnUDPRead в 9-ке вызывается в дополнительном потоке.


 
sniknik ©   (2007-09-16 21:55) [2]

ThreadedEvent  по умолчанию false (не думаю что в 9ке отличается), и как видно в коде он не меняется, а обработчик OnUDPRead вызывается в UDPRead так
procedure TIdUDPListenerThread.Run;
...
     if FServer.ThreadedEvent then begin
       UDPRead;
     end else begin
       Synchronize(UDPRead);
     end;
...

Т.е. работать должен. (хотя это и не рабочий код а пример где убрано все для выделения глюка)
В 9-ке, посмотрел файл, данные строки те же

Но вообще это отступление от темы, не нравится игнорирование потока измени так
const
 WM_MEMO_ADD = WM_USER+101;

 ....
 procedure MemoAdd(var Mess: TMessage); message WM_MEMO_ADD;
 ....

procedure TForm1.MemoAdd(var Mess: TMessage);
var
 Buf: PChar;
begin
 Buf:= Pointer(Mess.WParam);
 Memo1.Lines.Add(Buf);
 FreeMem(Buf);
end;

procedure TForm1.UDPRead(Sender: TObject; AData: TBytes; ABinding: TIdSocketHandle);
var
 Ln: integer;
 Buf: PChar;
begin
 Ln:= Length(AData);
 GetMem(Buf, Ln);
 Move(AData[0], Buf^, Ln);
 Buf[Ln]:= #0;
 PostMessage(Handle, WM_MEMO_ADD, integer(Buf), 0);
end;


Это ничего(в смысле описанного глюка) не меняет.


 
sniknik ©   (2007-09-16 21:59) [3]

Сорри, надо заменить
GetMem(Buf, Ln+1);


 
Сергей М. ©   (2007-09-17 08:34) [4]


> начинает задваиваться


Это как понимать ?


 
sniknik ©   (2007-09-17 09:04) [5]

> Это как понимать ?
Код модуля с ошибкой выложен весь, проше всего скомпилить в программу и посмотреть... (в общем то результат такого "посмотреть" мне и нужен, убедиться, что это не только у меня так)

Результат работы программы
2500 1  //первой нажатие на первую кнопку, несколько последующих до "клина" нет реакции

2501 1 //нажатие на вторую кнопку
2500 2


2501 2 //еще раз на нее же
2500 3

2501 3 //еще, и тд.
2500 4


2501 4
2500 5

2501 5 //"клин" второй кнопки
2500 6


2501 6 //меняем кнопку на первую, продолжается тоже самое для нее до ее "клина"
2500 7
2501 7
2500 8
2501 8
2500 9
2501 9
2500 10
2501 10
2500 11
2501 11
2500 12
2501 12
2500 13
2501 13
2500 14

"клин" кнопки, это не то что она вдруг "задизейблилась", это то, что сервер почемуто не отдает принятое сразу. Т.к. очевидно что пакет всетаки получил, а отдает порциями вместе с пакетом второго порта.


 
Сергей М. ©   (2007-09-17 10:07) [6]


> sniknik ©   (17.09.07 09:04) [5]


Попробовать не могу, у меня 9-ка ..


 
umbra ©   (2007-09-17 10:50) [7]

если нажимать кнопки по очереди, все работает как ожидается, если нет - как описано в сабже.


 
sniknik ©   (2007-09-17 11:20) [8]

> Попробовать не могу, у меня 9-ка ..
в 9-ке работало. но не работал протокол https (в другой прграмме), может не совсем не работал, но какие то проблемы были, не помню, что и заставило поставить 10й (https сразу заработал), а это вот "выплыло" при каком то мелком исправлении (в caption лейбела орфографическую ошибку сделал ;)) и перекомпиляции (хорошо не отослал замену, сначала проверил и заметил... пришлось в старом ресхакером строку поменять и отослать, но это временно, а вдруг еще что понадобиться поменять, где ресхакером не обойдешся?).

umbra ©   (17.09.07 10:50) [7]
т.е. у тебя также? ок.
"по очереди" пакеты не приходят увы. ;(

ладно, будет время придётся в исходниках "поковыряться".


 
Slym ©   (2007-09-17 12:52) [9]

sniknik ©   (17.09.07 11:20) [8]
не проще 2 сервер сокета иметь?


 
umbra ©   (2007-09-17 13:47) [10]


> не проще 2 сервер сокета иметь?
>

похоже, именно в этом и дело. Из исходников следует, что для UDP сервера создается 1 слушающий поток, который в цикле проверяет все привязанные адреса и порты, вызывая на каждом RecvFrom. Если есть две привязки и на первую приходит пакет (нажата Button1), то сведения о нем попадают в мемо, а затем слушающий сокет блокируется на второй привязке и остается блокированным до нажатия второй кнопки. Если сначала нажать Button2, то в мемо ничего не появится до нажатия Button1, т.к. слушающий сокет блокирован на первой привязке. В 9-й инди, скорее всего, на каждую привязку создавался отдельный поток. Почему в 10-й сделали иначе - неясно.


 
sniknik ©   (2007-09-17 15:26) [11]

> не проще 2 сервер сокета иметь?
Ну их вообще то не 2 бывает, а ~ от 1 до 30. Не знаю, реализовать массив то просто, но вот будет ли это правильно... (теперь после [10], если там действительно 1 поток на все, слоняюсь к мысли что так правильней т.к., имхо, должен быть поток на каждую прослушку)


 
Сергей М. ©   (2007-09-17 15:31) [12]


> должен быть поток на каждую прослушку


Необязательно.
Можно организовать и в одном потоке с использованием таймаута в select"е.
Но вот почему индейцы это у себя не организовали (коль скоро там один-единственный слушающий поток) - то для меня загадка.


 
umbra ©   (2007-09-17 16:26) [13]


> Можно организовать и в одном потоке с использованием таймаута
> в select"е.

Я присмотрелся, и таки да, есть там Select(0, AReadSet, nil, nil, ATimeout). Тогда вопрос - почему это не срабатывает? И почему срабатывало в 9-й?


 
Сергей М. ©   (2007-09-17 16:31) [14]


> почему это не срабатывает?


Надо смотреть код листенер-треда ..

Похоже что параметр ATimeout некорректен, точнее его значение при вызове берется не то что нужно или не оттуда откуда нужно ..


 
DVM ©   (2007-09-17 16:51) [15]


> Сергей М. ©   (16.09.07 11:12) [1]
> Не знаю как в 10-ке, но и в 9-ке этот код нормально работать
> не должен, ибо обрабортчик OnUDPRead в 9-ке вызывается в
> дополнительном потоке.

С чего вы взяли, что в дополнительном?


 
Сергей М. ©   (2007-09-17 16:57) [16]


> DVM ©   (17.09.07 16:51) [15]


На сию мысль навело название класса TIdListenerThread.


 
umbra ©   (2007-09-18 10:52) [17]

нашел засаду!

в модуле IdUDPServer.pas есть метод TIdUDPListenerThread.Run. Жирным выделены мои исправления, подчеркнутые комментарии - то, что было раньше. Протестировал на сабжевом коде - работает нормально, как и ожидается.

procedure TIdUDPListenerThread.Run;
var
 PeerIP: string;
 i, PeerPort, ByteCount: Integer;
 ReadableFDSet: TIdSocketList;
begin
ReadableFDSet := nil;  
 try

 // FReadList.SelectRead(AcceptWait);
 if FReadList.SelectReadList(ReadableFDSet, AcceptWait) then
//    for i := 0 to FReadList.Count - 1 do try
   for i := 0 to ReadableFDSet.Count - 1 do try
     // Doublecheck to see if we"ve been stopped    {Do not Localize}
     // Depending on timing - may not reach here if it is in ancestor run when thread is stopped
     if not Stopped then begin
//        FIncomingData := //FServer.Bindings.BindingByHandle(TIdStackSocketHandle(ReadableFDSet[i]));
       FIncomingData := FServer.Bindings.BindingByHandle(TIdStackSocketHandle(ReadableFDSet[i]));
       SetLength(FBuffer,FBufferSize);
       ByteCount := GStack.ReceiveFrom(FIncomingData.Handle,FBuffer,PeerIP,PeerPort,FIncomingData.IP Version );
       SetLength(FBuffer,ByteCount);
       FIncomingData.SetPeer(PeerIP, PeerPort,FIncomingData.IPVersion);
       if FServer.ThreadedEvent then begin
         UDPRead;
       end else begin
         Synchronize(UDPRead);
       end;
     end;
   except
     // exceptions should be ignored so that other clients can be served in case of a DOS attack
     on E : Exception do
       begin
         FCurrentException := E.Message;
         FCurrentExceptionClass := E.ClassType;
         if FServer.ThreadedEvent then begin
           UDPException;
         end else begin
           Synchronize(UDPException);
       end;
     end;
   end;
 finally
   ReadableFDSet.Free;
 end;
end;


 
umbra ©   (2007-09-18 10:54) [18]

правда смотрел последний снэпшот инди - там в TIdUDPServer для каждой привязк создается отдельный поток. Чем-то их select не устроил.


 
Сергей М. ©   (2007-09-18 11:14) [19]


> ReadableFDSet := nil;  


А эт зачем ?
Для пущей уверенности что ли ?)


 
umbra ©   (2007-09-18 11:21) [20]


> А эт зачем ?

в методе SelectReadList(ReadableFDSet, AcceptWait) список сокетов создается только если есть готовые к чтению. А поскольку Free происходт в finally, то немного уверенности не помешает :)


 
Сергей М. ©   (2007-09-18 11:23) [21]

А-а-а ..

ну тады ой)


 
sniknik ©   (2007-09-18 16:17) [22]

> нашел засаду!
Спасибо! :о)
Проверю, и заменю.

> там в TIdUDPServer для каждой привязк создается отдельный поток. Чем-то их select не устроил.
чисто интуитивно (объяснить не смогу) мне тоже кажется на каждую нужен отдельный поток... (зря что ли многопроцессорные компы и распараллеливание задач делают? :)


 
Сергей М. ©   (2007-09-18 16:39) [23]


> sniknik ©   (18.09.07 16:17) [22]


> зря что ли многопроцессорные компы и распараллеливание задач
> делают?


Не зря, думаю ...

Но, пожалуй, факт есть факт. И я склонен доверять результатам исследований  ув. Umbra (C)


 
sniknik ©   (2007-09-18 23:57) [24]

Кстати, изменение > umbra ©   (18.09.07 10:52) [17]
убрало еще одну неприятность, ошибку 10004 (прерванный вызов функции) при завершении программы в режиме разработки... кого это в 10-ке раздражало, пожалуйста готовый рецепт.

umbra ©   (18.09.07 10:52) [17]
Спасибо еще раз.



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2008.07.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.66 MB
Время: 0.095 c
3-1201682750
Tack
2008-01-30 11:45
2008.07.06
Прогресс выборки TADOQuery нерегулярный


15-1211181140
BlueDragon
2008-05-19 11:12
2008.07.06
ЕГЭ по информатике


2-1212663474
msg
2008-06-05 14:57
2008.07.06
обработка сообщений и наследование


2-1213015398
tytus
2008-06-09 16:43
2008.07.06
Как в TIdTelnet передать несколько комманд?


2-1212732220
кот
2008-06-06 10:03
2008.07.06
создание компонента





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский