Читаем О чём не пишут в книгах по Delphi полностью

TTimeVal = record

 tv_sec: LongInt;

 tv_usec: LongInt;

end;

Эта структура служит для задания времени ожидания. Поле tv_sec содержит число полных секунд в этом интервале, поле tv_usec — число микросекунд. Так, чтобы задать интервал ожидания, равный 1,5 с, нужно присвоить полю tv_sec значение 1, а полю tv_usec — значение 500 000. Параметр timeout функции select должен содержать указатель на заполненную подобным образом структуру, определяющую, сколько времени функция будет ожидать, пока хотя бы один из сокетов не будет готов к требуемой операции. Если этот указатель равен nil, ожидание будет бесконечным.

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

Функция select позволяет дождаться, когда хотя бы один из сокетов, переданный в одном из множеств, будет готов к выполнению той или иной операции. Какой именно операции, определяется тем, в какое из трех множеств входит сокет. Для сокетов, входящих в множество readfds, готовность означает, что функции recv или recvfrom будут выполнены без блокирования. В случае UDP это означает, что во входном буфере сокета есть данные, которые можно прочитать. При использовании TCP функции recv и recvfrom могут быть выполнены без задержки еще в двух случаях: когда партнер закрыл соединение (в этом случае функции вернут 0), а также когда соединение некорректно разорвано (в этом случае функции вернут SOCKET_ERROR). Кроме того, если сокет, включенный в множество readfds, находится в состоянии ожидания соединения (в которое он переведен с помощью функции listen), то для него состояние готовности означает, что очередь соединений не пуста и функция accept будет выполнена без задержек.

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

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

И наконец, последнее множество exceptfds. Для сокетов, входящих в это множество, состояние готовности означает либо неудачу попытки соединения для неблокирующего сокета, либо получение высокоприоритетных данных (out-of-band data). В этой книге мы не будем детально рассматривать отправку и получение высокоприоритетных данных. Те, кому это понадобится, легко разберутся с этим вопросом по MSDN.

Функция select возвращает общее количество сокетов, находящихся в состоянии готовности. Если функция завершила работу по тайм-ауту, возвращается 0. Множества readfds, writefds и exceptfds модифицируются функцией: в них остаются только те сокеты, которые находятся в состоянии готовности. При вызове функции любые два из этих трех указателей могут быть равны nil, если программу не интересует готовность сокетов по соответствующим критериям. Один и тот же сокет может входить в несколько множеств.

В листинге 2.23 приведен пример кода TCP-сервера, взаимодействующего с несколькими клиентами в рамках одной нити и работающего по простой схеме "запрос-ответ".

Листинг 2.23. Пример сервера, использующего select

var

 Sockets: array of TSocket;

 Addr: TSockAddr;

 Data: TWSAData;

 Len, I, J: Integer;

 FDSet: TFDSet;

begin

 WSAStartup($101, Data);

 SetLength(Sockets, 1);

 Sockets[0]:= socket(AF_INET, SOCK_STREAM, 0);

 Addr.sin_family:= AF_INET;

Перейти на страницу:

Похожие книги

1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных