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

на главную

Жанры

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

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

Шрифт:
Примечание

Эта ситуация отличается от использования

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

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

на начало цикла (листинг 2.26).

Листинг 2.26. Основная часть сервера SelectServer

// Тайм-аут для функции select, хотя и передается через указатель,

// является для нее входным параметром, который не изменяется.

// Так как у нас везде будет использоваться один и тот же нулевой

// тайм-аут, можем один раз задать значение переменной Timeout

// и в дальнейшем всегда им пользоваться.

Timeout.tv_sec := 0;

Timeout.tv_usec := 0;

// Начало цикла подключения и общения с клиентами

repeat

 // Сначала проверяем, готов ли слушающий сокет.

 // Если он готов, это означает, что есть подключившийся,

 // но не обработанный функцией accept клиент

 FD_ZERO(SockSet);

 FD_SET(MainSocket, SockSet);

 if select(0, @SockSet, nil, nil, @Timeout) = SOCKET_ERROR then

raise ESocketException.Create('Ошибка при проверке готовности слушающего сокета: ' +

GetErrorString);

 // Если функция select оставила MainSocket в множестве, значит,

 // зафиксировано подключение клиента, и функция accept не приведет

 // к блокированию нити.

 if FD_ISSET(MainSocket, SockSet) then

 begin

ClientSockAddrLen := SizeOf(ClientSockAddr);

// Принимаем подключившегося клиента. Для общения с ним создается

// новый сокет, дескриптор которого помещается в ClientSocket.

ClientSocket :=

accept(MainSocket, @ClientSockAddr, @ClientSockAddrLen);

if ClientSocket = INVALID_SOCKET then raise

ESocketException.Create(

'Ошибка при ожидании подключения клиента: ' + GetErrorString);

// Создаем в динамической памяти новый экземпляр TConnection

// и заполняем его данными, соответствующими подключившемуся клиенту

New(NewConnection);

NewConnection.ClientSocket := ClientSocket;

NewConnection.ClientAddr :=

Format('%u.%u.%u.%u:%u',

Ord(ClientSockAddr.sin_addr.S_un_b.s_bl),

Ord(ClientSockAddr.sin_addr.S_un_b.s_b2),

Ord(ClientSockAddr.sin_addr.S_un_b.s_b3),

Ord(ClientSockAddr.sin_addr.S_un_b.s_b4),

ntohs(ClientSockAddr.sin_port));

NewConnection.Deleted := False;

//
Добавляем соединение в список

Connections.Add(NewConnection);

WriteLn(OemString('Зафиксировано подключение с адреса ' +

NewConnection.ClientAddr));

 end;

 // Теперь проверяем готовность всех сокетов подключившихся клиентов.

 // Так как множество SockSet не может содержать более чем FT_SETSIZE

 // элементов, а размер списка Connections мы нигде не ограничиваем,

 // приходится разбивать Connections на "куски" размером не более

 // FD_SETSIZE и обрабатывать этот список по частям.

 // Поэтому у нас появляется два цикла - внешний, который повторяется

 // столько раз, сколько у нас будет кусков, и внутренний, который

 // повторяется столько раз, сколько элементов в одном куске.

 for J := 0 to Ceil(Connections.Count, FD_SETSIZE) - 1 do

 begin

FD_ZERO(SockSet);

for I := FD_SETSIZE * J to Min(FD_SETSIZE * (J + 1) - 1, Connections.Count - 1) do

FD_SET(PConnection(Connections[I])^.ClientSocket, SockSet);

if select(0, @SockSet, nil, nil, @Timeout) = SOCKET_ERROR then

raise ESocketException.Create(

'Ошибка при проверке готовности сокетов: ' + GetErrorString);

// Проверяем, какие сокеты функция select оставила в множестве,

// и вызываем для них ProcessSocketMessage. В этом есть некоторый

// риск, т.к. для того, чтобы select оставила сокет в множестве,

// достаточно, чтобы он получил хотя бы один байт от клиента,

// а не все сообщение. Поэтому может возникнуть такая ситуация,

// когда сервер получил только часть сообщения, но уже пытается

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

Титан империи 2

Артемов Александр Александрович
2. Титан Империи
Фантастика:
фэнтези
боевая фантастика
аниме
5.00
рейтинг книги
Титан империи 2

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Ты нас предал

Безрукова Елена
1. Измены. Кантемировы
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Ты нас предал

Огни Аль-Тура. Желанная

Макушева Магда
3. Эйнар
Любовные романы:
любовно-фантастические романы
эро литература
5.25
рейтинг книги
Огни Аль-Тура. Желанная

Личник

Валериев Игорь
3. Ермак
Фантастика:
альтернативная история
6.33
рейтинг книги
Личник

Приручитель женщин-монстров. Том 14

Дорничев Дмитрий
14. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Приручитель женщин-монстров. Том 14

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

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

Вечный. Книга I

Рокотов Алексей
1. Вечный
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга I

Последний попаданец

Зубов Константин
1. Последний попаданец
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Последний попаданец

Найди меня Шерхан

Тоцка Тала
3. Ямпольские-Демидовы
Любовные романы:
современные любовные романы
короткие любовные романы
7.70
рейтинг книги
Найди меня Шерхан

Гром над Академией. Часть 2

Машуков Тимур
3. Гром над миром
Фантастика:
боевая фантастика
5.50
рейтинг книги
Гром над Академией. Часть 2

Имперец. Том 5

Романов Михаил Яковлевич
4. Имперец
Фантастика:
попаданцы
альтернативная история
аниме
6.00
рейтинг книги
Имперец. Том 5

Бастард

Осадчук Алексей Витальевич
1. Последняя жизнь
Фантастика:
фэнтези
героическая фантастика
попаданцы
5.86
рейтинг книги
Бастард

Метатель

Тарасов Ник
1. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель