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

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

ClientSocket + TThread = ошибка при завершении программы [D7, WinXP]


Alex_C ©   (2009-03-24 09:27:00) 

В продолжении моей темы о работе телнет-сокета.
Чтоб работа телнет не тормозила работу основной программы, сокет был вынесен в отдельный тред.

собственно вот код:


constructor TTelnetThread.Create;
begin
 // Создаем сокет телнета
 TelnetSocket := TClientSocket.Create(nil);
 TelnetSocket.OnConnecting := ClientOnConnecting;
 TelnetSocket.OnConnect := ClientOnConnected;
 TelnetSocket.OnDisconnect := ClientOnDisconnected;
 TelnetSocket.OnRead := ClientOnRead;
 TelnetSocket.OnError := ClientOnError;
 inherited Create(false);
end;

destructor TTelnetThread.Destroy;
begin
 TelnetSocket.Free;
 inherited;
end;

procedure TTelnetThread.Execute;
begin
 FreeOnTerminate := True;
 try
   TelnetSocket.Host := NextHost;
   TelnetSocket.Port := NextPort;
   TelnetSocket.Service := 'telnet';
   TelnetSocket.Active := True;
   while TelnetSocket.Socket.Connected do
    Application.ProcessMessages;
 finally
   TelnetSocket.Socket.Close;
 end;
end;


Проблема в том, что если попытаться закрыть программу во время работы сокета велетает ошибка чтения по адресу 0000000.
Вопрос: как корректно завершить соединение с сокетом, а затем закрыть программу?


Alex_C   (2009-03-25 16:28:00) [1]


> Не совсем.


Ок! Понял - буду разбираться дальше!


Сергей М.   (2009-03-25 14:46:00) [2]


> правильно понимаю?


Не совсем.

1. Вызов ReceiveLength в блокирущем режиме не обязателен - логика его использования более уместна в неблок.режиме с асинхронными нотификациями (ClientType = ctNonBlocking)

2. Результат вызова ReceiveBuf следует интерпретировать след.образом:

< 0 - возникла неустранимая ошибка, связанная с невозможностью дальнейшей работы с данным соединением, например, кот Васька только что перегрыз пачкорд. Continueлишен смысла, следует закругляться.

= 0 - удаленный партнер по соединению корректно разорвал соединение по своей инициативе. Continueтут также лишен смысла, следует закругляться.

> 0 - из вх.очереди актуально выбрано Size байт, можно их обрабатывать, при этом соединение на этот моменьт может уже и не существовать, будучи разорванным по тем или иным причинам.


Alex_C   (2009-03-25 14:35:00) [3]

Поторопился.
Вот так правильно:

       while TelnetSocket.Socket.Connected do
       begin
         DataLength := TelnetSocket.Socket.ReceiveLength;
         if DataLength <= 0 then
           Continue;
         SetLength(Buf, DataLength);
         TelnetSocket.Socket.ReceiveBuf(Buf[0], DataLength);
         ReadDataFromTelnet(Buf, DataLength);
       end;


Alex_C   (2009-03-25 14:18:00) [4]

Ок! Спасибо!
С сокетами вообще мало дело имел, а в тредах вообще.
Разобрался!
правильно для бликирующего сокета будет так:


       DataLength := TelnetSocket.Socket.ReceiveLength;
       Buf := GetMemory(DataLength);
       while TelnetSocket.Socket.Connected do
       begin
         Size := TelnetSocket.Socket.ReceiveBuf(Buf, DataLength);
         if Size <= 0 then
           Continue;
         ReadDataFromTelnet(Buf, Size);
       end;


где ReadDataFromTelnet - альнейшая обработка полученных данных.
Я правильно понимаю?


Сергей М.   (2009-03-25 13:12:00) [5]


> Alex_C   (25.03.09 12:46) [8]
>
>


Обращение к VCL-объектам в доп.потоке небезопасно, а в большинсве случаев и недопустимо.


Palladin   (2009-03-25 13:04:00) [6]


> Пока есть соединение - ожидаем ответа. А как правильно?

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


> Чтоб работа телнет не тормозила работу основной программы

С каких фигов у тебя "работа телнет" тормозит основную программу если у тебя сокет не блокирующий, чего ты бредишь?  Зачем тебе отдельный поток? Воздух на самосвалах возишь?


> А почему б ему тут не стоять? Есть разница где его размещать
> - в Create или Execute?

А ты как думаешь? Execute уже в контексте созданного потока исполняется. Так наверное логичнее будет указать, что нужно разрушить объект в контексте создающего, а не создаваемого? Разве не логично?


> ВЕЗДЕ написано, что закрывать сокет надо именноTelnetSocket.
> Socket.Closeа неTelnetSocket.Free

Ну вот этого я не знаю, потому ничего не скажу. Может я и не прав.


Slym   (2009-03-25 13:04:00) [7]

Alex_C   (25.03.09 12:46) [8]
Пока есть соединение - ожидаем ответа. А как правильно?

правильно использовать боп поток при блокирующем режиме сокета (ClientType =  ctBlocking)
а у тебя ctNonBlocking
при ctBlocking не используютсясобытия типа:
TelnetSocket.OnConnecting
TelnetSocket.OnConnect
TelnetSocket.OnDisconnect
TelnetSocket.OnRead
TelnetSocket.OnError

пример работы в блокирующем режиме рассмотрен тут http://www.delphimaster.ru/cgi-bin/forum.pl?id=1227604925&n=4


Alex_C   (2009-03-25 12:46:00) [8]


> >    while TelnetSocket.Socket.Connected do     Application.
>
> > ProcessMessages;
>
> а вот это зачем?


Пока есть соединение - ожидаем ответа. А как правильно?


> >  FreeOnTerminate := True;
>
> а это какого фика в Execute делает?

А почему б ему тут не стоять? Есть разница где его размещать - в Create или Execute?


> >  finally    TelnetSocket.Socket.Close;  end;
>
> а это зачем в Execute? разве при TelnetSocket.Free он не
> закрывается?


ВЕЗДЕ написано, что закрывать сокет надо именно
TelnetSocket.Socket.Close
а не
TelnetSocket.Free


Palladin   (2009-03-25 10:44:00) [9]

... ах, он еще и неблокирующий... :)


Slym   (2009-03-25 10:22:00) [10]

Palladin ©   (24.03.09 10:25) [5]
+1000
Неблокирующий сокет в потоке :)
Alex_C   (24.03.09 9:27)
сокет был вынесен в отдельный тред

ничего не вынесено... поток ничем особым и полезным не занимается


Palladin   (2009-03-24 10:25:00) [11]

короче бред какой то...


Palladin   (2009-03-24 10:24:00) [12]


>  FreeOnTerminate := True;

а это какого фика в Execute делает?


Palladin   (2009-03-24 10:24:00) [13]


>  finally    TelnetSocket.Socket.Close;  end;

а это зачем в Execute? разве при TelnetSocket.Free он не закрывается?


Palladin   (2009-03-24 10:23:00) [14]


>    while TelnetSocket.Socket.Connected do     Application.
> ProcessMessages;

а вот это зачем?


Alex_C   (2009-03-24 10:18:00) [15]

В общем задача решена :)
Оказвается я перед закрытием программы делал вот что:



FormClose:

if Assigned(TelnetThread) then
begin
 TelnetThread.Disconnect; // Socket.Close
 TelnetThread.Free; // Тут ошибка и возникала, т.к. TelnetThread уже завершился!
end;


Наверх

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