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

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

Жанры

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

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

Шрифт:
Листинг 2.49. Пример простого сервера на асинхронных сокетах

unit Unit1;

interface

uses

 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, WinSock;

const

 WM_SOCKETEVENT = WM_USER + 1;

type

 TForm1 = class(TForm)

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObjеct);

 private

ServSock: TSocket;

procedure WMSocketEvent(var Msg: TMessage); message WM_SOCKETEVENT;

 end;

var

 Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);

var

 Data: TWSAData;

 Addr: TSockAddr;

begin

 WSAStartup($101, Data);

 //
Обычная последовательность действий по созданию сокета,

 // привязке его к адресу и установлению на прослушивание

 ServSock := socket(AF_INET, SOCK_STREAM, 0);

 Addr.sin_family := AF_INET;

 Addr.sin_addr.S_addr := INADDR_ANY;

 Addr.sin_port := htons(3320);

 FillChar(Addr.sin_zero, SizeOf(Addr.sin_zero), 0);

 bind(ServSock, Addr, SizeOf(Addr));

 listen(ServSock, SOMAXCONN);

 // Перевод сокета в асинхронный режим. Кроме события FD_ACCEPT

 // указаны также события FD_READ и FD_CLOSE, которые никогда не

 // возникают на сокете, установленном в режим прослушивания.

 // Это сделано потому, что сокеты, созданные с помощью функции

 // accept, наследуют асинхронный режим, установленный для

 // слушающего сокета. Таким образом, не придется вызывать

 // функцию WSAAsyncSelect для этих сокетов - для них сразу

 // будет назначен обработчик событий FD_READ и FD_CLOSE.

 WSAAsyncSelect(ServSock, Handle, WM_SOCKETEVENT, FD_READ or FD_ACCEPT or FD_CLOSE);

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

 closesocket(ServSock);

 WSACleanup;

end;

procedure TForm1.WMSocketEvent(var Msg: TMessage);

var

 Sock: TSocket;

 SockError: Integer;

begin

 Sock := TSocket(Msg.WParam);

 SockError := WSAGetSelectError(Msg.lParam);

 if SockError <> 0 then

 begin

//
Здесь должен быть анализ ошибки

closesocket(Sock);

Exit;

 end;

 case WSAGetSelectEvent(Msg.lParam) of

 FD_READ: begin

// Пришел запрос от клиента. Необходимо прочитать данные,

// сформировать ответ и отправить его.

 end;

 FD_АССЕРТ: begin

// Просто вызываем функция accept. Ее результат нигде не

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

// начинает работать в асинхронном режиме, и его дескриптор

// при необходимости будет передан через Msg.wParam при

// возникновение события

accept(Sock, nil, nil);

 end;

 FD_CLOSE:

 begin

// Получив от клиента сигнал завершения, сервер, в принципе,

// может попытаться отправить ему данные. После этого сервер

// также должен закрыть соединение со своей стороны

shutdown(Sock, SD_SEND);

closesocket(Sock);

 end;

 end;

end;

end.

Преимущество такого сервера по сравнению с сервером, основанным на функции

select
, заключается в том, что он не должен постоянно проверять наличие полученных данных — когда данные поступят, он без дополнительных усилий получит уведомление об этом. Кроме того, этот сервер не имеет проблем, связанных с количеством сокетов в множестве типа
TFDSet
. Впрочем, последнее несущественно, т.к. при таком количестве клиентов сервер обычно реализует другие, более производительные способы взаимодействия с клиентами.

2.2.6. Пример сервера, основанного на сообщениях

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

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

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

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Бывшие. Война в академии магии

Берг Александра
2. Измены
Любовные романы:
любовно-фантастические романы
7.00
рейтинг книги
Бывшие. Война в академии магии

Мастер клинков. Начало пути

Распопов Дмитрий Викторович
1. Мастер клинков
Фантастика:
фэнтези
9.16
рейтинг книги
Мастер клинков. Начало пути

Имя нам Легион. Том 8

Дорничев Дмитрий
8. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 8

Измена. Право на счастье

Вирго Софи
1. Чем закончится измена
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на счастье

Начальник милиции 2

Дамиров Рафаэль
2. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции 2

Камень. Книга 4

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

Измена. Мой заклятый дракон

Марлин Юлия
Любовные романы:
любовно-фантастические романы
7.50
рейтинг книги
Измена. Мой заклятый дракон

Предатель. Цена ошибки

Кучер Ая
Измена
Любовные романы:
современные любовные романы
5.75
рейтинг книги
Предатель. Цена ошибки

Звездная Кровь. Изгой

Елисеев Алексей Станиславович
1. Звездная Кровь. Изгой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Изгой

Рождение победителя

Каменистый Артем
3. Девятый
Фантастика:
фэнтези
альтернативная история
9.07
рейтинг книги
Рождение победителя

Барону наплевать на правила

Ренгач Евгений
7. Закон сильного
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Барону наплевать на правила

Камень. Книга шестая

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

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь