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

 Addr.sin_port:= htons(5514);

 Addr.sin_addr.S_addr:= INADDR_ANY;

 FillChar(Addr.sin_zero, SizeOf(Addr.sin_zero), 0);

 bind(Sockets[0], Addr, SizeOf(TSockAddr));

 listen(Sockets[0], SCMAXCONN);

 while True do

 begin

// 1. Формирование множества сокетов

 FD_ZERO(FDSet);

for I:= 0 to High(Sockets) do FDSET(Sockets[1], FDSet);

 // 2. Проверка готовности сокетов

 select(0, @FDSet, nil, nil, nil);

// 3. Чтение запросов клиентов тех сокетов, которые готовы к этому

 I:= 1;

while I <= High(Sockets) do

begin

if FD_ISSET(Sockets[I], FDSet) then if recv(Sockets[I]…) <= 0 then

 begin

// Связь разорвана, нужно закрыть сокет

 // и удалить его из массива

closesocket(Sockets[I]);

 for J:= I to High(Sockets) — 1 do Sockets[J]:= Sockets[J + 1];

 Dec(I);

SetLength(Sockets, Length(Sockets) -1);

 end

 else

 begin

// Получены данные от клиента, нужно ответить

 send(Sockets[I]…);

 end;

Inc(I);

 end;

 // 4. Проверка подключения нового клиента

 if FD_ISSET(Sockets[0], FDSet) then

 begin

 // Подключился новый клиент

SetLength(Sockets, Length(Sockets) + 1);

Len:= SizeOf(TSockAddr);

Sockets[High(Sockets)]:= accept(Sockets[0], @Addr, @Len)

 end;

 end;

end;

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

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

На первом шаге цикла создаётся множество сокетов, в которое добавляются все сокеты, содержащиеся в массиве. В этом месте в примере пропущена важная проверка того, что сокетов в массиве не больше 64-х. Если их будет больше, то попытки добавить лишние сокеты в множество будут проигнорированы функцией FD_SET и, соответственно, эти сокеты выпадут из дальнейшего рассмотрения, т. е. даже если клиент что-то пришлет, сервер этого не увидит. Решить проблему можно тремя способами. Самый простой — это отказывать в подключении лишним клиентам. Для этого сразу после вызова accept нужно вызывать для нового сокета closesocket. Второй способ — это увеличение количества сокетов в множестве, как это было описано ранее. В этом случае все равно остается та же проблема, хотя если сделать число сокетов в множестве достаточно большим, она практически исчезает. И наконец, можно разделить сокеты на несколько порций, для каждой из которых вызывать select отдельно. Это потребует усложнения примера, потому что сейчас в функции select мы используем бесконечное ожидание. При разбиении сокетов на порции это может привести к тому, что из-за отсутствия готовых сокетов в первой порции программа не сможет перейти к проверке второй порции, в которой готовые сокеты, может быть, есть. Пример разделения сокетов на порции будет рассмотрен в следующем разделе.

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

Move((PChar(Sockets) — 4)^, FDSet, Length(Sockets) * SizeOf(TSocket) + SizeOf(Integer));

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

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

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

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

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

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