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

на главную

Жанры

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

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

Шрифт:

// прочитать сообщение целиком. Это приведет к блокированию нити,

// но вероятность блокирования на долгое время мы оцениваем как

// крайне низкую, т.к. оставшаяся часть сообщения, скорее всего,

// придет достаточно быстро, и поэтому идем на такой риск.

for I := FD_SETSIZE * J to Min(FD_SETSIZE * (J + 1) - 1, Connections.Count - 1) do

if FD_ISSET(PConnection(Connections[I])^.ClientSocket, SockSet) then

ProcessSocketMessage(PConnection(Connections[I])^);

 end;

 //
Проверяем поле Deleted у всех соединений. Те, у которых

 // оно равно True, закрываем: закрываем сокет, освобождаем память,

 // удаляем указатель из списка. Цикл идет с конца списка к началу,

 // потому что в ходе работы цикла верхняя граница списка

 // может меняться, и цикл for снизу вверх мог бы привести

 // к появлению индексов вне диапазона.

 for I := Connections.Count - 1 downto 0 do

if PConnection(Connections[I])^.Deleted then

begin

closesocket(PConnection(Connections[I])^.ClientSocket);

Dispose(PConnection(Connections[I]));

Connections.Delete(I);

end;

 Sleep(100);

until False;
 

Функции

Ceil
и
Min
, которые встречаются здесь, можно было бы заменить одноимёнными функциями из модуля
Math
. Но этот модуль входит не во все варианты поставки Delphi, и чтобы пример можно было откомпилировать в любом варианте поставки Delphi, мы описали их здесь самостоятельно (листинг 2.27).

Листинг 2.27. Функции
Ceil
и
Min

// Функция Ceil возвращает наименьшее целое число X, удовлетворяющее

// неравенству X >= А / В

function Ceil(A, B: Integer): Integer;

begin

 Result := A div B;

 if A mod В <> 0 then Inc(Result);

end;

// Функция Min возвращает меньшее из двух чисел

function Min(А, В: Integer): Integer;

begin

 if A < В then Result := A

 else Result := B;

end;

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

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

Примечание

Многонитевой сервер в этом отношении надежнее: некорректное сообщение клиента заблокирует только ту нить, которая

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

Сделать сервер более устойчивым к некорректным действиям клиента можно, если каждый раз читать ровно столько байтов, сколько пришло. Это усложнит сервер, т.к. придется между "сеансами связи с клиентом" помнить сколько байтов было прочитано в прошлый раз. Однако это поможет полностью избежать блокировок при операциях чтения, что существенно повысит надежность сервера. В этом разделе мы не будем рассматривать соответствующий пример, а реализуем эту возможность в следующем сервере, использующем неблокирующие сокеты. В сервере на основе

select
это делается совершенно аналогично.

2.1.15. Неблокирующий режим

Ранее мы столкнулись с функциями, которые могут надолго приостановить работу вызвавшей их нити, если действие не может быть выполнено немедленно. Это функции

accept
,
recv
,
recvfrom
,
send
,
sendto
и
connect
дальнейшем в этом разделе мы не будем упоминать функции
recvfrom
и
sendto
, потому что они в смысле блокирования эквивалентны функциям
recv
и
send
соответственно, и все, что будет здесь сказано о
recv
и
send
, применимо к
recvfrom
и
sendto
). Такое поведение не всегда удобно вызывающей программе, поэтому в библиотеке сокетов предусмотрен особый режим работы сокетов — неблокирующий. Этот режим может быть установлен или отменен дм каждого сокета индивидуально с помощью функции
ioctlsocket
, имеющей следующий прототип:

function ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;

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

ioctlsocket
. Ее параметр
cmd
определяет действие, которое выполняет функция, а также смысл параметра
arg
. Допустимы три значения параметра
cmd
:
SIOCATMARK
,
FIONREAD
и
FIONBIO
. При задании
SIOCATMARK
параметр
arg
рассматривается как выходной: в нем возвращается ноль, если во входном буфере сокета имеются высокоприоритетные данные, и ненулевое значение, если таких данных нет (как уже было оговорено, мы в этой книге не будем касаться передачи высокоприоритетных данных). 

При

cmd
, равном
FIONREAD
, в параметре
arg
возвращается размер данных, находящихся во входном буфере сокета, в байтах. При использовании TCP это число равно максимальному количеству информации, которое можно получить на данный момент за один вызов
recv
. Для UDP это значение равно суммарному размеру всех находящихся в буфере дейтаграмм (напомним, что прочитать несколько дейтаграмм за один вызов
recv
нельзя). Функция
ioctlsocket
с параметром
FIONREAD
может использоваться для проверки наличия данных с целью избежать вызова recv тогда, когда это может привести к блокированию, или для организации вызова recv в цикле до тех пор, пока из буфера не будет извлечена вся информация.

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

Внешняя Зона

Жгулёв Пётр Николаевич
8. Real-Rpg
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Внешняя Зона

Князь

Мазин Александр Владимирович
3. Варяг
Фантастика:
альтернативная история
9.15
рейтинг книги
Князь

Путь Чести

Щукин Иван
3. Жизни Архимага
Фантастика:
фэнтези
боевая фантастика
6.43
рейтинг книги
Путь Чести

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

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

Школа. Первый пояс

Игнатов Михаил Павлович
2. Путь
Фантастика:
фэнтези
7.67
рейтинг книги
Школа. Первый пояс

Наследник и новый Новосиб

Тарс Элиан
7. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник и новый Новосиб

Бестужев. Служба Государевой Безопасности. Книга третья

Измайлов Сергей
3. Граф Бестужев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга третья

По дороге пряностей

Распопов Дмитрий Викторович
2. Венецианский купец
Фантастика:
фэнтези
героическая фантастика
альтернативная история
5.50
рейтинг книги
По дороге пряностей

Начальник милиции. Книга 3

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

Убивать, чтобы жить

Бор Жорж
1. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать, чтобы жить

Измена. Осколки чувств

Верди Алиса
2. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Осколки чувств

Ведьма

Резник Юлия
Любовные романы:
современные любовные романы
эро литература
8.54
рейтинг книги
Ведьма

Темный Патриарх Светлого Рода 6

Лисицин Евгений
6. Темный Патриарх Светлого Рода
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода 6

Светлая ведьма для Темного ректора

Дари Адриана
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Светлая ведьма для Темного ректора