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


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


Автор: Brian Pedersen

В 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 - это размер буфера.

Взято с Исходников.ru http://www.sources.ru





DELPHI FAQ




EOMY TOP 100      Рейтинг@Mail.ru      Rambler's Top100