KVRSOFT - Програмиране на сокети в Delphi

За първи път се запознах с контакти, ако не се лъжа, преди година или половина. Тогава задачата беше да се разработи протокол за приложение, който да изпрати заявка до сървърна машина (работеща на Unix/Linux OS) и да получи отговор чрез сокет канал. Трябва да се отбележи, че за разлика от други протоколи (FTP, POP, SMTP, HTTP и др.), Сокетите са в основата на тези протоколи. По този начин, използвайки гнезда, можете сами да създадете (симулирате) FTP, POP и всеки друг протокол и не непременно вече създаден, но дори и ваш собствен!

Така че нека започнем с теорията. Ако сте отдаден практикуващ (и не виждате алгоритми в очите си), тогава трябва да пропуснете този раздел.

Алгоритъм за работа с сокет протоколи

И така, какво ни позволяват гнездата? Всичко! И това е едно от основните предимства на този метод за обмен на данни в мрежата. Въпросът е, че когато работите с сокет, просто изпращате последователност от символи на друг компютър. Така че с този метод можете да изпращате както прости съобщения, така и цели файлове! Освен това не е необходимо да контролирате коректността на прехвърлянето (както беше при работа с COM портове)!

По-долу е дадена примерна схема за работа с сокети в приложенията на Delphi

Нека анализираме схемата по-подробно:

Изпращането/получаването на данни всъщност е това, за което е била отворена връзката на сокета. Комуникационният протокол също зависи от сървъра;

Затваряне на сокет - след като всички операции са изпълнени, трябва да затворите сокета, използвайки метода Close на компонента TClientSocket (или да зададете свойството Active на False).

Описание на свойствата и методите на компонента TClientSocket

Тук ще се запознаем с основните свойства, методи и събития на компонента TClientSocket.

Активен - показва дали гнездото е отворено или не. Тип: Boolean. Съответно True е отворен, а False е затворен. Това свойство може да се записва;

Хост - низ (Тип: низ), указващ името на хоста на компютъра, към който да се свържете;

Порт - номер на порт (Тип: Цяло число (Word)), към който да се свържете. Валидни стойности са от 1 до 65535;

Услуга - низ (Тип: низ), определящ услугата (ftp, http, поп и т.н.), към която ще бъде свързан портът. Това е вид справка за съответствието на номерата на портове с различни стандартни протоколи;

ClientType - тип връзка. ctNonBlocking - асинхронно предаване на данни, тоест можете да изпращате и получавате данни през сокет, използвайки OnRead и OnWrite. ctBlocking - синхронен (едновременен) трансфер на данни. Събитията OnRead и OnWrite не работят. Този тип връзка е полезен за организиране на обмен на данни с помощта на потоци (т.е. работа с сокет като файл);

Open - отваряне на сокет (подобно на задаването на свойството Active на True);

Close - затваря сокета (подобно на присвояване на False на свойството Active);

OnConnecting - задейства се, когато се установи връзка. Разликата от OnConnect е, че връзката все още не е установена. Обикновено тези междинни събития се използват за актуализиране на състоянието;

OnDisconnect - Повишава се, когато гнездото е затворено. Нещо повече, затваряне както от вашата програма, така и от страната на отдалечен компютър (или поради повреда);

OnError - продължава тъжната тема на предишното събитие:). Възниква, когато възникне грешка в сокет. Трябва да се отбележи, че това събитие няма да ви помогне да уловите грешка в момента на отваряне на сокета (Open). За да избегнете издаването на съобщение за грешка в Windows, трябва да приложите отворените отчети на сокета в блок try.except (обработка на изключения);

OnRead - възниква, когато отдалеченият компютър ви е изпратил някакви данни. Когато се случи това събитие, е възможна обработка на данни;

OnWrite - възниква, когато ви е позволено да записвате данни в сокета.

Практика и примери

Пример 1. Най-проста програма за сокети

При натискане на бутона се извиква манипулаторът на събитието OnClick - Button1Click.

Преди това трябва да въведете името на хоста в първия от TEdits,

а във втория - порта на отдалечения компютър.

НЕ ЗАБРАВЯЙТЕ ДА ПОСТАВАТЕ КОМПОНЕНТА TClientSocket във ФОРМАТА!>

процедура Button1Click (Изпращач: TObject);

ClientSocket1.Port: = StrToInt (Edit2.Text);

процедура ClientSocket1Connect (Изпращач: TObject; Гнездо: TCustomWinSocket);

Ако смятате, че тази примерна програма е напълно безполезна и не може да бъде от полза, дълбоко се заблуждавате. Даденият код е най-простият пример за скенер на портове (PortScanner). Същността на такава помощна програма е да провери дали посоченият порт е активиран и дали е готов да приема/предава данни. Това е принципът зад PortScanner от NetTools Pro.

Следва друг пример, в който текстови съобщения се изпращат и получават през сокет:

Пример 2. Изпращане/получаване на текстови съобщения през гнезда

При щракване върху първия бутон се извиква манипулаторът на събитието OnClick - Button1Click.

Преди това трябва да въведете името на хоста в първия от TEdits,

а вторият е портът на отдалечения компютър. След установяване на връзката

можете да изпращате текстови съобщения, като въвеждате текст в третия TEdit и натискате

вторият бутон TB. За да прекъснете връзката, трябва отново да натиснете първия бутон TB.

Също така трябва да добавим TListBox, в който ще поставим полученото

и изпратени съобщения.

НЕ ЗАБРАВЯЙТЕ ДА ПОСТАВАТЕ КОМПОНЕНТА TClientSocket във ФОРМАТА!>

процедура Button1Click (Изпращач: TObject);

ако ClientSocket1.Активен тогава

ClientSocket1.Port: = StrToInt (Edit2.Text);

процедура ClientSocket1Connect (Изпращач: TObject; Гнездо: TCustomWinSocket);

процедура Button2Click (Изпращач: TObject);

ЗАБЕЛЕЖКА: В някои случаи (в зависимост от сървъра) трябва да изпращате линейна емисия след всяко съобщение:

ClientSocket1.Socket.SendText (Edit3.Text # 10);

Работа с поток от сокет

„Как иначе можете да работите със сокет?“, Питате вие. Естествено, горният метод не е най-доброто решение. Има много методи за организиране на работа с гнезда. Ще дам само още едно допълнително - работа през потока. Със сигурност много от вас вече имат опит с, ако не с потоци, то с файлове - със сигурност. За тези, които не знаят, потокът е канал за обмен на данни, работата с който е подобна на работата с обикновен файл. Примерът по-долу показва как да настроите поток за работа с сокет:

Пример 3. Поток за работа със сокет

процедура ClientSocket1Connect (Изпращач: TObject; Гнездо: TCustomWinSocket);

свържете го с сокета (60000 - изчакване в ms)>

MySocket: = TWinSocketStream.Create (Socket, 60000);

(в този пример - 100) и връща True, ако има поне едно

байт за данни, False, ако няма данни от потока.>

докато не MySocket.WaitForData (100)

прозоречни елементи и дава време на други програми. Ако този оператор

не беше и данните нямаше да бъдат получени дълго време,

системата би замръзнала леко

MySocket.Read (c, 1);

(в този пример - 1) към посочената променлива от определен тип

(в примера в променлива c от тип Char). Моля, имайте предвид, че,

че Read, за разлика от ReadBuffer, не задава стриктно

ограничения върху количеството получена информация. Тези. Прочетете четете

не повече от n байта от потока (където n е определен номер).

Тази функция връща броя на получените байтове с данни.>

MySocket.Write (c, 1);

че Write пише данни в потока.>

ЗАБЕЛЕЖКА: За да използвате поток, не забравяйте да зададете свойството ClientType на ctBlocking.

Изпращане и получаване на сложни данни

Понякога е необходимо да се изпращат по мрежата не само прости текстови съобщения, но и сложни структури (типът запис в Pascal) или дори файлове. И тогава трябва да използвате специални оператори. Някои от тях са изброени по-долу:

Методи на TClientSocket.Socket (TCustomWinSocket, TClientWinSocket):

SendBuf (var Buf; Count: Integer) - Изпращане на буфер през сокет. Буферът може да бъде от всякакъв тип, било то запис или обикновено цяло число. Буферът се определя от параметъра Buf, като с втория параметър трябва да посочите размера на прехвърлените данни в байтове (Count);

SendText (const S: string) - Изпраща текстов низ през сокет. Този метод беше обсъден в пример 2 (виж по-горе);

SendStream (AStream: TStream) - Изпратете съдържанието на посочения поток през сокет. Препратеният поток трябва да е отворен. Потокът може да бъде от всякакъв тип - файл, от RAM и др. Описанието за директна работа с потоци е извън обхвата на тази статия;

Всички изброени методи съответстват на методите Receive ... Описанието им може да бъде намерено във файла за помощ на Delphi (помощ за VCL).

Упълномощаване на сървъра

Пример 4. Упълномощаване

TEdit - Edit3 и Edit4, за да въведете потребителско име и парола>

процедура ClientSocket1Connect (Изпращач: TObject; Гнездо: TCustomWinSocket);

вход, парола: низ;

MySocket: = TWinSocketStream.Create (Socket, 60000);

за да може сървърът да отдели данните за вход и парола.>

вход: = Редактиране 3. Текст # 10;

парола: = Edit4.Text # 10;

MySocket.Write (вход, дължина (Edit3.Text) 1);

MySocket.Write (парола, дължина (Edit4.Text) 1);

докато не MySocket.WaitForData (100)

MySocket.Read (c, 1);

(това е само пример). След това изпълняваме необходимите действия

(получаване/изпращане на данни) и затваряне на потока.>

В тази статия съм написал само малко от това, което може да се каже за гнездата. Може би когато имам нов прилив на енергия, ще допълня тази статия с още по-интересен материал.

В близко бъдеще планирам и статия за сокет сървъри (TServerSocket).