![]() |
![]() ![]() ![]() ![]() |
|
Программирование сокетов в DelphiDelphi , Интернет и Сети , СокетыАвтор: Павел Введение Данная статья посвящена созданию приложений архитектуры клиент/сервер в Borland Delphi на основе сокетов ("sockets" - гнезда). А написал я эту статью не просто так, а потому что в последнее время этот вопрос очень многих стал интересовать. Пока что затронем лишь создание клиентской части сокетного приложения. Впервые я познакомился с сокетами, если не ошибаюсь, год или полтора назад. Тогда стояла задача разработать прикладной протокол, который бы передавал на серверную машину (работающую на ОС Unix/Linux) запрос и получал ответ по сокетному каналу. Надо заметить, что в отличие от любых других протоколов (FTP, POP, SMTP, HTTP, и т.д.), сокеты - это база для этих протоколов. Таким образом, пользуясь сокетами, можно самому создать (симитировать) и FTP, и POP, и любой другой протокол, причем не обязательно уже созданный, а даже свой собственный! Итак, начнем с теории. Если Вы убежденный практик (и в глаза не можете видеть всяких алгоритмов), то Вам следует пропустить этот раздел. Алгоритм работы с сокетными протоколамиТак что же позволяют нам делать сокеты?... Да все что угодно! И в этом одно из главных достоинств этого способа обмена данными в сети. Дело в том, что при работе с сокетом Вы просто посылаете другому компьютеру последовательность символов. Так что этим методом Вы можете посылать как простые сообщения, так и целые файлы! Причем, контролировать правильность передачи Вам не нужно (как это было при работе с COM-портами)! Ниже следует примерная схема работы с сокетами в Дельфи-приложениях Разберем схему подробнее:
Описание свойств и методов компонента TClientSocket Здесь мы познакомимся с основными свойствами, методами и событиями компонента TClientSocket.
Практика и примеры Легче всего (и полезней) изучать любые методы программирования на практике. Поэтому далее приведены примеры с некоторыми комментариями: Пример 1. Простейшая сокетная программа
{... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1}
{В форму нужно поместить кнопку TButton и два TEdit.
При нажатии на кнопку вызывается обработчик события OnClick - Button1Click.
Перед этим в первый из TEdit-ов нужно ввести хост-имя,
а во второй - порт удаленного компьютера.
НЕ ЗАБУДЬТЕ ПОМЕСТИТЬ В ФОРМУ КОМПОНЕНТ TClientSocket!}
procedure Button1Click(Sender: TObject);
begin
{Присваиваем свойствам Host и Port нужные значения}
ClientSocket1.Host := Edit1.Text;
ClientSocket1.Port := StrToInt(Edit2.Text);
{Пытаемся открыть сокет и установить соединение}
ClientSocket1.Open;
end;
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
begin
{Как только произошло соединение - закрываем сокет и прерываем связь}
ClientSocket1.Close;
end;
Если Вы думаете, что данный пример программы совершенно бесполезен и не может принести никакой пользы, то глубоко ошибаетесь. Приведенный код - простейший пример сканера портов (PortScanner). Суть такой утилиты в том, чтобы проверять, включен ли указанный порт и готов ли он к приему/передаче данных. Именно на таком принципе основан PortScanner из программы NetTools Pro. Далее следует другой пример, в котором по сокету передаются и принимаются текстовые сообщения: Пример 2. Посылка/прием текстовых сообщений по сокетам
{... Здесь идет заголовок файла и определение формы TForm1 и ее экземпляра Form1}
{В форму нужно поместить две кнопки TButton и три TEdit.
При нажатии на первую кнопку вызывается обработчик события OnClick - Button1Click.
Перед этим в первый из TEdit-ов нужно ввести хост-имя,
а во второй - порт удаленного компьютера. После установления соединения
можно посылать текстовые сообщения, вводя текст в третий TEdit и нажимая
вторую кнопку TButton. Чтобы отсоединиться, нужно еще раз нажать первую TButton.
Еще нужно добавить TListBox, в который будем помещать принятые
и отправленные сообщения.
НЕ ЗАБУДЬТЕ ПОМЕСТИТЬ В ФОРМУ КОМПОНЕНТ TClientSocket!}
procedure Button1Click(Sender: TObject);
begin
{Если соединение уже установлено - прерываем его.}
if ClientSocket1.Active then
begin
ClientSocket1.Close;
Exit; {...и выходим из обработчика}
end;
{Присваиваем свойствам Host и Port нужные значения}
ClientSocket1.Host := Edit1.Text;
ClientSocket1.Port := StrToInt(Edit2.Text);
{Пытаемся открыть сокет и установить соединение}
ClientSocket1.Open;
end;
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
begin
{Как только произошло соединение - посылаем приветствие}
Socket.SendText('Hello!');
ListBox1.Items.Add('< Hello!');
end;
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
begin
{Если пришло сообщение - добавляем его в ListBox}
ListBox1.Items.Add('> ' + Socket.ReceiveText);
end;
procedure Button2Click(Sender: TObject);
begin
{Нажата кнопка - посылаем текст из третьего TEdit}
ClientSocket1.Socket.SendText(Edit3.Text);
ListBox1.Items.Add('< ' + Edit3.Text);
end;
ПРИМЕЧАНИЕ: В некоторых случаях (зависящих от сервера) нужно после каждого сообщения посылать перевод строки: ClientSocket1.Socket.SendText(Edit3.Text + #10); Работа с сокетным потоком "А как еще можно работать с сокетом?", - спросите Вы. Естественно, приведенный выше метод - не самое лучшее решение. Самих методов организации работы с сокетами очень много. Я приведу лишь еще один дополнительный - работа через поток. Наверняка, многие из Вас уже имеют опыт работы, если не с потоками (stream), то с файлами - точно. Для тех, кто не знает, поток - это канал для обмена данными, работа с которым аналогична работе с обычным файлом. Нижеприведенный пример показывает, как организовать поток для работы с сокетом: Пример 3. Поток для работы с сокетом
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var
c: Char;
MySocket: TWinSocketStream;
begin
{Как только произошло соединение - создаем поток и
ассоциируем его с сокетом (60000 - таймаут в мсек)}
MySocket := TWinSocketStream.Create(Socket, 60000);
{Оператор WaitForData ждет данных из потока указанное время в мсек
(в данном примере - 100) и возвращает True, если получен хотя бы один
байт данных, False - если нет никаких данных из потока.}
while not MySocket.WaitForData(100) do
Application.ProcessMessages;
{Application.ProcessMessages позволяет Windows перерисовать нужные
элементы окна и дает время другим программам. Если бы этого оператора
не было и данные бы довольно долго не поступали,
то система бы слегка "подвисла".}
MySocket.Read(c, 1);
{Оператор Read читает указанное количество байт из потока
(в данном примере - 1) в указанную переменную определенного типа
(в примере - в переменную c типа Char). Обратите внимание на то,
что Read, в отличие от ReadBuffer, не устанавливает строгих
ограничений на количество принятой информации. Т.е. Read читает
не больше n байтов из потока (где n - указанное число).
Эта функция возвращает количество полученных байтов данных.}
MySocket.Write(c, 1);
{Оператор Write аналогичен оператору Read, за тем лишь исключением,
что Write пишет данные в поток.}
MySocket.Free;
{Не забудем освободить память, выделенную под поток}
end;
ПРИМЕЧАНИЕ: Для использования потока не забудьте установить свойство ClientType в ctBlocking. Посылка и прием сложных данных Иногда необходимо пересылать по сети не только простые текстовые сообщения, но и сложные структуры (тип record в Паскале), или даже файлы. И тогда Вам необходимо использовать специальные операторы. Некоторые из них перечислены ниже: Методы TClientSocket.Socket (TCustomWinSocket, TClientWinSocket):
Всем перечисленным методам соответствуют методы Receive... Их описание можно посмотреть в справочном файле по Дельфи (VCL help). Авторизация на сервере Напоследок хочу привести несложный пример того, как можно реализовать авторизацию (вход на сервер). В данном примере пароль посылается нешифрованным текстом, так что если Вам нужен действительно надежный механизм входа, то Вам придется внести кое-какие изменения в исходник данного примера. Пример реализован как работа с сокетным потоком. Пример 4. Авторизация
{В данном примере нужно добавить в форму еще два
TEdit - Edit3 и Edit4 для ввода логина и пароля}
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var
c: Char;
MySocket: TWinSocketStream;
login, password: string;
begin
MySocket := TWinSocketStream.Create(Socket, 60000);
{Добавляем к логину и паролю символ перевода строки,
чтобы сервер смог отделить логин и пароль.}
login := Edit3.Text + #10;
password := Edit4.Text + #10;
MySocket.Write(login, Length(Edit3.Text) + 1);
MySocket.Write(password, Length(Edit4.Text) + 1);
while not MySocket.WaitForData(100) do
Application.ProcessMessages;
MySocket.Read(c, 1);
{Здесь сервер посылает нам один байт, значение 1 которого
соответствует подтверждению успешной авторизации, а 0 - ошибку
(это лишь пример). Далее мы выполняем нужные действия
(прием/пересылку данных) и закрываем поток.}
MySocket.Free;
end;
Эпилог В этой статье я написал лишь самую малость из того, что можно было бы сказать про сокеты. Может быть, когда у меня появится новый прилив сил, я дополню эту статью еще более интересным материалом. В ближайшем будущем планирую также статью про сокетные серверы (TServerSocket). Программирование сокетов в Delphi. Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш
|
||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 | ||||||||||