VR
Virtual Reality On-line   WinSock
Новости   |     Журнал    |    Хаkер   |     Магазин   |   Проекты
[   Вход    ]
[Kарта сайтa]
[ Download  ]
[  Конкурс  ]
[  Анекдоты ]
[  Ссылки   ]
[  Реклама  ]
[ Почтальон ]
[ О проекте ]






TopList
Программирование гнёзд.
Компоненты ТServerSocket и ТClientSocket
:

До сегодняшнего дня, я описывал низкоуровневое программирование в сети. Но это не говорит о том, что в Delphi нет компонентов, облегчающих работу с сокетами. Такие компоненты есть, и сейчас я расскажу о двух из них: ТServerSocket и ТClientSocket. В качестве примера я не буду изобретать колесо, а воспользуюсь примером, который поставляется с Delphi.
Logo
Рис 1. Главная форма

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

Для начала о компонентах. ТServerSocket является сервером сокета. К нему могут подключаться клиенты ТClientSocket. Для того, чтобы ТclientSocket мог присоединиться к ТserverSocket у них должны быть одинаковые свойства ServerType (для обучения достаточно stNonBlocking) и Port (номер порта). Номер порта желательно использовать больше чем 1000, это позволит избежать конфликтов с зарезервированными портами для других целей. В примере я использую 1024 для сервера и клиента.

Я тут заметил, что я ещё не рассказывал, как создаётся меню. Сейчас исправлю. Чтобы создать меню, надо поставить на форму компонент TMainMenu. Дважды щёлкаем по нему и получите распишитесь. Перед нами возникает редактор. Просто пишем названия меню в поле Caption и всё. А в это время в Object Inspector можно изменять такие интересные значения, как Bitmap (картинка для пункта меню), ShotCut (быстрый вызов), RadioItem (пункт меню с галочкой, как у TRadioBox) и многое другое. Со всем очень легко разобраться, если есть хоть начальные знания английского. Если таким мама не наградила, то очень даже помогает словарь. Вставлять и удалять пункты меню можно клавишами Ins и Del . Теперь попробуй создать меню сам, и всё станет понятно.

Теперь рассмотрим все пункты меню.

"Включить прослушивание":

  FileListenItem.Checked := not FileListenItem.Checked;
  if FileListenItem.Checked then
  begin
  //Надо включить прослушивание
    ClientSocket.Active := False;
    ServerSocket.Active := True;
    Statusbar1.Panels[0].Text := 'Прослушиваем...';
  end
  else//Иначе надо отключить прослушивание
  begin
    if ServerSocket.Active then
      ServerSocket.Active := False;
    Statusbar1.Panels[0].Text := '';
  end;

Первая строка изменяет состояние FileListenItem.Checked на противоположное. Это означает: Если уже включено прослушивание FileListenItem. Checked = true, то надо отключить, иначе надо включить.

Для начала, рассмотрим ситуацию, когда надо включить сервер на прослушивание. Здесь я сначала отключаю клиента. ClientSocket.Active := False - делаю клиента не активным. Если у тебя на форме стоит одновременно и клиент и сервер, то они не могут быть оба одновременно включёнными. Одно приложение не может быть одновременно и сервером и клиентом для одного и того же порта. Это возможно только если порты разные, поэтому я на всякий случай отключаю клиента.

ServerSocket.Active := True - включить сервер на прослушивание. После этого ТserverSocket начинает слушать порт на предмет подключения к нему.

Statusbar1.Panels[0].Text := 'Прослушиваем...' - вывожу соответствующее сообщение в строку состояния.

Теперь ситуация, когда надо отключить сервер:

if ServerSocket.Active then ServerSocket.Active := False - эта строка означает: если сервер включён, то отключить его.

Statusbar1.Panels[0].Text := '' - отчищаю строку состояния.

Если ты один раз выберешь это меню, то запуститься сервер на прослушивание. При следующем нажатии, сервер отключится.

Теперь о меню подключиться:

procedure TChatForm.FileConnectItemClick(Sender: TObject);
begin
if ClientSocket.Active then ClientSocket.Active := False;
if InputQuery('Присоединиться к...', 'Имя сервера:', Server) then
if Length(Server) > 0 then
 with ClientSocket do
  begin
    Host := Server;
    Active := True;
    FileListenItem.Checked := False;
  end; 
end;

В первой строке я проверяю, если клиент уже подключён, то я отключаю его.

Затем я запрашиваю ввод имени сервера (имя компьютера или его IP адрес где запущена такая же прога и включено прослушивание). InputQuery - показывает диалоговое окно, в котором можно производить ввод. В качестве первых двух параметров выступают заголовки. Это строки, которые подсказывают пользователю, что надо ввести. Третий параметр - это переменная типа строки, в которую будет записан результат ввода.

Дальше идёт проверка if Length(Server)>0 then если длинна введённого пользователем текста больше 0 (то есть, если строка не пустая), то выполнить действия. В качестве действий выполняется три оператора.

with ClientSocket do
  begin
    Host := Server;
    Active := True;
    FileListenItem.Checked := False;
  end;

Обрати внимание на присутствие здесь конструкции with ClientSocket do. Я уже рассказывал о ней, но всё же повторюсь. Она говорит о том, что все действия между последующими BEGIN и END, надо по умолчанию выполнять с ClientSocket. Если какое-то действие нельзя выполнить, то выполнять его с главной формой. Сейчас всё будет видно на примере.

Host := Server. Если бы эта строка не стояла внутри конструкции with, то Host не был бы найден. А так, Delphi находит свойство Host у ClientSocket и присваивает в него введённое имя сервера.

Можно было не использовать конструкцию with, но тогда наша фунция бы выглядела так:

procedure TChatForm.FileConnectItemClick(Sender: TObject);
begin
if ClientSocket.Active then ClientSocket.Active := False;
if InputQuery('Присоединиться к...', 'Имя сервера:', Server) then
if Length(Server) > 0 then
  begin
    ClientSocket.Host := Server;
    ClientSocket.Active := True;
    FileListenItem.Checked := False;
  end; 
end;

Итак, имя сервера ввели, можно его активировать (Active := True;). После этого я на всякий случай отключаю прослушивание (FileListenItem.Checked := False). Я уже говорил, что одно приложение не может быть одновременно и сервером и клиентом для одного порта.

Если имя сервера было введено правильно, то приложение начнёт присоединяться к нему. Присоединились? Хорошо. Теперь надо разорвать связь. Вот процедура, вызываемая при щелчке по пункту меню "Отключиться":

procedure TChatForm.Disconnect1Click(Sender: TObject);
begin
  ClientSocket.Active := False;
  ServerSocket.Active := True;
  Statusbar1.Panels[0].Text := 'Прослушиваю...';
end;

Всё очень просто. Первая строка делает неактивным клиент (разрывает связь). Вторая строка включает сервер на прослушивание. Третья выводит сообщение в строку состояния. Всё это мы уже пережевали немного раньше.

Теперь перейдём к отправке текста. Для этого в примере перехватывается событие OnKeyDown у TMemo:

procedure TChatForm.Memo1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if Key = VK_Return then
 if ServerSocket.Active then
  ServerSocket.Socket.Connections[0].SendText(
                Memo1.Lines[Memo1.Lines.Count - 1])
 else
  ClientSocket.Socket.SendText(Memo1.Lines[Memo1.Lines.Count - 1]);
end;

Вначале идёт проверка: если нажата клавиша ENTER, то мы продолжаем работать. Дальше проверяется, если это сервер (к нам подключились), то для отправки используется компонент TServerSocket иначе TClientSocket.

Я немного мухлюю. Я проверяю, активен ли сервер, но не проверяю, есть ли к нему присоединившиеся клиенты. Если их нет, то произойдёт ошибка. Если не хочешь, чтоб выскакивала эта ошибка то напиши так:

 if (ServerSocket.Active=true) and 
    (ServerSocket.Socket.ActiveConnections>0) then 
  ServerSocket.Socket.Connections[0].SendText(
                Memo1.Lines[Memo1.Lines.Count - 1])

Теперь будет проверяться активность сервера и количество конектов (ServerSocket.Socket.ActiveConnections), которое должно быть обязательно больше 0. Если хотябы одно из этихз условий не выполнено, то отправки текста не будет.

Сначала разберёмся с клиентом, он проще. У него есть свойство Socket типа TClientWinSocket, которое отвечает за всю сетевую работу. У этого Socket есть интересующие нас методы SendBuf (отправить буфер), SendStream (отправить поток) и непосредственно SendText (отправить текст). Вот последняя нас и интересует. С помощью неё мы отправляем последнюю введённую пользователем строчку (Memo1.Lines[Memo1.Lines.Count - 1]).

У сервера чуточку сложнее. Там тоже есть свойство Socket типа TServerWinSocket. Но тут нельзя сразу отправить текст. Для этого нужно выбрать, какому именно клиенту предназначается текст. Я отправляю всегда первому клиенту ServerSocket. Socket. Connections[0]. SendText, но если ты захочешь отправлять сообщения сразу всем, то это можно сделать так:

for I:=0 to ServerSocket.Socket.ActiveConnections-1 do
begin
  ServerSocket.Socket.Connections[i].SendText(
                  Memo1.Lines[Memo1.Lines.Count - 1])
end;

Весь остальной текст проги - это ответы на сообщения, генерируемые компонентами ТServerSocket и ТClientSocket, поэтому я не будут на них останавливаться. Все эти процедуры чисто информационные. Единственное, что нам надо - это сообщение OnRead у ТClientSocket и OnClientRead у ТServerSocket . Эти сообщения происходят, когда на порт пришли какие-то данные (в нашем случае это текст). В примере, обе функции реализованы одинаковы, поэтому я приведу только одну:

procedure TChatForm.ClientSocketRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Memo2.Lines.Add(Socket.ReceiveText);
end;

Это сообщение возвращает нам Socket типа TCustomWinSocket. Это очень удобно, потому что, вызвав Socket.ReceiveText, мы получаем переданный нам текст. Я его просто добавляю к Memo2.

Программа готова. Запусти одну её копию на одном компьютере, а другую на другом. Теперь в одной из них включи прослушивание, а из другой попробуй подсоединиться, введя имя или IP- адрес первого компьютера. Попробуй напечатать какой-нибудь текст в поле Memo. После нажатия пимпы Enter, текст пересылается на другой компьютер.

Развлекайся, а я пошёл работать дальше. Напоминаю: если с чем-то не разобрался, то не волнуйся. Просто поиграй с примером и всё само придёт. Я даю только основы, а всё самое главное придёт собственным потом. Тренируйся, и всё получится.

 Исходники примера забирай здесь


Copyright©: Horrific aka Флёнов Михаил
Design by FMk group©