![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Блокирующий tserversocket-не генерятся события отключения клиента [D5, Win2k]
Виноградов Алексей © (2003-10-21 20:42:00)
Люди, я с ума сойду ! Есть TServerSocket. Блокирующий. На форме -одна кнопка старта сервера. После подключения клиента для него аккуратно создается поток (видно в Диспетчере Задач), и сервер начинает с помощью метода READ сокетного потока MYSOCKET читать данные (байт) от клиента. Все работает (подключаюсь к серверу телнетом). Если закрыть телнет, то событие OnClientDisconnect не генерируется, и поток клиента остается неубитым. Если подключить n клиентов и потом закрsть, от них останатся n потоков. У меня вопрос - почему не генерятся события отключения,как сделать так, чтобы они генерились, и как узнать, что от сервера отключился клиент ? Вот мой код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, Inifiles, Grids, ComCtrls, ExtCtrls, Buttons;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
Start_Server: TBitBtn;
procedure FormActivate(Sender: TObject);
procedure ServerSocket1GetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
procedure ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure Start_ServerClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{Класс-наследник для процесса каждого клиента}
type
tmyserverthread = class(tserverclientthread)
public
procedure clientexecute; override;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
application.icon:=form1.icon; application.title:=form1.caption;
start_server.setfocus;
end;
{Это событие возникает, если серверному сокету нужно создать новый поток для соедининия с клиентом}
procedure TForm1.ServerSocket1GetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
{SocketThread - поток, использующийся единственным соединением}
{Отсылаем приветствие ...}
clientsocket.sendtext ("Hello! Have a nice day!" + #13 + #10);
socketthread:=tmyserverthread.create (true, clientsocket); {Создаем поток}
socketthread.priority:=tpnormal; {Устанавливаем приоритет}
socketthread.resume; {Запускаем поток в работу}
end;
procedure tmyserverthread.clientexecute;
{MySocket - это поток, предоставляющий сервисы, позволяющие читать (писать)в сокетное соединение}
var mysocket : twinsocketstream;
how_many_bytes : word;
one_letter : char;
begin
{Сокетный поток сообщит о таймауте, если через 5 секунд после запуска чтения или записи не будет принято никаких данных}
mysocket:=twinsocketstream.create(clientsocket, 5000);
try
while (not terminated) and (clientsocket.connected) do begin
how_many_bytes:=mysocket.read(one_letter,1);
end;
finally
mysocket.free; {Закрываем поток, предоставляющий сервисы}
if clientsocket.connected = true then clientsocket.close;
end;
end;
{От Сервера отключился Клиент}
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
showmessage("Еще один клиент отключился ...");
end;
{Пользователь запускает сервер}
procedure TForm1.Start_ServerClick(Sender: TObject);
begin
serversocket1.active:=true; {Запускаем сервер}
start_server.enabled:=false;
end;
end.
Виноградов Алексей (2003-10-22 10:12:00) [1]
Reindeer Moss Eater © (22.10.03 10:05) [6]
Я же сказал, что этим занимается TCP. Он сообщит экземпляру сервера что нет больше соединения. А сервер сгенерит OnDisconnect.
Да, спасибо, так работает ! Если сервер шлет подключенному клиенту некий символ, а потом закрывается телнет, происходит исключение пр записи ...
Reindeer Moss Eater (2003-10-22 10:06:00) [2]
Либо клиент на прикладном уровне должен сообщить о том, что уходит, а сервер обработать это сообщение
Reindeer Moss Eater (2003-10-22 10:05:00) [3]
Сама она не генерится ?
Я же сказал, что этим занимается TCP. Он сообщит экземпляру сервера что нет больше соединения. А сервер сгенерит OnDisconnect.
Либо с клиентской стороны должен прилететь fin пакет, говорящий, что клиент уходит.
Виноградов Алексей (2003-10-22 10:01:00) [4]
Reindeer Moss Eater
Нужно писать. Если сервер попробует писать и не получит квитанцию приема то спустя некоторое время решит что был дисконнект. (точнее это стек протокола решает а не сервер)
То есть я должен писать, а клиент (не телнет, или же телнет, если я успею на клаве нажимать кнопки) - слать квитанцию ? Сама она не генерится ?
Reindeer Moss Eater (2003-10-22 09:37:00) [5]
Как не ведет ?
А чтение в сокетном потоке ?!
Нужно писать. Если сервер попробует писать и не получит квитанцию приема то спустя некоторое время решит что был дисконнект. (точнее это стек протокола решает а не сервер)
Виноградов Алексей (2003-10-22 09:31:00) [6]
Reindeer Moss Eater © (22.10.03 08:44) [1]
Клиент по тихому закрыл соединение ничего не говоря серверу, сервер в свою очередь никакого обмена с клиентом не ведет.
Как не ведет ?
А чтение в сокетном потоке ?!
Digitman (2003-10-22 08:56:00) [7]
procedure tmyserverthread.clientexecute;
var mysocket : twinsocketstream;
how_many_bytes : word;
one_letter : char;
begin
try
mysocket:=twinsocketstream.create(clientsocket, 5000);
try
while (not Terminated) and (clientsocket.connected) do
try
how_many_bytes:=mysocket.read(one_letter,1);
// ... обрабатываем успешно полученные данные
except
// при чтении данных возникло исключение, например, по причине дисконнекта по инициативе клиента
// закроем гнездо
clientsocket.Close; // вот при выполнении этого метода и будет сгенерировано синхронное событие OnClientDisconnect()
raise;
end;
finally
mysocket.free;
end;
except
// .. здесь можно вести лог исключений, например, с пом. HandleException
end;
end;
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
// showmessage("Еще один клиент отключился ..."); // недопустимо !!! showmessage() - потоконебезопасный вызов
MsgBox(...); // если так необходимо вывести диал.окно с сообщением, то или MsgBox() или синхронизировать вызов showmessage() с пом. метода Synchronize()
end;
Reindeer Moss Eater (2003-10-22 08:44:00) [8]
Если закрыть телнет, то событие OnClientDisconnect не генерируется
А с какой стати оно должно генерироваться?
Клиент по тихому закрыл соединение ничего не говоря серверу, сервер в свою очередь никакого обмена с клиентом не ведет.
Откуда серверу узнать что клиента уже нет?