Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Проблемы при работе с Indy [D7, WinXP]


Страницы:   1 2 3 4 5 6 7 8

Cyrax ©   (2006-08-26 18:46:00) 

Столкнулся я с такой проблемой. При использовании компонента TIdTCPClient при отсоединении от сервера не освобождается порт, занимаемый клиентом. Отсоединяюсь я методом Disconnect (пробовал и DisconnectSocket). При каждом очередном соединении клиента ОС выделяет ему новый порт. Если же задать порт клиента самому, то при повторном соединении возникает ошибка - порт то остался занятым...
С TIdTCPServer такой проблемы не возникает.

Что самое интересное, пример работы с TIdTCPServer и TIdTCPClient (IdTCPDemo), скачанный с инета, показывает те же результаты.
На форумах читал, как обсуждали глюки некоторых компонентов Indy.
Так вот, может это очередной глюк? Или отсоединяться (клиенту) нужно как то по-другому?

Правильно ли я понимаю механизм соединения клиента с сервером:
При попытке клиента соединиться с сервером (метод TIdPeerThread.Run на клиенте) на стороне сервера вначале создаётся поток для обслуживания этого клиента. Далее происходит попытка установления связи с клиентом. Событие OnExecute на сервере генерится именно после создания потока. При этом возможна ситуация, когда поток создан, а соединение не установлено. При последующем успешном соединении этого же клиента используется тот же поток.
Если я в чём-то ошибаюсь, прошу меня поправить.
Остаётся непонятно, почему в начале обработчика события OnExecute нужно ставить проверку "if not AThread.Terminated". Что, OnExecute генерится ещё и при завершении работы потока?

Есть у меня и другая проблема. При создании объекта TIdTCPServer присвоил полям OnConnect и OnDisconnect имена обработчиков. Напомню, что я пишу модуль, и никакого интерфейса, а тем более визуальных компонентов, нет. Т.е. все объекты я создаю и инициализирую сам... Так вот, в процессе соединения и отсоединения клиентов сервер генерирует события OnConnect и OnDisconnect соответственно и вызывает мои обработчики этих событий (по крайней мере, должен). С коннектом проблем нет. НО: событие OnDisconnect на сервере не генерируется при отсоединении клиента. Это событие генерируется только при завершении работы сервера (IdTCPServer.Active := false). Как я понял из help'а, оно должно генерироваться при каждом отсоединении клиента. Именно так и происходит в случае с сервером и клиентом, созданных визуально путём установки на форму компонентов (в этом случае все необходимые поля инициализируются нужным образом).

Может я не все нужные поля у IdTCPServer проинициализировал?
Вот моя инициализация клиента:

MaxLineLength := DataMax;        
MaxLineAction := maException;
ReadTimeout := 0;
BoundPort := 0;      // чтобы не возникало проблем с занятым портом
Host := '127.0.0.1'; //  пока для проверки
Port := 6002;          


Инициализация сервера:

DefaultPort     := port;
ThreadMgr      := TIdThreadMgrDefault.Create(id_component);
MaxConnections := ClientsMax;
ListenQueue    := 15;
OnExecute      := onexecute;
OnConnect      := onconnect; // мой обработчик
OnDisconnect  := ondisconnect;  // мой обработчик

_______________________
Дополнительные вопросы:
1. Как в винде посмотреть, какие порты в данный момент заняты и какими прогами (средствами винды, без программирования) + как принудительно освободить занятый порт (естественно, с завершением работы проги).
2. Свойство BoundIP клиента указывает IP компа, на котором можно его запускать ?

_______________________
Напоследок хочу узнать мнение тех, кто работал с Indy. Я пишу модуль, который будет обеспечивать связь клиентов с сервером по TCP/IP. Интерфейс представлен 4-мя функциями: инициализация, отправка, получение и завершение. Так вот, целесообразно ли использовать Indy для этих целей. Или проще напрямую работать с winsock, ведь Indy тоже работат через winsock.


Сергей М.   (2006-10-12 08:28:00) [41]


> Приходится рыться в инете.
> (ошибаюсь ?)
>


В дан.случае ошибаешься.
Эта функциональность специфична именно для Delphi IDEб и где еще как не в "родной" справке к IDE искать ее описание ?


> Не думаю, что из Search -> Find Error что-то толковое выйдет


Если ошибка именно в твоем коде, Search -> Find Error покажет тебе строчку, при выполнении которой произошла эта ошибка.


Cyrax   (2006-10-11 23:00:00) [42]

Справку читай, там все описано.

Уж не особо я полагаюсь на справку в Delphi...
Не особо ей доверяю...
Она не достаточно практична... Приходится рыться в инете.
(ошибаюсь ?)

Да и вообще, ассемблерным дебаггером в своё время активно пользовался.
В данном же случае меня интересует вопрос, касающийся ошибки...
Не думаю, что из Search -> Find Error что-то толковое выйдет. По-моему, достаточно вызова функции, которую я привёл выше, и парочку уточнений по моему модулю - и проблема будет решена (естественно, с помощью тех, кто работал с SetSockOpt)...


Сергей М.   (2006-10-11 17:43:00) [43]


> Cyrax ©   (11.10.06 17:31) [113]



> этот же сокет передатчика является и сокетом приёмника


"Приемнику" алгоритм Нанеля по барабану - этот алгоритм актуален лишь для передающей стороны.


> что я должен высмотреть в этих регистрах и дампах


Справку читай, там всеописано.


Cyrax   (2006-10-11 17:31:00) [44]

Надеюсь, вся эта катавасия у тебя происходит для гнезда-передатчика.

Да. Но этот же сокет передатчика является и сокетом приёмника - двусторонняя связь...

Вот по именно такому-то адресу и ищи ошибку.
см. Search -> Find Error ..

И что я должен высмотреть в этих регистрах и дампах...


Сергей М.   (2006-10-10 16:41:00) [45]


> по такому-то адресу


Вот по именно такому-то адресу и ищи ошибку.
см. Search -> Find Error ..

Надеюсь, вся эта катавасия у тебя происходит для гнезда-передатчика.


Cyrax   (2006-10-10 16:17:00) [46]

Не пашет:

const Id_SO_True: boolean = true;
     Id_SO_False: boolean = false;
begin
 Self.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_TCP_NODELAY, Char(@Id_SO_False), SizeOf(Id_SO_False));

Ошибка типа доступ по такому-то адресу...
Превым параметром ставил и Id_IPPROTO_TCP, и Id_IPPROTO_IP - то же самое...


Сергей М.   (2006-10-10 08:49:00) [47]


> До каких пор данные будут буферизоваться (до какого размера)


Это определяется алгоритмом Нагеля.

см. SetSockOpt(TCP_NODELAY)


Cyrax   (2006-10-10 08:07:00) [48]

И насчёт аккумуляции. До каких пор данные будут буферизоваться (до какого размера). И через какое время они начинают передаваться (если данных для буферизации больше не поступает)...


Cyrax   (2006-10-10 08:04:00) [49]

Ну, скажем, ковыряться в имплементе функции, обрабатывающей данные, не в моей компетенции. Я лишь вызываю её, когда приходят данные.
Функция работате правильно только тогда, когда вызывается только для одногоочередного прикладного пакета...


Ketmar   (2006-10-10 00:16:00) [50]

ну и "перепосылай". или сделай разборщик на простом автомате. а буфера -- не трогай. их не зря сделали. %-)


Cyrax   (2006-10-09 23:44:00) [51]

Ketmar ©   (09.10.06 23:32) [105]
а зачем? ну, положим, можно. но -- зачем? лучше код напиши правильно.

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


Ketmar   (2006-10-09 23:32:00) [52]

а зачем? ну, положим, можно. но -- зачем? лучше код напиши правильно.


Cyrax   (2006-10-09 23:21:00) [53]

И как ету аккумуляцию придушить ?


Ketmar   (2006-10-09 23:18:00) [54]

естественно, аккумулируется в буфере винсока.

Ethereal.


Cyrax   (2006-10-09 23:14:00) [55]

Что-то я забросил ветку...
Всё-таки половина вопросов была по сетям.

1. Сейчас у меня такая ситуация. Клиент отсылает запросы серверу. 1 запрос - 1 прикладной пакет (10-30 байтов). Сервер поддерживает как SPX/IPX-протокол, так и TCP/IP. На стороне сервера, как только приходят данные (хотя бы 1 байт), вызывается функция, их обрабатывающая. Проверка появления входных данных на серверном сокете происходит в отдельном потоке в цикле OnExecute, т.е. практически непрерывно. В случае с TCP/IP наблюдается ситуация, когда эта функция получает блок данных, соответствующий нескольким запросам клиента (*). Запросы же клиент отсылает отдельно, друг за другом, с некоторыми промежутками. В случае с SPX/IPX функция обрабатывает входные данные отдельными прикладными пакетами, т.е. ситуации, когда функция вызывается после прихода на серверный сокет нескольких клиентских прикладных пакетов, не наблюдается... (для SPX/IPX вызывается другая функция, но выполняющая практически те же действия)
Конечно, такие ситуации в общем случае вполне могут быть. Но настораживает то, что проверка в OnExecute происходит практически непрерывно и появление на серверном сокете очередного прикладного пакета должно быть сразу же зафиксировано и вызвана соответствующая функция, не дожидаясь, пока придёт ещё один прикладной пакет...

з.ы. не объединяются ли прикладные пакеты в один IP-пакет (по "вине" ОС) на клиентской стороне (стороне отправителя), поскольку прикладной пакет намного меньше среднего размера IP-пакета ?
И какие задержки могут привести к таким результатам (*)

Рассматриваемые ситуации с TCP и IPX полностью идентичны за исключением протокола...

2. Какие проги можете посоветовать для слежки за передачей IP-пакетов в винде. Желательно небольшие, чтоб можно было закачать по dialup'у...


Сергей М.   (2006-09-25 08:13:00) [56]

Дискуссия перешла в русло абстрактной "болтологии" на тему Паскаля, к сетям не имеющей отношения.

Формулируй свои вопросы отдельно в порядке их возникновения, с иллюстрациями в коде, и задавай их в конф-ции "Общие" или "Начинающим".


Cyrax   (2006-09-24 23:04:00) [57]

Сергей М. ©   (22.09.06 08:17) [99]
Ну и нафиг тогда тебе Инди со всеми его наворотами ?

Выходит, что нафиг...
В любом случае использовать Indy - не моя идея...
С другой стороны, отсутствие ориентации модуля на какой-либо протокол позволяет использовать его и на серверах, реализующую параллельную обработку клиентов. Для случая однопоточной обработки запросов использование этого модуля для подобных целей было бы невозможно...

11. Задача такова. Есть функция, которая принимает параметр типа PData.
Тип PData - какой-либо типизированный указатель, включая PChar.
При вызове функции в качестве фактического параметра передаётся PData(параметр_типа_Pointer). Но в случае с PChar генерируется статическая ошибка.
Как этого избежать ?  Почему PChar не приводится к Pointer ? Ведь это просто указатель на Char...
Дело в том, что среди возможных типов PData должен быть такой, чтобы доступ к элементам осуществлялся путём индексации (как в случае с PChar).

Обязан.
Потому что Destroy - виртуальный метод.

Тогда в своих деструкторах и конструкторах придётся самому вызывать деструкторы и конструкторы базового класса. Не очень то удобно...

Зачем серверу оператор ? Зачем оператору инф-ция об отверженном соединении ?

Допустим, сервер ведёт статистику, собирает и обрабатывает подобную (и не только) информацию. В любой момент можно быдет посмотреть, какие клиенты подключены, каким соединениям и когда было отказано и т.п.
Эта информация в любом случае не помешает...

>> Почему, когда ты в производном классе определяешь конструктор
>> и деструктор, при их вызове (а вернее, до и после, соответственно)
>> автоматически не вызываются конструкторы и деструкторы базового
>> класса ?
>Потому что у тебя ошибка в декларации/реализации/использовании
>конструктора и деструктора "производного" класса (*)

Я так не думаю...
>Ну тогда продолжай в том же духе.
А по моему, виртуальный метод не должен вызывать соответствующий метод базового класса...

Ты считаешь более простым объяснять тебе на пальцах неизвестно что и неизвестно почему происходящее в неизвестно каком коде ?

Дело в том, что для моделирования подобных ситуаций и представлении их в ярко выраженной форме потребуется потратить время на выдумывание такого кода. А в моей программе такие ситуации имеют место, но не в такой выраженной форме, чтобы только по коду можно было понять вопрос, да и части кода будут из разных мест программы + всё-равно потребуются письменные комментарии и разьяснения...

Те которые ждут акцептирования, т.е. потенциальные.

Почему слушающий поток не всегда может установить соединение и выделить клиенту отдельный поток, чтобы эти неразрешённые соединения накапливались...

4. Я унаследовал класс TTCPServer от TIdTCPServer. Далее пытаюсь проинициализировать обработчики событий:
inherited OnExecute      := onexecute;
nherited OnConnect      := onconnect;
inherited OnDisconnect   := ondisconnect;
Почему после наследования приходится приписывать к ним inherited.
Без них - ошибка.

Разыменование здесь нужно потому что переменная buffer объявлена именно как pointer, в то время как соотв.форм.параметр объявлен как нетипизированный и передаваемый по ссылке, а не по значению.

Вообще странно, что допускается разыменование нетипизированного указателя... В  C++ так делать нельзя...

12. Чем отличается тип Pointer от PVariant ?
13. И почему в сигнатуре методов пишут var имя_парам, а не var Vaiant. Т.е., фактически, пропускают тип параметра...


Сергей М.   (2006-09-22 08:17:00) [58]


> Вызов происходит в OnExecute соответствующего дочернего
> потока. При этом не допускается одновременных выполнений
> этой процедуры в нескольких потоках


Ну и нафиг тогда тебе Инди со всеми его наворотами ?
Индейский сервер изначальноподразумевает его использование для параллельнойобработки клиентских запросов.
Бзял бы обычный TServersocket или TTCPServer в режиме non-blocking - там события возбуждаются последовательно в одном-единственном потоке (например, в основном), и никакие заморочки с крит.секциями и прочей синхронизацией изобретать совершенно не нужно.


> synchronize(метод без парам). Но здесь возникает проблема:
>  процедура у меня с параметрами. Как ето самое уделать ?
>


Вот так:

TMyThread = class(TSomeThreadAncestor)
 ..
 FSomeParam: SomeType;
 ..
 procedure SomeSyncMethod;
 procedure SomeProc(SomeParam: SomeType);
end;

....

procedure TMyThread.SomeSyncMethod;
begin
  SomeProc(FSomeParam);
end;

...

FSomeParam := SomeValue;
Syncronize(SomeSyncMethod);


Cyrax   (2006-09-21 23:04:00) [59]

У меня механизм обработки входных данных следующий.
При инициализации клиента/сервера указывается процедура, которая будет вызываться, когда приходят данные. Вызов происходит в OnExecute соответствующего дочернего потока. При этом не допускается одновременных выполнений этой процедуры в нескольких потоках. Т.е. процедура должна полностью завершиться до начала следующего её вызова.
Имеем 2 варианта реализации вызова:
1. Делаем что-то типа lock'ов для чего-то...
2. Вызываем эту процедуру на выполнение в главный (первичный) поток с помощью synchronize(метод без парам). Но здесь возникает проблема: процедура у меня с параметрами. Как ето самое уделать ?

з.ыз. В случае 2 как раз и будет неявно организована очередь обработки запросов клиентов.


Сергей М.   (2006-09-20 14:08:00) [60]

По поводу Free ..

Если ты имеешь

TMyClass = class(...)
...
 destructor Destroy; override;
end;

TMyClass1 = class(TMyClass)
...
 destructor Destroy; override;
end;

TMyClass2 = class(TMyClass1)
...
 destructor Destroy; override;
end;

и создаешь объект класса TMyClass2

var MyObject: TMyClass;
MyObject := TMyClass 2.Create(..);

то при вызове MyObject.Free (или непосредственно MyObject.Destroy, что несущественно в дан.случае) самым первымбудет вызван метод TMyClass2.Destroy, поскольку этот метод перекрывает соотв.виртуальный метод предка, который точно так же перекрывает соотв.виртуальный метод своего предка, который... и так далее вплоть до TObject.Destroy, который собственно и объявлен как виртуальный метод, допускающий перекрытие (override) в своих потомках.


Страницы:   1 2 3 4 5 6 7 8

Наверх

Титульная страница Поиск, карта сайта Написать письмо