Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Сокеты в Дельфи !!!


Автор: Vinnety 5.10.2004, 16:08
qstn.gif Народ! Помогите советом!
Мне необходимо передать посредством сокетов с клиентской программы (использую TClientSocket) данные на программу-сервер(использую TServerSocket).

Вопрос №1. Как мне на стороне сервера (используя TServerSocket) определять адреса клиентов, т.е. чтобы я мог послать определенную информацию определённому пользователю.
Например, чтобы сообщение "Привет, Коля!" дошло Коле, а не кому то другому.

Вопрос №2. Мне необходимо передавать данные :

type
TPack = record
Code : integer;
Data : double;
end;
TArrRec = array of TRec;

TRec = record
UserID : integer;
ActionID : integer;
Datas : TArrRec;
end;

var
Rec : TRec;


Т.е. массив TArrRec - динамический, поля UserID, ActionID - служебные (для передачи на данных на сервер).
Как мне отправить наполнить и отправить такую запись как Rec через сокеты (используя TClientSocket)? Каким способом лучше это сделать (через SendBuf или SendStream)?
Или кто-то видит другое решение проблемы?

Автор: Alex 5.10.2004, 19:48
В 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
Добавлено @ 19:50
А вообще скачай http://forum.vingrad.ru/index.php?showtopic=22229 и там найдешь еще информацию о сокетах и не только.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)