На днях, в свой проект MapWindows GIS в Delphi я добавил сетевую поддержку. То есть создал отдельный сервер и отдельный клиент. Смысл заключается в том, что работает сервер приложения, пользователь запускается клиент и в пользователь вводит запрос: Москва Тверская 6. Затем сервер обрабатывает запрос, получает результаты поиска из Яндекс.Карт и отправляет полученную картинку клиенту, затем уже в клиенте в компоненте TMap отображается часть данной карты, которая соответствует запросу пользователя. В итоге пользователь может ее масштабировать, сохранять и так далее.

Поэтому в данной статье я хочу рассказать, как я реализовывал клиента и сервер. Это я делал с помощью TClientSocket и TServerSocket, в данной статье мы и рассмотрим подробно те методы, которые использовал я у себя, в своем проекте.

Для начала давайте посмотрим, как эти компоненты можно установить себе в IDE. Если Вы используете IDE Delphi 7, то в ней по умолчанию данные компоненты присутствуют, но они, к сожалению, не установлены, но это не проблема. Нам достаточно открыть Delphi и установить.

Для этого выполним команду Component-Install Packages… и в появившемся окне необходимо нажать на кнопку Add. После этого необходимо указать путь к файлу dclsockets70.bpl, который обычно, по умолчанию, находится в папке BIN. После этого необходимо нажать на кнопку Ок. Все, компоненты у Вас должны появиться на вкладке Internet (TClientSocket и TServerSocket).

В проекте MapWindow GIS, я начинал всю работу, с минимальной разработке сервера. Для начала установил компонент TServerSocket на форму. И по нажатию на кнопку Запустить сервер задал первоначальные настройки, для его инициализации:

Server.Port:=FormServerSetting.SpinEditPort.Value;//указываем порт сервера
    Server.Active:=True;//активируем его
    Server.Open;
    if Server.Active then
     begin
      //выводим сообщение что сервер запущен и работает
     end;
……..
//выводим ошибку, если сервер не запустился

 

Для инициализации сервера на своей машине, я задавал лишь только свободный порт (который не занят другими приложениями) и активировал его.

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

Для того, чтобы мне получить список клиентов, которые подключаются к серверу и дальнейшей работы с ними, я установил компонент TCheckListBox на форму и на событие OnclientConnect компонента TServerSocket, написал следующий код:

procedure TFormServer.ServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   //отслеживаем подключение клиента
   RichEditLog.SelAttributes.Color:=clGreen;
   RichEditLog.SelAttributes.Style:=[fsBold];
   CheckListClient.Items.Add(Socket.RemoteHost);
   RichEditLog.Lines.Add('['+TimeToStr(Time)+'] Client connected: '+Socket.RemoteHost);//добавляем в список клиента, который подключился
   RichEditLog.Perform(WM_VSCROLL,SB_BOTTOM,0);
end;

То есть, я в список добавляю имена тех клиентов, которые подключаются к серверу, для дальнейшего получения информации о них.

Например, можно получить подробную информацию о клиенте:

procedure TFormInfoClient.FormShow(Sender: TObject);
begin
   //выводим ифнормацию о клиенте
   Caption:='Информация о клиенте: '+FormServer.CheckListClient.Items[FormServer.CheckListClient.ItemIndex];
   LocalName.Caption:=FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].LocalHost;
   LocalHost.Caption:=FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].LocalAddress;
   LocalPort.Caption:=IntToStr(FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].LocalPort);
   RemoteName.Caption:=FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].RemoteHost;
   RemoteHost.Caption:=FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].RemoteAddress;
   RemotePort.Caption:=IntToStr(FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].RemotePort);
end;

Можно получить следующие данные:

  • Локальное имя
  • Локальный адрес
  • Локальный порт
  • Удаленное имя
  • Удаленный адрес
  • Удаленный порт

Информацию я получаю о том клиента, с помощью данного кода, которого я выделил в списке компонента TCheckListBox.

Ничего сложного, как видите, нет, для того, чтобы отправить сообщение клиенту, можно воспользоваться следующим кодом:

FormServer.Server.Socket.Connections[FormServer.CheckListClient.ItemIndex].SendText('#message#'+RichEditMessage.Text);

 

В квадратных скобках, я указываю, какому клиенту мы будем отправлять сообщение (оно равно выделенному клиенту в компоненте TCheckListBox), в сообщение я указываю #message# — что означает, что это обычное сообщение от сервера, которое следует просто вывести в окне.

Для того чтобы получить сообщение от клиента, серверу, нам понадобится событие OnClientRead компонента TServerSocket и текстовая переменная, в которую мы будем записывать запрос, который посылает клиент.

procedure TFormServer.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
query:String;
begin
   //получаем запрос от клиента на карту
   try
    query:=Socket.ReceiveText;
     if pos('query',query)<>0 then
      begin
       //запрашиваем у Яндекса или Google координаты карты, соответсвующие запросу клиента
      end;
     //если просто сообщение от клиента, то выводим его
     if pos('#message#',query)<>0 then
      begin
 
      end;
……

Из данного кода можно увидеть, что клиент может посылать как обычное сообщение серверу, так и запрос на получение карты, вида: Москва, Тверская, 6.

Для этого мне надо определить, где обычное сообщение, а где именно запрос, на получение карты, чтобы сервер в дальнейшем смог его обработать. В этом случае я к сообщениям клиента, в самом начале, добавляю такие идентификаторы:

  • #message#
  • #query#

Если вначале сообщения клиента присутствует идентификатор #message#, то сервер распознает, как обычное сообщение от клиента. Если вначале сообщения присутствует идентификатор #query#, то это означает, что клиент послал запрос на получение карты.

Вот и все, дальше сервер обрабатывает запрос и отправляет карту клиенту, которая отображается в компоненте TMap.

Также клиент, в любое время может отключить от сервера, нам это также необходимо отследить, чтобы удалить его из общего списка клиентов, подключенных к серверу. Для этого выделяем компонент TServerSocket и на событие OnClientDisconnect пишем следующий код:

procedure TFormServer.ServerClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
 i:integer;
begin
   try
    //отслеживаем отключение клиента
    RichEditLog.SelAttributes.Color:=clRed;
    RichEditLog.SelAttributes.Style:=[fsBold];
    for i := 0 to Server.Socket.ActiveConnections-1 do
     begin
      if Server.Socket.Connections[i].Handle=Server.Socket.Connections[i].Handle then
       begin
        RichEditLog.Lines.Add('['+TimeToStr(Time)+'] Client disconnected: '+Socket.RemoteHost);
        CheckListClient.Items.Delete(i);
        RichEditLog.Perform(WM_VSCROLL,SB_BOTTOM,0);
       end;
     end;
   finally
     //-//-//-//-//-//
   end;
end;

Мы проходим по всем клиентам, которые у нас есть в списке и если какого-то ненаходим, то удаляем его из компонента TCheckListBox, это означает, что клиент в своем приложении нажал на кнопку Отключиться.

Кстати, на сервере также можно отключать клиентов, для этих целей можно использовать следующий код:

procedure TFormServer.N1Click(Sender: TObject);
begin
   //отключаем клиента вручную
   if CheckListClient.ItemIndex<0 then
    begin
      Application.MessageBox('Выберите клиента','Ошибка',MB_OK+MB_ICONERROR);
      exit;
    end;
   Server.Socket.Connections[CheckListClient.ItemIndex].Destroy;
   CheckListClient.Items.Delete(CheckListClient.ItemIndex);
end;

Тут я думаю, должно быть все понятно, отключаем клиента, который выделен в списке, в компоненте TCheckListBox.

Что касается сервера, то вроде бы все, я все рассказал, что я использовал в своем приложении MapWindow GIS и получении карт с сервиса Яндекс.Карты. Теперь давайте перейдем к рассмотрению клиента.

Для начала на форму клиента, необходимо установить компонент TClientSocket, после этого произвести настройки, к какому серверу он будет подключаться.

Это делается следующим образом:

procedure TForm1.Button1Click(Sender: TObject);
begin
   if ClientSocket1.Active<>True then
    begin
     ClientSocket1.Port:=SpinEdit1.Value;
     ClientSocket1.Host:=Edit1.Text;
     ClientSocket1.Active:=True;
    end;
end;

 

Указываем ему следующие данные:

  • Порт
  • Хост

Далее активируем его, если сервер и клиент находятся на одном компьютере (то в хост можно указывать localhost или же 127.0.0.1).

После того, как нажмете на кнопку подключить, имя данного клиента должно отобразиться в окне нашего сервера (в компоненте TCheckListBox, помните?).

Если нас сервер отключает, то можно вывести соответсвующее сообщение, для этого необходимо на событие OnDisconnect компонента TClientSocket написать следующий код:

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   if flag=False then
    begin
     ShowMessage('Вас отключили с сервера');
     flag:=true;
    end;
end;

 

Чтобы клиент сам мог отключиться, то можно воспользоваться следующим кодом:

procedure TForm1.Button2Click(Sender: TObject);
begin
   ClientSocket1.Active:=False;
end;

 

Для того чтобы отправить запрос серверу, я использую следующий код:

procedure TForm1.Button3Click(Sender: TObject);
begin
   ClientSocket1.Socket.SendText('#query#="Москва"');
end;

В данном случае сервер будет распознавать данное сообщение, как запрос и естественно в дальнейшем будет его обрабатывать (посылать запрос на Яндекс.Карты и полученную карту отправлять клиенту).

Если я от клиента – серверу, отправляю обычное сообщение, то я указываю:

procedure TForm1.Button3Click(Sender: TObject);
begin
   ClientSocket1.Socket.SendText('#message#="Москва"');
end;

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

Вот примерно и все, хочется сказать еще одно, что на событие OnRead компонента TClienSocket я получаю нашу карту, которую в дальнейшем отображаю в окне клиента, в компоненте TMap. Клиент может ее увеличивать, сохранять, рисовать на ней.

За проектом MapWindow GIS, можно следить на странице.

Данный метод можно применять не только для карт, а в любой момент, где Вы не хотите, чтобы клиенты получали доступ к Интернету, но имели возможность для получения какой-то информации из Интернета.

Метки: , , , ,




К записи “Работа с TClientSocket и TServerSocket на примере проекта MapWindow GIS” оставлено комментариев: 5.

  1. […] уже рассказывал о работе TClientSocket и TServerSocket на примере MapWindow GIS, в той статье мы рассмотрели: как можно передавать […]

  2. Мне кажется, что тут ошибка, т.к. при таком условии удалятся все клиенты из listbox:
    if Server.Socket.Connections[i].Handle=Server.Socket.Connections[i].Handle then

  3. pch:

    Переменная flag к какому типу принадлежит? Все застопорилось

  4. SaheR:

    Здравствуйте. Тоже использую в проекте Socket’ы. Но, например, сообщение ‘cmd1′ доходит до сервера в виде иероглифов. Что происходит и как быть?

  5. 4elovek:

    Дружище! Статья просто супер! Все адекватно расписано, все понятно и интересно! Спасибо :)

Оставить комментарий

Вы можете использовать следующие теги:

*