Ранее уже обсуждалось, что функция connect
на стороне клиента считается успешно завершенной тогда, когда соединение встало в очередь, а не тогда, когда оно реально принято сервером через функцию accept
. По умолчанию для клиента, соединение с которым сервер отклонил, нет разницы, вызвал ли сервер функцию WSAAccept
и сразу отклонил соединение, или установил его с помощью accept
, а потом разорвал. В обоих случаях клиент сначала получит информацию об успешном соединении с сервером, а потом это соединение будет разорвано. Но при использовании WSAAccept
можно установить такой режим работы, когда сначала выполняется функция. заданная параметром lpCondition
, и лишь потом клиенту отправляется разрешение или запрет на подключение. Включается этот режим установкой параметра слушающего сокета SO_CONDITIONAL_ACCEPT
, что иллюстрирует листинг 2.42.
Листинг 2.42. Включение режима ожидания реального подключения
var
Cond: BOOL;
begin
Cond := True;
setsockopt(S, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, PChar(@Cond), SizeOf(Cond));
Этот режим снижает нагрузку на сеть и повышает устойчивость сервера против DoS-атак, заключающихся в многократном подключении-отключении посторонних клиентов, поэтому в серьезных серверах рекомендуется использовать эту возможность.
Из сказанного следует, что при использовании протокола TCP функция WSAAccept
по сравнению с accept даёт два принципиальных преимущества: позволяет управлять качеством обслуживания и запрещать подключение нежелательных клиентов.
Некоторые протоколы поддерживают передачу информации не только при установлении связи, но и при её завершении. Для таких протоколов в WinSock2 предусмотрены функции WSASendDisconnect
и WSARecvDisconnect
. Так как протокол TCP не поддерживает передачу данных при закрытии соединения, для него эти функции не дают никаких преимуществ по сравнению с вызовом функции shutdown
, поэтому мы не будем их здесь рассматривать.
Далее мы рассмотрим несколько новых функций, унифицирующих работу с различными протоколами.
Функция inet_addr
, как это уже упоминалось, жестко связана с протоколом IP и не имеет смысла для других протоколов. WinSock 2 предлагает вместо нее функцию WSAStringToAddress
, имеющую следующий прототип (листинг 2.43).
Листинг 2.43. Функция WSAStringToAddress
// ***** Описание на C++ *****
INT WSAStringToAddress(LPTSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFO lpProtocolInfo, LPSOCKADDR lpAddress, LPINT lpAddressLength);
// ***** Описание на Delphi *****
function WSAStringToAddress(AddresString: PChar; AddressFamily: Integer; lpProtocolInfo: PWSAProtocolInfo; var Address: TSockAddr; var AddressLength: Integer): Integer;
Данная функция преобразует строку, задающую адрес сокета, в адрес, хранящийся в структуре TSockAddr
. Параметр AddressString
указывает на строку, хранящую адрес, параметр AddressFamily
— на семейство адресов, для которого осуществляется трансляция. Если есть необходимость выбрать конкретный провайдер для протокола, в функцию может быть передан параметр lpProtocolInfo
, в котором указан идентификатор провайдера. Если же программу устраивает провайдер по умолчанию, параметр lpProtocolInfo
должен быть равен nil
. Адрес возвращается через параметр Address
. Параметр AddressLength
при вызове функции должен содержать размер буфера, переданного через Address
, а на выходе содержит реально использованное число байтов в буфере.
Функция возвращает 0 в случае успешного выполнения и SOCKET_ERROR
— при ошибке.
Допустимый формат строки определяется протоколом (некоторые протоколы вообще не поддерживают текстовую запись адреса, и для них функция WSAStringToAddress
неприменима). Для семейства AF_INET
, к которому относятся TCP и UDP, адрес может задаваться в виде "IP1.IP2.IP3.IР4:Port" или "IP1.IP2.IP3.IP4", где IРn — n -й компонент IP-адреса, записанною в виде 4-байтных полей, Port
— номер порта. Если порт явно не указан, устанавливается нулевой номер порта.
Таким образом, чтобы в структуре TSockAddr
оказался, например, адрес 192.168.100.217 и порт с номером 5000, необходимо выполнить следующий код (листинг 2.44).
Листинг 2.44. Пример использования функции WSAStringToAddress
var
Addr: TSockAddr;
AddrLen: Integer;
begin
AddrLen := SizeOf(Addr);
WSAStringToAddress('192.168.100.217:5000', AF_INET, nil, Addr, AddrLen);
Существует также функция WSAAddressToString
, обратная к WSAStringToAddrеss
. Ее прототип приведен в листинге 2.45.
Листинг 2.45. Функция WSAAddressToString
// ***** Описание на C++ *****
Читать дальше
Конец ознакомительного отрывка
Купить книгу