Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

Таким образом, функция

connect
в случае протокола UDP позволяет, во-первых, выполнить фильтрацию входящих дейтаграмм по адресу средствами самой библиотеки сокетов, а во-вторых, использовать более лаконичные альтернативы
recvfrom
и
sendto
recv
и
send
.

Возможные последовательности действий программы для протокола UDP показаны на рис. 2.1.

2.1.10. Пример программы: простейший чат на UDP

Попробуем применить свои знания на практике и напишем простейший чат

на основе протокола UDP. Пример этой программы находится на прилагаемом к книге компакт-диске и называется UDPChat, окно приложения показано на рис. 2.2.

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

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

FormatMessage
, которая возвращает текстовое сообщение по коду ошибки (эта функция работает со всеми ошибками, а не только с ошибками сокетов). На основе
FormatMessage
мы создадим функцию
GetErrorString
(листинг 2.6), которая возвращает сообщение, соответствующее коду ошибки, возвращаемому функцией
WSAGetLastError
. Эта функция будет встречаться во всех наших примерах.

Рис. 2.2. Главное окно UDP-чата

Листинг 2.6. Функция
GetErrorString
, возвращающая описание ошибки

// функция GetErrorString возвращает сообщение об ошибке,

// сформированное системой из основе значения, которое

// вернула функция WSAGetLastError. Для получения сообщения

// используется системная функция FormatMessage.

function GetErrorString: string;

var

 Buffer: array [0..2047] of Char;

begin

 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, WSAGetLastError, $400,

@Buffer, SizeOf(Buffer), nil);

 Result := Buffer;

end;

Нам понадобится и принимать, и передавать данные. Как мы помним, функция

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

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

TThread
. Мы не будем возлагать на эту нить задачу создания сокета, — пусть он создается в главной нити, а затем его дескриптор передаётся в дополнительную, которая сохраняет его в своем внутреннем поле
FSocket
. Код нити, читающей сообщения, показан в листинге 2.7.

Листинг 2.7. Код "читающей" нити

unit ReceiveThread;

{

 В этом модуле реализуется дополнительная нить UDP-чата, отвечающая за прием сообщений.

}

interface

uses

 SysUtils, Classes, WinSock;

type

 TReceiveThread = class(TThread)

 private

// Сообщение, которое нужно добавить в лог,

// хранится в отдельном поле, т.к. метод, вызывающийся через

// Synchronize, не может иметь параметров.

FMessage: string;

// Сокет, получающий сообщения

FSocket: TSocket;

// Вспомогательный метод для вызова через Synchronize

procedure DoLogMessage;

 protected

procedure Execute; override;

// Вывод сообщения в лог главной формы

procedure LogMessage(const Msg: string);

 public

constructor Create(ServerSocket: TSocket);

 end;

implementation

uses ChatMainUnit;

{TReceiveThread}

// Сокет, получающий сообщения, создается в главной нити,

// а сюда передаётся через параметр конструктора

constructor TReceiveThread.Create(ServerSocket: TSocket);

begin

 FSocket := ServerSocket;

 inherited Create(False);

end;

procedure TReceiveThread.Execute;

var

 // Буфер для получения сообщения.

 // Размер равен максимальному размеру UDP-дейтаграммы

 Buffer: array[0..65506] of Byte;

 // Адрес, с которого пришло сообщение

 RecvAddr: TSockAddr;

 RecvLen, AddrLen: Integer;

 Msg: string;

begin

Поделиться:
Популярные книги

Свадьба по приказу, или Моя непокорная княжна

Чернованова Валерия Михайловна
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Свадьба по приказу, или Моя непокорная княжна

Сборник коротких эротических рассказов

Коллектив авторов
Любовные романы:
эро литература
love action
7.25
рейтинг книги
Сборник коротких эротических рассказов

Отец моего жениха

Салах Алайна
Любовные романы:
современные любовные романы
7.79
рейтинг книги
Отец моего жениха

Вадбольский

Никитин Юрий Александрович
1. Вадбольский
Фантастика:
попаданцы
5.00
рейтинг книги
Вадбольский

Бастард Императора. Том 7

Орлов Андрей Юрьевич
7. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 7

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

В зоне особого внимания

Иванов Дмитрий
12. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
В зоне особого внимания

Таня Гроттер и магический контрабас

Емец Дмитрий Александрович
1. Таня Гроттер
Фантастика:
фэнтези
8.52
рейтинг книги
Таня Гроттер и магический контрабас

Бастард Императора. Том 2

Орлов Андрей Юрьевич
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 2

Кодекс Крови. Книга ХI

Борзых М.
11. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХI

Третий

INDIGO
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий

Возвышение Меркурия. Книга 16

Кронос Александр
16. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 16

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9

Потусторонний. Книга 1

Погуляй Юрий Александрович
1. Господин Артемьев
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Потусторонний. Книга 1