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

Если на момент вызова функции accept очередь соединений пуста, то нить, вызвавшая ее, блокируется до тех пор, пока какой-либо клиент не подключится к серверу. С одной стороны, это удобно: сервер может не вызывать функцию accept в цикле до тех пор, пока она не завершится успехом, а вызвать ее один раз и ждать, когда подключится клиент. С другой стороны, это создает проблемы тем серверам, которые должны взаимодействовать с несколькими клиентами. Действительно, пусть функция accept успешно завершилась и в распоряжении программы оказались два сокета: находящийся в режиме ожидания новых подключений и созданный для обслуживания уже существующего подключения. Если вызвать accept, то программа не сможет продолжить работу до тех пор, пока не подключится еще один клиент, а это может произойти через очень длительный промежуток времени или вообще никогда не случится. Из-за этого программа не сможет обрабатывать вызовы уже подключившегося клиента. С другой стороны, если функцию acсept не вызывать, сервер не сможет обнаружить подключение новых клиентов. Средства для решения этой проблемы есть как у стандартных сокетов, так и у сокетов Windows, и далее мы их рассмотрим. Но существует довольно популярный способ ее решения средствами не библиотеки сокетов, а операционной системы. Он заключается в использовании отдельной нити для обслуживания каждого из клиентов. Каждый раз, когда клиент подключается, функция accept передает управление программе, возвращая новый сокет. Здесь сервер может породить новую нить, которая предназначена исключительно для обмена данными с новым клиентом. Старая нить после этого снова вызывает accept для старого сокета, а новая — функции recv и send для нового сокета. Такой метод решает заодно и проблемы, связанные с тем, что функции send и recv также могут блокировать работу программы и помешать обмену данными с другими клиентами. В данном случае будет блокирована только одна нить, обменивающаяся данными с одним из клиентов, а остальные нити продолжат свою работу. Далее мы рассмотрим пример сервера, работающего по такой схеме.

Рис. 2.3. Последовательность действий клиента и сервера при использовании TCP

То, что функция recv может возвратить только часть ожидаемого пакета, обычно вызывает трудности, поэтому здесь мы рассмотрим один из вариантов написания функции (назовем ее ReadFromSocket), которая эти проблемы решает (листинг 2.13). Суть этой функции в том, что она вызывает recv до тех пор, пока не будет получено требуемое количество байтов или пока не возникнет ошибка. Тот код, который получает и анализирует приходящие данные, использует уже не recv, a ReadFromSocket, которая гарантирует, что будет возвращено столько байтов, сколько требуется.

Листинг 2.13. Функция ReadFromSocket, читающая из буфера сокета заданное количество байтов

// Функция читает Cnt байтов в буфер Buffer из сокета S

// Учитывается, что может потребоваться несколько операций чтения,

// прежде чем будет прочитано нужное число байтов.

// Возвращает:

// 1 — в случае успешного чтения

// 0 — в случае корректного закрытия соединения удаленной стороной

// -1 — в случае ошибки чтения

function ReadFromSocket(S: TSocket; var Buffer; Cnt: Integer): Integer;

var

 Res, Total: Integer;

begin

 // Total содержит количество принятых байтов

 Total:= 0;

 // Читаем байты в цикле до тех пор, пока не будет прочитано Cnt байтов

 repeat

 // На каждой итерации цикла нам нужно прочитать

 // не более чем Cnt — Total байтов, т. е. не более

 // чем нужное количество минус то, что уже прочитано

 // на предыдущих итерациях. Очередную порцию данных

 // помещаем в буфер со смещением Total.

 Res:= recv(S, (PChar(@Buffer) + Total)^, Cnt — Total, 0);

 if Res = 0 then

 begin

// Соединение закрыто удаленной стороной

 Result:= 0;

 Exit;

 end;

 if Res < 0 then

 begin

// Произошла ошибка при чтении

 Result:= -1;

 Exit;

 end;

 Inc(Total, Res);

 until Total >= Cnt;

 Result:= 1;

end;

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

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

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

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

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

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