Написание клиента и сервера при помощи компонентов Indy TIdTCPServer и TIdTCPClient на Delphi
На главную
 

Зарабатывай на своем сайте размещением рекламы используя
Popunder.ru

подробнее ...

 
Реклама
 
Книги
В разделе Книги смотрите лучшие книги по Delphi
искать на Books.Ru:
Партнеры

 

 

 

 

 

 

 

 

 


 

 

 

 

 



Написание клиента и сервера при помощи компонентов Indy TIdTCPServer и TIdTCPClient на Delphi

Всё сказанное здесь справедливо для версии 7 борландовского Delphi и компонентов Indy версии 9.00.10.
Для создания клиент-серверного звена при помощи компонентов Indy нам понадобятся компоненты TIdTCPServer (находится на странице «Indy Servers») и TIdTCPClient на странице «Indy Clients». Таким образом, у нас получится две программы: приложение-клиент, построенное на базе компонента TIdTCPClient и приложение-сервер на базе компонента TIdTCPServer.
Теория взаимодействия клиента и сервера простая: сервер открывает ТСР-соединение (или сокет) на определенном ТСР-порту и «слушает» его (ожидает запрос на соединение от клиента). Клиент выполняет свою задачу тем, что соединяется к серверу. После установления соединения клиент и сервер могут взаимодействовать между собой, обмениваясь данными(файлами, текстовыми сообщениями и т.д.).

Настройка

Ниже указаны сервер и клиент со значениями их свойств, необходимых для успешного соединения между собой.

Со стороны сервера необходимо создать объект типа TidSocketHandle и настроить его свойства IP и Port, т.е. задать IP-адрес клиента и порт, на котором сервер будет его «ждать». Со стороны клиента нужно настроить также два свойства: порт и IP адрес сервера – Host и IP. Обычно сервер и клиент тестируются на одном компьютере, поэтому в примере указан локальный IP-адрес компьютера: ‘127.0.0.1', значение номера порта выбрано произвольно и задано заведомо большое значение для того чтобы избежать риска дублирования уже использующихся портов другими службами.

Соединение

Теперь, когда клиент и сервер готовы для предстоящей серьёзной работы, опишем их поведение до и после соединения.

Запуск сервера осуществляется установкой свойства Active в True:

TCPServer1.Active:= True;

После запуска сервер «слушает» назначенный порт, т.е. «ждёт» соединения от клиента по заданному порту и IP-адресу. После установления соединения с клиентом, сервером генерируются события OnConnect и OnExecute. Сервер обслуживает клиента отдельным от основного приложения потоком, который описывается в методе IdTCPServer1Execute :

procedure TForm1.TCPServer1Execute(AThread: TIdPeerThread);

Этот метод вызывается событием OnExecute сервера и именно ему передается аргумент потока AThread. Другими словами, при подключении каждого клиента создаётся отдельный поток, который и обслуживает каждого клиента в отдельности. В дальнейшем работа сервера с клиентом сводится к использованию набора методов и свойств потока AThread.

Более активную роль играет клиент. Для соединения с сервером клиент использует метод TCPClient1.Connect, для разрыва соединения применяется метод TCPClient1.Disconnect; После установления соединения с сервером клиентом генерируется событие OnConnected, при разрыве - OnDisconnected.

Отправка сообщения от сервера к клиенту

Отправка сообщения производится сервером в обслуживающем клиента потоке:

procedure TForm1.TCPServer1Execute(AThread: TIdPeerThread);
begin
AThread.Connection.Writeln('Это сообщение сервера');
end;

на стороне клиента принять это сообщение можно так:

procedure TForm1.TCPClient1Connected(Sender: TObject);
begin
ShowMessage(TCPClient1.Readln);
end;

т.е. запись сообщения в поток и считывание его происходит методами, схожими при работе с консолью или текстовыми файлами: Write, WriteLn, Read, ReadLn .

Отправка файла от сервера к клиенту

Для отправки файла на стороне сервера создаём следующий код:

procedure TForm1.TCPServer1Execute(AThread: TIdPeerThread);
var
MemStream:TMemoryStream;
FileName:string ;
SizeFile:integer;
begin
MemStream:=TMemoryStream.Create; // создаём поток памяти
MemStream.LoadFromFile('c:\example.txt'); // загружаем в поток памяти файл
SizeFile:=MemStream.Size; // определяем размер файла
AThread.Connection.Writeln(FileName); // отсылаем название файла
AThread.Connection.Writeln(SizeFile); // отсылаем размер файла AThread.Connection.OpenWriteBuffer; // открываем буфер записи
AThread.Connection.WriteStream(MemStream); // посылаем файл AThread.Connection.CloseWriteBuffer; // закрываем буфер записи
MemStream.Free; // уничтожаем поток памяти
end;

на стороне сервера сначала создаём поток памяти, загружаем в него файл и отсылаем поток клиенту. Теперь осталось принять файл на стороне клиента:

procedure TForm1.TCPClient1Connected(Sender: TObject);
var
s:string;
FileName,SizeFile: string;
MemStr:TMemoryStream;
begin
while
TCPClient1.Connected do
begin
FileName:=TCPClient1.Readln;
s:=TCPClient1.Readln;
SizeFile:=StrToInt(s);
MemStr:=TMemoryStream.Create;
TCPClient1.ReadStream(MemStr,SizeFile,False);
MemStr.SaveToFile('d:\'+FileName);
MemStr.Free;
end;
end;

Теперь поподробнее распишем методы.

Поток данных отправляется методом

procedure WriteStream(AStream: TStream; const AAll: Boolean = True; const AWriteByteCount: Boolean = False; const ASize: Integer = 0); virtual;

с параметрами:
AStream : TStream - собственно поток данных, в нашем случае это поток памяти
const AAll:Boolean=True - константа булева типа, показывающая, производить ли запись с начальной позиции потока Astream или нет, по умолчанию имеет значение True , т.е. запись производится с начальной позиции потока.
const AWriteByteCount: Boolean = False - константа булева типа, означающая, отсылать число битов, записанных в поток на приёмную сторону или нет, по умолчанию имеет значение False, т.е. не надо. Используется в тех случаях, когда поток отправляется не полностью, а с какой-то позиции. В этом случае AAll:=False, и для отправки количества отсылаемых бит применяется метод WriteInteger или любой другой.

В нашем случае мы применили метод как
AThread.Connection.WriteStream(MemStream); // посылаем файл

Т.е. поток оправляем с начальной позиции и полностью.

Приём файла делаем вызовом метода

procedure ReadStream (AStream : TStream; AByteCount:LongInt=-1; const AReadUntilDisconnect: boolean = false);  

где:
AStream:TStream - как вы уже догадались поток приёма информации,
AByteCount: LongInt = -1 - число байтов, которое нужно принять.
const AReadUntilDisconnect: boolean = false - логическая константа, показывающая, принимать поток данных до разрыва соединения или нет. По умолчанию имеет значение False и метод работает до конца приёма потока из стека. Если установить значение в True, то приём данных методом будет осуществлять до тех пор, пока свойство Connected будет не равно False, т.е. до разрыва соединения.

В нашем примере мы применили метод как
TCPClient1.ReadStream(MemStr,SizeFile,False);

т.е. читаем поток в поток памяти MemStr, размер принимаемого потока данных SizeFile, который мы предварительно получаем с сервера.

Таким образом, сказанного здесь хватит для написания простого клиента и сервера для приёма и отправки файлов и сообщений.

Рекомендуемая литература и источники:

«Indy in Depth» Chad Z. Hower (Kudzu) перевод Анатолия Подгорецкого
М. Кэнту.«Delphi7.Дляпрофессионалов».Глава 19. Интернет-программирование: сокеты и Indy




 

 

"."
 
 

 



© Delphi: избранное
© Владимир Богдановский 2005-2011 гг.
bogdan_we@mail.ru
ICQ 337 311 969

PRCY-info.ru, анализ сайтов bigmir)net TOP 100 Rambler's Top100 Яндекс.Метрика

WebList.Ru Яндекс цитирования Каталог ИТ