О чём не пишут в книгах по Delphi
Шрифт:
Параметр
lpOverlapped
функции AcceptEx
не может быть равным -1, а его поле hEvent
должно указывать на корректное событие. Процедуры завершения не предусмотрены. Если на момент вызова функции клиент уже подключился и прислал первую порцию данных (или место для данных в буфере не зарезервировано), AcceptEx
возвращает True
. Если же клиент еще не подключился, или подключился, но не прислал данные, функция AcceptEx
возвращает False
, а WSAGetLastError
— ERROR_IO_PENDING
. Параметр lpBytesReceived
Проконтролировать состояние операции можно с помощью функции
GetOverlappedResult
, которая является аналогом известной нам функции WSAGetOverlappedResult
, за исключением того, что использует запись TOverlapped
вместо TWSAOverlapped
и не предусматривает передачу флагов. С ее помощью можно узнать, завершилась ли операция, а также дождаться ее завершения и узнать, сколько байтов прислано клиентом (функция AcceptEx
не ждет, пока клиент заполнит весь буфер, предназначенный для него — для завершения операции подключения достаточно первого пакета). Если к серверу подключаются некорректно работающие клиенты, которые не присылают данные после подключения, операция может не завершаться очень долго, что будет мешать подключению новых клиентов. MSDN рекомендует при ожидании время от времени с помощью функции
getsockopt
для сокета sAcceptSocket
узнавать значение целочисленного параметра SO_CONNECT_TIME
уровня SOL_SOCKET
. Этот параметр показывает время в секундах, прошедшее с момента подключения клиента к данному сокету (или -1, если подключения не было). Если подключившийся клиент слишком долго не присылает данных, сокет sAcceptSocket
следует закрыть, что приведет к завершению операции, начатой AcceptEx
, с ошибкой. После этого можно снова вызывать AcceptEx
для приема новых клиентов. Функция
AcceptEx
реализована таким образом, чтобы обеспечивать максимальную скорость подключения. Ранее мы говорили, что сокеты, созданные функциями accept
и WSAAccept
, наследуют параметры слушающего сокета (например, свойства асинхронного режима). Для повышения производительности сокет sAcceptSocket
по умолчанию не получает свойств сокета sListenSocket
. Но он может унаследовать их после завершения операции с помощью следующей установки параметра сокета SO_UPDATE_ACCEPT_CONTEXT
: setsockopt(sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, PChar(@sListenSocket), SizeOf(sListenSocket));
Ha сокет
sAcceptedSocket
после его подключения к клиенту накладываются ограничения: он может использоваться не во всех функциях WinSock, а только в следующих: send
, WSASend
, recv
, WSARecv
, ReadFile
, WriteFile
, TransmitFile
, closesocket
и setsockopt
, причем в последней — только для установки параметра SO_UPDATE_ACCEPT_CONTEXT
. В WinSock не документируется, в какую именно часть буфера помещаются адрес клиента и принявшего его сокета. Вместо этого предоставляется функция
GetAcceptExSockAddrs
, прототип которой приведен в листинге 2.83. Листинг 2.83. Функция
GetAcceptExSockAddrs
procedure GetAcceptExSockAddrs(lpOutputBuffer: Pointer; dwReceiveDataLength: DWORD; dwLocalAddressLength: DWORD; dwRemoteAddressLength: DWORD; var LocalSockaddr: PSockAddr; var LocalSockaddrLength: Integer; var RemoteSockaddr: PSockAddr; var RemoteSockaddrLength: Integer);
Примечание
В Delphi
LocalSockaddr
и RemoteSockaddr
функции GetAcceptExSockAddrs
имеют в нем тип TSockAddr
вместо PSockAddr
. Из-за этой ошибки функцию GetAcceptExSockAddrs
в этих версиях Delphi необходимо самостоятельно импортировать. Следует заметить, что во многих модулях для WinSock 2 от независимых разработчиков объявление этой функции скопировано из стандартного модуля вместе с ошибкой. Первые четыре параметра функции
GetAcceptExSockAddrs
определяют буфер, в котором в результате вызова AcceptEx
оказались данные от клиента и адреса, и размеры частей буфера, зарезервированных для данных и для адресов. Значения этих параметров должны совпадать со значениями аналогичных параметров в соответствующем вызове AcceptEx
. Через параметр LocalSockaddrs
возвращается указатель на то место в буфере, в котором хранится адрес привязки сокета sAcceptSocket
, а через параметр LocalSockaddrsLength
— длина адреса (16 в случае TCP). Адрес клиента и его длина возвращаются через параметры RemoteSockaddrs
и RemoteSockaddrsLength
. Следует особенно подчеркнуть, что указатели LocalSockaddrs
и RemoteSockaddrs
указывают именно на соответствующие части буфера: память для них специально не выделяется и, следовательно, не должна освобождаться, а свою актуальность они теряют при освобождении буфера. Последняя из дополнительных функций,
TransmitFile
, служит для передачи файлов по сети. Ее прототип приведен в листинге 2.84. Листинг 2.84. Функция
TransmitFile
function TransmitFile(hSocket: TSocket; hFile: THandle; nNumberOfBytesToWrite, nNumberOfBytesPerSend: DWORD; lpOverlapped: POverlapped; lpTransmitBuffers: PTransmitFileBuffers; dwReserved: DWORD): BOOL;
Функция
TransmitFile
отправляет содержимое указанного файла через указанный сокет. При этом допускаются только протоколы, поддерживающие соединение, т.е. использовать данную функцию с UDP-сокетом нельзя. Сокет задается параметром hSocket
, файл — параметром hFile
. Дескриптор файла обычно получается с помощью функции стандартного API CreateFile
. Файл рекомендуется открывать с флагом FILE_FLAG_SEQUENTIAL_SCAN
, т.к. это повышает производительность. Параметр
nNumberOfBytesToWrite
определяет, сколько байтов должно быть передано (позволяя, тем самым, передавать не весь файл, а только его часть). Если этот параметр равен нулю, передается весь файл. Функция
TransmitFile
кладет данные из файла в буфер сокета по частям. Параметр nNumberOfBytesPerSend
определяет размер одной порции данных. Он может быть равен нулю — в этом случае система сама определяет размер порции. Этот параметр критичен только в случае дейтаграммных протоколов, потому что при этом размер порции определяет размер дейтаграммы. Для TCP данные, хранящиеся в буфере, передаются в сеть целиком или по частям в зависимости от загрузки сети, готовности принимающей стороны и т.п., а какими порциями они попали в буфер, на размер пакета почти не влияет. Поэтому для TCP-сокета параметр nNumberOfBytesPerSend
лучше установить равным нулю.
Поделиться:
Популярные книги
Измена. Тайный наследник
1. Тайный наследник
Фантастика:
фэнтези
5.00
рейтинг книги
Инквизитор Тьмы
1. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Наследник
3. Династия
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Ротмистр Гордеев 3
3. Ротмистр Гордеев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
(Не)нужная жена дракона
5. Хроники Драконьей империи
Любовные романы:
любовно-фантастические романы
6.89
рейтинг книги
Идеальный мир для Лекаря 28
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Сыночек в награду. Подари мне любовь
1. Суровые отцы
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Инквизитор Тьмы 2
2. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Генерал Скала и ученица
2. Генерал Скала и Лидия
Любовные романы:
любовно-фантастические романы
6.30
рейтинг книги
Искатель 1
1. Валинор
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Сердце Дракона. Том 10
10. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.14
рейтинг книги
Печать мастера
6. Гибрид
Фантастика:
попаданцы
технофэнтези
аниме
фэнтези
6.00
рейтинг книги
Выстрел на Большой Морской
4. Сыщик Его Величества
Детективы:
исторические детективы
полицейские детективы
8.64
рейтинг книги
Кодекс Крови. Книга VII
7. РОС: Кодекс Крови
Фантастика:
боевая фантастика
попаданцы
аниме
5.00