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

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

Жанры

О чём не пишут в книгах по 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

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

Право налево

Зика Натаэль
Любовные романы:
современные любовные романы
8.38
рейтинг книги
Право налево

Третий. Том 2

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

Гром над Империей. Часть 2

Машуков Тимур
6. Гром над миром
Фантастика:
фэнтези
попаданцы
5.25
рейтинг книги
Гром над Империей. Часть 2

Сама себе хозяйка

Красовская Марианна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Сама себе хозяйка

Бальмануг. Невеста

Лашина Полина
5. Мир Десяти
Фантастика:
юмористическое фэнтези
5.00
рейтинг книги
Бальмануг. Невеста

Аромат невинности

Вудворт Франциска
Любовные романы:
любовно-фантастические романы
эро литература
9.23
рейтинг книги
Аромат невинности

Чемпион

Демиров Леонид
3. Мания крафта
Фантастика:
фэнтези
рпг
5.38
рейтинг книги
Чемпион

Эксперимент

Юнина Наталья
Любовные романы:
современные любовные романы
4.00
рейтинг книги
Эксперимент

Небо для Беса

Рам Янка
3. Самбисты
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Небо для Беса

Идеальный мир для Социопата 7

Сапфир Олег
7. Социопат
Фантастика:
боевая фантастика
6.22
рейтинг книги
Идеальный мир для Социопата 7

Я не князь. Книга XIII

Дрейк Сириус
13. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я не князь. Книга XIII

Камень. Книга пятая

Минин Станислав
5. Камень
Фантастика:
боевая фантастика
6.43
рейтинг книги
Камень. Книга пятая

Романов. Том 1 и Том 2

Кощеев Владимир
1. Романов
Фантастика:
фэнтези
попаданцы
альтернативная история
5.25
рейтинг книги
Романов. Том 1 и Том 2

Ваше Сиятельство 4т

Моури Эрли
4. Ваше Сиятельство
Любовные романы:
эро литература
5.00
рейтинг книги
Ваше Сиятельство 4т