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

на главную - закладки

Жанры

О чём не пишут в книгах по 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 оставила сокет в множестве,

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

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

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

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

Сама себе хозяйка

Красовская Марианна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Сама себе хозяйка

Сердце Дракона. Том 11

Клеванский Кирилл Сергеевич
11. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
6.50
рейтинг книги
Сердце Дракона. Том 11

Первый среди равных. Книга IV

Бор Жорж
4. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Первый среди равных. Книга IV

Неучтенный. Дилогия

Муравьёв Константин Николаевич
Неучтенный
Фантастика:
боевая фантастика
попаданцы
7.98
рейтинг книги
Неучтенный. Дилогия

Мастер Разума IV

Кронос Александр
4. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума IV

Авиатор: назад в СССР

Дорин Михаил
1. Авиатор
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Авиатор: назад в СССР

Кадры решают все

Злотников Роман Валерьевич
2. Элита элит
Фантастика:
боевая фантастика
попаданцы
альтернативная история
8.09
рейтинг книги
Кадры решают все

Плеяда

Суконкин Алексей
Проза:
военная проза
русская классическая проза
5.00
рейтинг книги
Плеяда

Потусторонний. Книга 2

Погуляй Юрий Александрович
2. Господин Артемьев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Потусторонний. Книга 2

Ученик. Книга 4

Первухин Андрей Евгеньевич
4. Ученик
Фантастика:
фэнтези
5.67
рейтинг книги
Ученик. Книга 4

Законник Российской Империи. Том 3

Ткачев Андрей Юрьевич
3. Словом и делом
Фантастика:
городское фэнтези
альтернативная история
аниме
дорама
5.00
рейтинг книги
Законник Российской Империи. Том 3

Ваше Сиятельство 7

Моури Эрли
7. Ваше Сиятельство
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Ваше Сиятельство 7

Война

Валериев Игорь
7. Ермак
Фантастика:
боевая фантастика
альтернативная история
5.25
рейтинг книги
Война

Младший сын князя. Том 4

Ткачев Андрей Юрьевич
4. Аналитик
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Младший сын князя. Том 4