Серверное Приложение С Tcpserver

borpavlenko

New Member
10.07.2008
2
0
#1
Здравствуйте, товарищи!

Пишу серверное многопользовательское приложение.
За основу взял пример отсюда http://softengines.ru/showthread.php?t=6863
На всякий случай продублирую код
Код:
…
type 
TMyClientThread = class(TClientSocketThread)
private
FCmd: String;
FData: String;
protected
procedure SyncProc; override;
end; 
…
procedure TMyClientThread. SyncProc;
begin
if FCmd = ‘CLR’ then
Form1.ListBox2.Clear
else
if FCmd =’TXT’ then
Form1.ListBox2.Items.Add(FData)
else 
if FCmd = ‘BYE’ then begin
Terminate;
Form1.ListBox1.Items.Add(‘Отключился:’+ ClientSocket.RemoteHost);
end;
else
if FCmd = ‘’ then
Form1.ListBox1.Items.Add(‘Подключился:’+ ClientSocket.RemoteHost);
end;

procedure TForm1.RormCreate(Sender: TObject);
begin
Caption:=’Сервер’;
ListBox1.Clear;
ListBox2.Clear;
TcpServer1.LocalPort :=’5050’;
TcpServer1.Active := ‘True’;
end;
procedure TForm1. TcpServer1GetThread(Sender: TObject;
var ClientSocketThread: TClientSocketThread);
begin
ClientSocketThread:= 
TMyClientThread.Create(TcpServer1.ServerSocketThread);
end;
procedure TForm1. TcpServer1Accept(Sender: TObject;
ClientSocket:TCustomIpClient);
begin
with (ClientSocket.GetThreadObject as TMyClientThread) do begin
FCmd:=’’;
ExecuteSyncProc;
while not Terminated do begin
FCmd:= ClientSocket.Receiveln;
if FCmd = ‘TXT’ then
FData:= ClientSocket.Receiveln;
if FCmd <> ‘’ then
ExecuteSyncProc;
end;
end;
end;
Итак, сам компонент TCPSocket ожидает подключения в отдельном потоке. При подключении клиента создается клиентский поток, в котором уже выполняется общение с клиентом.

Суть-вопросы.

1. Для закрытия соединения при получении команды 'BYE' используется вызов Terminate, который (как я понимаю) убивает клиентский поток. Правильно ли это? Не надо ли вызывать методы Disconnect, Close класса ClientSocket ? Проясните этот момент, кто знает.

2. Для меня сейчас более актуально разобраться в следующем:
если клиент не отправляет команду 'BYE', а просто вырубается, рвется соединение и т.п., то цикл while в TcpServer1Accept начинает бесконечно гонять по кругу. Т.е. получается, что сокет висит в каком-то неопределенном состоянии (пробовал определять эту ситуацию проверкой ClientSocket.Connected, но ничего не вышло, остается TRUE), пользовательский поток гоняет по кругу цикл, который уже ничего не сделает, хотя должен умереть.
Как правильно отследить и обработать эту ситуацию?

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

sinkopa

Well-Known Member
#2
Здравствуйте, товарищи!
Пишу серверное многопользовательское приложение.
За основу взял пример отсюда http://softengines.ru/showthread.php?t=6863

Суть-вопросы.

1. Для закрытия соединения при получении команды 'BYE' используется вызов Terminate, который (как я понимаю) убивает клиентский поток. Правильно ли это? Не надо ли вызывать методы Disconnect, Close класса ClientSocket ? Проясните этот момент, кто знает.
Не надо путать понятия Socket и поток обслуживающий Socket
Вызов Terminate всего лишь устанавливает свойство Terminated в True, тем самым сообщая потоку что ему пора вывалиться их цикла ожидания и "тихо", корректно помереть.
Сам поток ничего не знает ни про Disconnect, Close ни про класс ClientSocket. Ему "по барабану" в результате какого действия ему скажут "умри"... :)
2. Для меня сейчас более актуально разобраться в следующем:
если клиент не отправляет команду 'BYE', а просто вырубается, рвется соединение и т.п., то цикл while в TcpServer1Accept начинает бесконечно гонять по кругу. Т.е. получается, что сокет висит в каком-то неопределенном состоянии (пробовал определять эту ситуацию проверкой ClientSocket.Connected, но ничего не вышло, остается TRUE), пользовательский поток гоняет по кругу цикл, который уже ничего не сделает, хотя должен умереть.
Как правильно отследить и обработать эту ситуацию?
Конечно он будет крутиться... откуда бы ему узнать что какой то там клиент, (на другом конце света), не просто задумался на время... а взял и помер не успев положить трубку на рычаг телефона?... :)
Вы правильно поняли суть проблемы... тем самым вплотную приблизились к пониманию понятия "протокол сетевого обмена информацией"... :)
В той реализации сетевого общения которую Вы представили, я лично вижу только одну возможность.
1. Вы устанавливаете (добавляете к существующим) комаду типа 'Я ЕЩЕ ЖИВ' и с оговоренной (с сервером) периодичностью отправляете ее серверу, в то время пока сокет ваш не занят другими данными...
2. Сервер (зная максимально допустимое время простоя клиента) самостоятельно вырубает клиентский поток если за указанный промежуток времени от клиента не поступило никаких команд.
Код:
	while not Terminated do
begin
FCmd:= ClientSocket.Receiveln;

if (FCmd = 'WaitMe') then
ClientIDLCount := 1000000
else if (FCmd = '') then
begin
Dec(ClientIDLCount);
if (ClientIDLCount < 1) then
FCmd:= 'BYE';
end;

if (FCmd = 'TXT') then
FData:= ClientSocket.Receiveln;

if (FCmd <> '') then
ExecuteSyncProc;
end;
Где-то так в общем... Ну или организуйте встречный сокет канал, чтобы сервер сам мог спрашивать у клиента : "эй парень? ты жив еще?" :)
В общем, научите правильно закрывать соединения со стороны сервера во всех случаях. Заранее спасибо.
Давайте я Вам лучше ссылку дам http://delphiworld.narod.ru/_all_articles_.html
Читайте раздел Сокеты (27 интересных примеров и статей)