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

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

Жанры

О чём не пишут в книгах по 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 в цикле до тех пор, пока из буфера не будет извлечена вся информация.

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

Неудержимый. Книга VIII

Боярский Андрей
8. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
6.00
рейтинг книги
Неудержимый. Книга VIII

Законы Рода. Том 6

Flow Ascold
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 6

Восход. Солнцев. Книга I

Скабер Артемий
1. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга I

Попаданка

Ахминеева Нина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка

Возлюби болезнь свою

Синельников Валерий Владимирович
Научно-образовательная:
психология
7.71
рейтинг книги
Возлюби болезнь свою

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

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

Ротмистр Гордеев 2

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

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

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

Адвокат Империи 3

Карелин Сергей Витальевич
3. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 3

Жребий некроманта 3

Решетов Евгений Валерьевич
3. Жребий некроманта
Фантастика:
боевая фантастика
5.56
рейтинг книги
Жребий некроманта 3

Город драконов

Звездная Елена
1. Город драконов
Фантастика:
фэнтези
6.80
рейтинг книги
Город драконов

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

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

Инквизитор Тьмы 2

Шмаков Алексей Семенович
2. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы 2

Беглец

Бубела Олег Николаевич
1. Совсем не герой
Фантастика:
фэнтези
попаданцы
8.94
рейтинг книги
Беглец