![]() |
| ||
|
|
Новости |
Поиск |
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.
Сергей М. (2006-09-05 11:23:00) [101]
> по-другому не получится.
Чтой-то вдруг ?
Cyrax (2006-09-05 10:12:00) [102]Согласен, но по-другому не получится...
Сергей М. (2006-09-05 10:06:00) [103]
> Нужно, чтобы эти функции сразу же возвращали результат (код
> ошибки), а для этого нужно подождать, пока выполниться операция
> чтения/записи в соответствующем потоке
При этом теряется весь смысл выполнения трансп.операций в доп.потоке.
> Остановился пока на варианте ждать в цикле, пока не завершится
> операция в потоке
Плохой вариант.
Cyrax (2006-09-05 09:37:00) [104]Всё, запарился... Не буду извращаться с Indy...
Сделаю в соответствии с идеологией Indy - все read/write в OnExecute и потоки в OnExecute. А то OnDisconnect достал...
Попутно соображаю по поводу того, как лучше организовать implement моих фунций чтения/записи. Нужно, чтобы эти функции сразу же возвращали результат (код ошибки), а для этого нужно подождать, пока выполниться операция чтения/записи в соответствующем потоке.
Остановился пока на варианте ждать в цикле, пока не завершится операция в потоке (с помощью флагов), а затем результат операции возвращать в главную программу...
Что касается порта клиента, то проверил OutPost'ом - порт все-таки освобождается... но ошибка выходит... Может, руки кривые...
Проверю ещё раз, где именно вылазит.
Сергей М. (2006-09-04 11:52:00) [105]
> Cyrax © (04.09.06 11:49) [51]
Возьми любую готовую утилитку (а-ля TCPView) да посмотри, занят ли порт 55559 после первого же дисконнекта клиента.
Cyrax (2006-09-04 11:49:00) [106]Глюко всяко случается...
Сергей М. (2006-09-04 11:47:00) [107]
> ты пробовал создать файлы с текстом из [32] и скомпилить
> ?
>
А нафига ?
Если ты утверждаешь, что именно строка IdTCPClient1.Connectприводит к отказу 10048, то сервер тут вообще ни при чем .. Зачем, спрашивается его компилить ?)
Cyrax (2006-09-04 11:42:00) [108]Что за полтергейст... средь бела дня...
А ты пробовал создать файлы с текстом из [32] и скомпилить ?
P.S. Знаю, страшно ломает...
Сергей М. (2006-09-04 11:35:00) [109]
> Cyrax © (04.09.06 11:28) [47]
Повторил твой код с максимальной точностью
object IdTCPClient1: TIdTCPClient
...
BoundPort = 55559
Host = '127.0.0.1'
...
end
Никаких "Address already in use" по-прежнему не наблюдаю, хоть без хоть с перезагрузкой клиента.
Cyrax (2006-09-04 11:28:00) [110]
Socket Error # 10048
Address already in use.
Даже после перезагрузки клиента и сервера при соединении клиента сразу же возникает это исключение (с тем же портом клиента)...
Сергей М. (2006-09-04 11:21:00) [111]
> я обрабатываю это исключение в обработчике OnDisconnect.
> А OnDisconnect у меня вызывается стандартным обработчиком
> этого исключения, даже если не отлавливать try...except'ом
Ну можно и так.
> мой пример, где как раз и использую твой код
Приведи дословно текст сообщения об исключении, возникающем при выполнении IdTCPClient1.Connect
Cyrax (2006-09-04 11:08:00) [112]Если возникло исключение, то оно будет при этом перехвачено и обработано тобой должным образом.
При чем здесь OnDisconnect ?
Хочу сказать? что я обрабатываю это исключение в обработчике OnDisconnect. А OnDisconnect у меня вызывается стандартным обработчиком этого исключения, даже если не отлавливать try...except'ом...
Протокол у меня подразумевает вначале обязательную передачу размера пакета (моего, прикладного протокола), а затем сами данные. Это нужно для того, чтобы считать из сокета не все данные (а там может находится и несколько прикладных пакетов и даже нецелое их число), а только один мой пакет сообщения.
> Как насчёт [32]?
А вообще, я имел ввиду освобождение порта клиентом...
Там мой пример, где как раз и использую твой код...
Сергей М. (2006-09-04 10:50:00) [113]
> Cyrax © (04.09.06 10:37) [43]
Ты ведь спросил, как оперативно отреагировать на отключение клиента в момент выполнения операций приема/передачи, я тебе и ответил - заключать вызов таких ф-ций в try..except
Если возникло исключение, то оно будет при этом перехвачено и обработано тобой должным образом.
При чем здесь OnDisconnect ?
> Как насчёт [32]?
А что насчет него ?
Я тебе уже сказал - нет никакой необходимости знать сколько байт доступно во входном потоке.
Сколько требуется прочитать в соответствии с твоим прикладным протоколом инф.обмена, столько и читай.
Cyrax (2006-09-04 10:37:00) [114]По поводу [23]:
Обработчик OnDisconnect вызывается стандартным обработчиком исключения (см. [31])... (по крайней мере, у меня так работало, без своих except'ов).
> см. [21]
Как насчёт [32]?
Сергей М. (2006-09-04 10:30:00) [115]
> мне нужно обнаружить отсоединение клиента как можно раньше,
> хотя бы в момент чтения/записи
см. [23]
> как насчёт освобождения порта ?
см. [21]
Cyrax (2006-09-04 10:27:00) [116]Сергей М. © (04.09.06 10:14) [39]
Вообще-то примерчик неплох... стоит попробовать.
А как насчёт освобождения порта ?
Сергей М. (2006-09-04 10:14:00) [117]with AThread do
while not Terminated and Connection.Connected and GetDataToSend(SomeDataToSend, SomeTimeout) do begin
try
Connection.SomeWriteMethod( ..SomeDataToSend ... );
except
Connection.Disconnect;
end;
end;
Cyrax (2006-09-04 10:14:00) [118]Ну и делай)
Ну а варианты то какие ? Например, с OnExecute.
в чем проблема-то
Да мне нужно обнаружить отсоединение клиента как можно раньше, хотя бы в момент чтения/записи. Но если это делать из первичного потока, то исключений, вызывающих OnDisconnecting, не вырабатывается...
Сергей М. (2006-09-04 10:07:00) [119]
> мне нужно это делать именно по запросу главной программы
Ну и делай) ... в чем проблема-то ? не знаешь как синхронизировать потоки или что ?
Cyrax (2006-09-04 10:05:00) [120]Чё то ничего не понял... трудно соображать поутру... наверное, от Ketmar'а пошло...
Если я буду передавать данные в OnExecute, то ... да мне нужно это делать именно по запросу главной программы...