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

на главную

Жанры

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

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

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

Описанный алгоритм разбора буфера прост, но неэффективен с точки зрения нагрузки на процессор и использования динамической памяти, особенно в тех случаях, когда в буфере

RecvBuf
оказывается сразу несколько строк. Это связано с тем, что при добавлении содержимого
RecvBuf
к
FRecvStr
и последующем поочередном удалении строк из
FRecvStr
происходит многократное перераспределение памяти, выделенной для строки. Алгоритм можно оптимизировать: все строки, которые поместились в
RecvBuf
целиком, выделять непосредственно из этого буфера, не помещая в
FRecvStr
, а помещать туда только то, что действительно нужно сохранить между обработкой разных событий
FD_READ
. Реализацию такого алгоритма рекомендуем выполнить в качестве самостоятельного упражнения.

При отправке данных вероятность того, что функция send не сможет быть выполнена сразу, достаточно мала. Кроме того, как мы уже говорили, блокировка клиента при отправке данных часто бывает вполне приемлема из-за редкости и непродолжительности. Таким образом, блокирующий режим из-за своей простоты наиболее удобен при отправке данных серверу клиентом. Но мы не можем перевести сокет, работающий в асинхронном режиме, в блокирующий режим на время отправки, зато можем этот режим имитировать. Занимается этим метод

SendString
(листинг 2.67).

Листинг 2.67. Метод
SendString
, имитирующий блокирующим режим отправки

// Отправка строки серверу. Функция имитирует блокирующий

// режим работы сокета: если за один раз не удается отправить

// данные, попытка отправить их продолжается до тех пор,.

// пока все данные не будут отправлены или пока не возникнет ошибка.

procedure TESClientForm.SendString(const S: string);

var

 SendRes: Integer;

 // Буфер, куда помещается отправляемое сообщение

 SendBuf: array of Byte;

 // Сколько байтов уже отправлено

 BytesSent: Integer;

begin

 if Length(S) > 0 then

 begin

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

// Выделяем для буфера память, достаточную для хранения

// и того и другого.

SetLength(SendBuf, SizeOf(Integer) + Length(S));

// Копируем в буфер длину строки

PInteger(@SendBuf[0])^ := Length(S);

// А затем - саму строку

Move(S[1], SendBuf[SizeOf(Integer)], Length(S));

BytesSent := 0;

// повторяем попытку отправить до тех пор, пока все содержимое

// буфера не будет отправлено серверу.

while BytesSent < Length(SendBuf) do

begin

SendRes :=

send(FSocket, SendBuf[BytesSent], Length(SendBuf) - BytesSent, 0);

if SendRes > 0 then Inc(BytesSent, SendRes)

else if WSAGetLastError = WSAEWOULDBLOCK then Sleep(10)

else

begin

MessageDlg('Ошибка
при отправке данных серверу'#13#10 +

GetErrorString, mtError, [mbOK], 0);

OnDisconnect;

Exit;

end;

end;

 end;

end;

Имитация блокирующего режима осуществляется очень просто: если сообщение не удалось отправить сразу, после небольшой паузы производится попытка отправить то, что ещё не отправлено, и так до тех пор, пока не будет отправлено все или пока не возникнет ошибка. В программе SimpleClient мы отправляли длину строки и саму строку разными вызовами

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

Примечание

Далее мы познакомимся с функцией

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

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

TEdit
на
TMemo
). При нажатии кнопки Отправить клиент отправляет серверу все непустые строки из этого поля ввода.

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

2.2.9. Перекрытый ввод-вывод

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

Самая простая модель ввода-вывода — блокирующая. В блокирующем режиме, если операция не может быть выполнена немедленно, работа нити приостанавливается до тех пор, пока не возникнут условия для выполнения операции. В неблокирующей модели ввода-вывода операция, которая не может быть выполнена немедленно, завершается с ошибкой. И наконец, в асинхронной модели ввода-вывода предусмотрена система уведомлений о том что операция может быть выполнена немедленно.

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

Возвышение Меркурия. Книга 12

Кронос Александр
12. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 12

Кодекс Охотника. Книга XXIV

Винокуров Юрий
24. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XXIV

Буря империи

Сай Ярослав
6. Медорфенов
Фантастика:
аниме
фэнтези
фантастика: прочее
эпическая фантастика
5.00
рейтинг книги
Буря империи

Месть за измену

Кофф Натализа
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Месть за измену

Деспот

Шагаева Наталья
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Деспот

Осознание. Пятый пояс

Игнатов Михаил Павлович
14. Путь
Фантастика:
героическая фантастика
5.00
рейтинг книги
Осознание. Пятый пояс

Тринадцатый VII

NikL
7. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Тринадцатый VII

Эра мангуста. Том 4

Третьяков Андрей
4. Рос: Мангуст
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эра мангуста. Том 4

Ветер перемен

Ланцов Михаил Алексеевич
5. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ветер перемен

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

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

На границе империй. Том 7

INDIGO
7. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
6.75
рейтинг книги
На границе империй. Том 7

Прометей: владыка моря

Рави Ивар
5. Прометей
Фантастика:
фэнтези
5.97
рейтинг книги
Прометей: владыка моря

Бракованная невеста. Академия драконов

Милославская Анастасия
Фантастика:
фэнтези
сказочная фантастика
5.00
рейтинг книги
Бракованная невеста. Академия драконов

Кодекс Охотника. Книга XXII

Винокуров Юрий
22. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Кодекс Охотника. Книга XXII