Использование компонента TServerSocket

В Delphi документации по многопотоковому TServerSocket налито довольно много воды, и начинающему программисту сложно понять суть дела. Давайте попытаемся пролить немного света на этот раздел хелпа.
Совместимость: Delphi 3.x (или выше)
Вообще-то, создать многопотоковый сервер, который ожидает пришедшие сообщения на сокете довольно просто. В Delphi для этой цели достаточно использовать компонент TServerSocket.
Давайте рассмотрим структуру работы данного компонента:
* Добавляем TServerSocket в Вашу основную форму.
* Устанавливаем свойство Servertype в stThreadBlocking
* Создаём новый "unit" (показанный ниже) содержащий поток сервера.
Устанавливаем следующий код на OnSocketGetThread
procedure TfrmMain.fSocketGetThread(Sender: TObject;
 ClientSocket: TServerClientWinSocket;
 var SocketThread: TServerClientThread);
begin
 // Здесь создаём объект TServerThread, который я привожу ниже.
 // Новый объект создаётся каждый раз, когда когда установлен канал связи.
 SocketThread := TServerThread.Create(False, ClientSocket);
end;
TServerThread - это объект, который я создаю самостоятельно. Объект наследуется от TServerClientThread и содержит код, который обычно читает и пишет данные из/в сокет.
Созданный "unit", содержит следующий код:
unit serverthread;
interface
uses
 windows, scktcomp, SysUtils, Classes, Forms;
type
 EServerThread = class(Exception);
 // serverthread это потомок TServerClientThread
 TServerThread = class(TServerClientThread)
 private
 FSocketStream: TWinSocketStream;
 public
 procedure ClientExecute; override;
 // ClientExecute отменяет
 // TServerClientThread.ClientExecute
 // и содержит код, который
 // выполняется при старте потока
 end;
implementation
procedure TServerThread.ClientExecute;
begin
 inherited FreeOnTerminate := TRUE;
 try
 FSocketStream := TWinSocketStream.Create(ClientSocket, 100000);
 // 100000 - это таймаут в миллисекундах.
 try
 while (not Terminated) and ClientSocket.Connected do
 try
 // В это место обычно помещается код,
 // ожидающий входных данных, читающий из сокета или пишущий в него
 // Пример, приведённый ниже, показывает, что можно добавить в данную
 // секцию программы.
 except
 on e: Exception do
 begin
 // Если произошла ошибка, то закрываем сокет и выходим
 ClientSocket.Close;
 Terminate;
 end;
 end;
 finally
 FSocketStream.Free;
 end;
 except
 on e: Exception do
 begin
 // Если произошла ошибка, то закрываем сокет и выходим
 ClientSocket.Close;
 Terminate;
 end;
 end;
end;
Когда связь установлена, потоку необходимо ожидать входящих данных (запроса от клиента). Для этого можно использовать следующий код:
if (not Terminated) and (not FSocketStream.WaitForData(1000000)) then
begin
 // Обработчик таймаута (т.е. если по истечении 1000000 миллисекунд
 // от клиента не пришло запроса
end;
// В сокете есть входящие данные!
Для чтения данных, Вам понадобится создать буфер для хранения полученных данных. Обычно буфер - это PByteArray или массив символов. В этом примере я обозвал буфер как FRequest который является массивом символов. Кроме того я ожидаю фиксированное количество байт. Массив имеет постоянный размер REQUESTSIZE.
var
 ac, readlen: Integer;
begin
 FillChar(FRequest, REQUESTSIZE, 0);
 ac := 0;
 repeat
 readlen := FSocketStream.Read(FRequest[ac], 1024);
 // считываем блоки по 1024 байт, до тех пор, пока буфер
 // не заполнится
 ac := ac + readlen;
 until (readlen = 0) or (ac = REQUESTSIZE);
end;
Если readlen равно 0, значит больше нет входящих данных. Функция Чтения завершается через 100000 миллисекунд после запуска в TWinSocketStream.Create(). Если Вы не знаете сколько времени нужно ожидать запроса от клиента, то чем меньше будет таймаут, тем лучше. В большинстве случаев максимальный таймаут не должен превышать 30 секунд.
При посылке ответа, Вы должны знать, в каком режиме работает клиент. Многие клиенты ожидают только один пакет ответа, другие ожидают несколько пакетов. В этом примере, я подразумеваю клиента, который ожидает только один пакет, так что я должен послать мои данные назад в одном блоке:
FSocketStream.WriteBuffer(FRep, FReplySize);
FRep это буфер, содержащий ответ на запрос клиента, и FReplySize - это размер буфера.
Author: Brian Pedersen
Source: http://forum.sources.ru
ID: 03552
Category:Связь
Category:Сокеты