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

на главную

Жанры

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

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

Шрифт:

При задании аргумента

FIONBIO
параметр
arg
рассматривается как входной. Если его значение равно нулю, сокет будет переведен в блокирующий режим, если не равно нулю — в неблокирующий. Таким образом, чтобы перевести который сокет
s
в неблокирующий режим, нужно выполнить следующие действия (листинг 2.28).

Листинг 2.28. Перевод сокета в неблокирующий режим

var

 S: TSocket;

 Arg: u_long;

begin

 ...

 Arg := 1;

 ioctlsocket(S, FIONBIO, Arg);

Пока

программа использует только стандартные сокеты (а не сокеты Windows), сокет может быть переведен в неблокирующий или обратно в блокирующий режим в любой момент. Неблокирующим может быть сделан любой сокет (серверный или клиентский) независимо от протокола.

Функция

ioctlsocket
возвращает нулевое значение в случае успеха и ненулевое — при ошибке. В примере, как всегда, проверка результата для краткости опущена.

Итак, по умолчанию сокет работает в блокирующем режиме. С особенностями работы функций

accept
,
connect
,
recv
и
send
в этом режиме мы уже познакомились. Теперь рассмотрим то, как они ведут себя в неблокирующем режиме. Для этого сначала вспомним, когда эти функции блокируют вызвавшую их нить.

□ 

accept
— блокирует нить, если на момент ее вызова очередь подключений пуста. 

□ 

connect
— в случае TCP блокирует сокет практически всегда, потому что требуется время на установление связи с удаленным сокетом. Без блокирования вызов
connect
выполняется только в том случае, если какая-либо ошибка не дает возможности приступить к операции установления связи. Также без блокирования функция connect выполняется при использовании UDP, потому что в данном случае она только устанавливает фильтр для адресов.

□ 

recv
— блокирует нить, если на момент вызова входной буфер сокета пуст.

□ 

send
блокирует нить, если в выходном буфере сокета недостаточно места, чтобы скопировать туда переданную информацию.

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

WSAGetLastError
. Если она вернет
WSAEWOULDBLOCK
, значит, никакой ошибки не было, но выполнение операции без блокирования невозможно. Закрывать сокет и создавать новый после
WSAEWOULDBLOCK
, разумеется, не нужно, т.к. ошибки не было, и связь (в случае TCP) осталась неразорванной.

Следует отметить, что при нулевом выходном буфере сокета (т.е. когда функция

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

Для функций

accept
,
recv
и
send
WSAEWOULDBLOCK
означает, что операцию следует повторить через некоторое время, и, может быть, в следующий раз она не потребует блокирования и будет выполнена. Функция
connect
в этом случае начинает фоновую работу по установлению соединения. О завершении этой работы можно судить по готовности сокета, которая проверяется с помощью функции
select
. Листинг 2.29 иллюстрирует это.

Листинг 2.29. Установление связи при использовании неблокирующего сокета

var

 S: TSocket;

 Block: u_long;

 SetW, SetE: TFDSet;

begin

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

 ...

 Block := 1;

 ioctlsocket(S, FIONBIO, Block);

 connect(S, ...);

 if WSAGetLastError <> WSAEWOULDBLOCK then

 begin

// Произошла ошибка

raise ...

 end;

 FD_ZERO(SetW);

 FD_SET(S, SetW);

 FD_ZERO(SetE);

 FD_SET(S, SetE);

 select(0, nil, @SetW, @SetE, nil);

 if FD_ISSET(S, SetW) then

// Connect выполнен успешно

 else if FD_ISSET(S, SetE) then

// Соединиться не удалось

 else

// Произошла еще какая-то ошибка

Напомним, что сокет, входящий в множество

SetW
, будет считаться готовым, если он соединен, а в его выходном буфере есть место. Сокет, входящий в множество
SetE
, будет считаться готовым, если попытка соединения не удалась. До тех пор, пока попытка соединения не завершилась (успехом или неудачей), ни одно из этих условий готовности не будет выполнено. Таким образом, в данном случае
select
завершит работу только после того, как будет выполнена попытка соединения, и о результатах этой попытки можно будет судить по тому, в какое из множеств входит сокет.

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

connect
и
select
программа может выполнить какую-либо полезную работу, а в случае блокирующего сокета программа будет вынуждена сначала дождаться завершения работы функции connect и лишь потом сделать что-то еще. 

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

Пропала, или Как влюбить в себя жену

Юнина Наталья
2. Исцели меня
Любовные романы:
современные любовные романы
6.70
рейтинг книги
Пропала, или Как влюбить в себя жену

Адепт: Обучение. Каникулы [СИ]

Бубела Олег Николаевич
6. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.15
рейтинг книги
Адепт: Обучение. Каникулы [СИ]

Калибр Личности 1

Голд Джон
1. Калибр Личности
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Калибр Личности 1

У врага за пазухой

Коваленко Марья Сергеевна
5. Оголенные чувства
Любовные романы:
остросюжетные любовные романы
эро литература
5.00
рейтинг книги
У врага за пазухой

Бракованная невеста. Академия драконов

Милославская Анастасия
Фантастика:
фэнтези
сказочная фантастика
5.00
рейтинг книги
Бракованная невеста. Академия драконов

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

Кронос Александр
2. Меркурий
Фантастика:
фэнтези
5.00
рейтинг книги
Возвышение Меркурия. Книга 2

Наследник павшего дома. Том II

Вайс Александр
2. Расколотый мир [Вайс]
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Наследник павшего дома. Том II

Попаданка в академии драконов 2

Свадьбина Любовь
2. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
6.95
рейтинг книги
Попаданка в академии драконов 2

Теневой путь. Шаг в тень

Мазуров Дмитрий
1. Теневой путь
Фантастика:
фэнтези
6.71
рейтинг книги
Теневой путь. Шаг в тень

Архил...? Книга 2

Кожевников Павел
2. Архил...?
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Архил...? Книга 2

Искатель. Второй пояс

Игнатов Михаил Павлович
7. Путь
Фантастика:
фэнтези
боевая фантастика
6.11
рейтинг книги
Искатель. Второй пояс

Решала

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

70 Рублей - 2. Здравствуй S-T-I-K-S

Кожевников Павел
Вселенная S-T-I-K-S
Фантастика:
боевая фантастика
постапокалипсис
5.00
рейтинг книги
70 Рублей - 2. Здравствуй S-T-I-K-S

Не верь мне

Рам Янка
7. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Не верь мне