![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Проблемы при работе с Indy [D7, WinXP]
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.
Cyrax (2006-10-18 12:45:00) [21]Если ты причастен к его разработке, то ты всегда волен реализовать сервер так как тебе нужно.
Ну, предположим, так...
И какой из всего этого можно сделать вывод ?
з.ы. Видно, вы никогда не отправляли групповые TCP-пакеты...
Сергей М. (2006-10-18 12:33:00) [22]Да по барабану, на основе чего он там сейчас работает)
Если ты причастен к его разработке, то ты всегдаволен реализовать сервер так как тебе нужно.
Cyrax (2006-10-18 12:11:00) [23]Допустим, сервер работает на основе сторонних модулей (а не моего), не реализующих поддержку UDP...
Сергей М. (2006-10-18 11:52:00) [24]
> сервер может не поддерживать UDP
Что мешает реализовать в нем такую поддержку ?
Cyrax (2006-10-18 11:31:00) [25]Так извращеннее всего...
Ну, модуль у меня TCP-шный, кроме того, сервер может не поддерживать UDP...
Сергей М. (2006-10-18 11:25:00) [26]
> нужно максимально быстро найти сервер
> пользуясь только протоколом TCP/IP...
Это что, блажь ? Чем это обосновано ? Чем UDP помешал ?
Cyrax (2006-10-18 11:20:00) [27]Тут такая задача подвернулась. Надо извратиться и отправить широковещательный TCP-пакет для поиска сервера...
А вообще, нужно максимально быстро найти сервер (с неизвестным IP-адресом и неизвестным портом из известных диапазонов), пользуясь только протоколом TCP/IP...
Verg (2006-10-17 09:49:00) [28]
> Отсоединяюсь я методом Disconnect (пробовал и DisconnectSocket).
> При каждом очередном соединении клиента ОС выделяет ему
> новый порт. Если же задать порт клиента самому, то при повторном
> соединении возникает ошибка - порт то остался занятым...
>
> С TIdTCPServer такой проблемы не возникает.
>
> Что самое интересное, пример работы с TIdTCPServer и TIdTCPClient
> (IdTCPDemo), скачанный с инета, показывает те же результаты.
>
> На форумах читал, как обсуждали глюки некоторых компонентов
> Indy.
> Так вот, может это очередной глюк? Или отсоединяться (клиенту)
> нужно как то по-другому?
Это не от Indy.
см. http://book.itep.ru/4/44/tcp_443.htm
Состояние соединения TIME_WAIT.
Сергей М. (2006-10-17 08:33:00) [29]
> Где в справке указано, что... Вообще, где в справке хоть
> что-то описано об этих уровнях
Не ту справку ты куришь.
Справка к индейским компонентам в основном ориентированы на батонокидателей, которые не заморачиваются низкоуровневым программированием гнезд.
Следует курить как минимум справку MS Windows Sockets 2 Reference (поставляется штатно), где сказано:
level = IPPROTO_TCP*
TCP_NODELAY BOOL Disables the Nagle algorithm for send coalescing.
* - included for backward compatibility with Windows Sockets 1.1
BSD options not supported for setsockopt are:
...
TCP_NODELAY
The TCP_NODELAY option is specific to TCP/IP service providers. Enabling the TCP_NODELAY option disables the TCP Nagle Algorithm (and vice versa). The Nagle algorithm (described in RFC 896) is very effective in reducing the number of small packets sent by a host by essentially buffering send data if there is unacknowledged data already "in flight" or until a full-size packet can be sent ....
А еще лучше искать инф-цию в первоисточнике - MSDN.
> Везде одна и та же ошибка
В смысле "Access violation at address XXXXXXXX...." ?
И чему равен XXXXXXXX ? Входит ли XXXXXXXX в диапазон адресов, распределенных под образ твоегомодуля в ВАП процесса ?
Если входит, то в [117] - вранье, либо ты не умеешь пользоваться встроенным отладчиком.
Если не входит, то обязательновходит в диапазон адресов для образа какого-либо иного модуля, и эта инф-ция (т.е. какого конкретно модуля) не менее важна при поиске причин отказа.
Ketmar (2006-10-16 23:35:00) [30]>[126] Cyrax(c) 16-Oct-2006, 23:15
>Ну вот, самому ведь приходилось, а говоришь код пиши
>правильно, буфера не трогай...
я это делал "из спортивного интереса". в реальных задачах не приходилось ни разу.
Cyrax (2006-10-16 23:15:00) [31]Ketmar © (16.10.06 22:14) [125]
ну, я отключал.
Ну вот, самому ведь приходилось, а говоришь код пиши правильно, буфера не трогай... $\g
где-то на "королевстве" была статья...
паоищу.. Глядел какой-то форум по этой функции, но на C++ - на паскале не прокатывает...
Ketmar (2006-10-16 22:14:00) [32]>[124] Cyrax(c) 16-Oct-2006, 22:07
>Кто-нибудь отключал буферизацию TCP-пакетов с помощью
>SetSockOpt ?
ну, я отключал. только как -- убей, не помню. и вспоминать лениво. давно было. где-то на "королевстве" была статья по работе с сокетами, там в том числе и об этом сказано.
Cyrax (2006-10-16 22:07:00) [33]Ketmar © (15.10.06 23:19) [122]
жениться бы вам, барин... (ц)
Тогда останется один путь - повеситься...
Сейчас есть приоритеты и поважнее...
Сергей М. © (16.10.06 08:33) [123]
Кто такой Self в данном контексте ?
Ето наследник TIdTCPClient. Self я уже давно убрал. Он мне нужен был только чтоб добраться до SetSockOpt...
Нагель отключается на уровне Id_IPPROTO_TCP.
И на уровне Id_IPPROTO_TCP отключал, и на уровне... в общем, все уровни перепробовал... Везде одна и та же ошибка...
Справку-то когда читать наконец научимся ?
Где в справке указано, что... Вообще, где в справке хоть что-то описано об этих уровнях. Например, всё, что написано про Id_IPPROTO_TCP:
Id_IPPROTO_TCP = IPPROTO_TCP;
Unit
IdStackConsts
Description
Id_IPPROTO_TCP
И так про все константы, используемые в SetSockOpt...
_________________________________________________________________
Кто-нибудь отключал буферизацию TCP-пакетов с помощью SetSockOpt ?
Сергей М. (2006-10-16 08:33:00) [34]
> Cyrax © (15.10.06 19:15) [117]
> Self.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_TCP_NODELAY,
> Char(@Id_SO_False), SizeOf(Id_SO_False));
Кто такой Self в данном контексте ?
Нагель отключается на уровне Id_IPPROTO_TCP.
Справку-то когда читать наконец научимся ?
Ketmar (2006-10-15 23:19:00) [35]жениться бы вам, барин... (ц)
Cyrax (2006-10-15 23:10:00) [36]Задача никак не менялась.
Могу написать простейший автомат и реализовать его в своём модуле. Будет некоторая надстройка (реализованная только в моём модуле и не выходящая за его пределы) над прикладным протоколом (неизвестным в общем случае). Ещё подумаю...
Но это всё будет после того, как разберусь с текущим глюком с отключением буферизации... - это садомазо такое (похоже на ситуацию с языковой панелью, которую я всё-таки вытащил наружу)...
Ketmar (2006-10-15 21:26:00) [37]>[119] Cyrax(c) 15-Oct-2006, 20:09
>Если не поможет, буду отслеживать движение IP-пакетов и
>проводить всякие извращенские опыты...
ага. вместо чтобы написать простейший автомат... или по ходу обсуждения задача уже поменялась? лень перечитывать.
Cyrax (2006-10-15 20:09:00) [38]Ketmar © (15.10.06 19:39) [118]
вот же прикопался к буферизации...
хочу дело до ума довести... потому-что надо...
Кстати вопрос с "освобождением" порта ещё не решён. После того, как отключу буферизацию, буду всех вас доставать этим портом, который на самом деле освобождается, но типа ведёт себя так, как будто не освобождается...
И вообще у меня много нерешённых проблем, в т.ч. с глюками дебагера и Qt-плагина в Eclipse, но этот вопрос нек вам...
чую, когда отключишь, будет пост типа "отключил. не помогло. что дальше?"
Если не поможет, буду отслеживать движение IP-пакетов и проводить всякие извращенские опыты...
Ketmar (2006-10-15 19:39:00) [39]вот же прикопался к буферизации. чую, когда отключишь, будет пост типа "отключил. не помогло. что дальше?" %-)
Cyrax (2006-10-15 19:15:00) [40]При вводе адреса в моей программе, где произошла ошибка, ничего не происходит, окно "CPU" не открывается. Но по этому адресу мне делать нечего...
При вводе адреса, к которому произошло обращение (00000068), окно "СPU" открывается. Меня смущает этот адрес - 00000068...
const Id_SO_True: boolean = true;
Id_SO_False: boolean = false;
begin
Self.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_TCP_NODELAY, PChar(@Id_SO_False), SizeOf(Id_SO_False));
Ну так кто-нибудь отключал буферизацию или нет !?
Если да, то как...