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

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

Двухэтапное соединение происходит только в идеальном случае. Чаще всего добавляется еще один этап - определение IP-адреса по указанному имени компьютера. Пользователям тяжело работать с IP-адресами, потому что это числа. Мы легко запоминаем 10 номеров телефонов, но постоянно держать в голове сотни больших чисел очень тяжело. Поэтому чаще всего используются символьные имена серверов/компьютеров. Понятные названия откладываются в памяти быстрее.

В отличие от людей компьютер работает с адресами как с числами. Именно поэтому приходится использовать преобразование символьного имени компьютера в числовой адрес. Мы будем работать с IP-адресацией, а это значит, что адрес будет состоять из 4 чисел от 0 до 255, разделенных точками

Познакомимся с процессом определения IP-адреса. Для этого используется одна из двух функций - gethostbyname или WSAAsyncGetHostByName. Для начала рассмотрим функцию gethostbyname. Она описывается следующим образом:

function gethostbyname(
name: PChar )• PHostEnt: stdcal1:

В качестве единственного параметра нужно передать символьное имя искомого компьютера. Функция возвращает структуру типа hostent, которую мы рассмотрим чуть позже.

Функция gethostbyname может генерировать следующие коды ошибок:

• WSANOTINITIALISED - сначала необходимо вызвать функцию WSASturtup, а потом создавать сокет;
• WSAENETDOWN - связь нарушена, возможные причины - отошел кабель^или произошло отключение от Интернета;
• WSAH0ST_N0T_F0UND - официальный ответ от компьютера с таким адресом не найден;
• WSATRYAGAIN - ошибка сервера. В этом случае можно попробовать вызвать функцию повторно. Не стоит запускать бесконечный цикл определения имени, пока нам возвращается эта ошибка. Программа может никогда не узнать адрес, и произойдет зависание;
• WSAN0_REC0VERY - возникла ошибка, которую нельзя устранить;
• WSANO_DATA - имя существует, но нет записи запрошенного типа. Это случается, когда компьютер в сети есть, но не имеет нужного нам настроенного протокола;
• WSAEFAULT - параметр name не входит в часть адресного пространства пользователя;
• WSAEINPROGRESS - выполняется операция в блокирующем режиме. Вы уже запустили на выполнение какую-то функцию и нужно дождаться завершения ее работы;

• WSAEINTR - функцией WSACancelBlockmgCall отменен блокирующий вызов

Теперь переходим к рассмотрению функции WSAAsyncGetHostByName. Она описывается следующим образом:

function WSAAsyncGetHostByName(
HWnd: HWND:
wMsg: u_int:
name: PChar:
buf: PChar:
buflen: Integer ): THandle;
stdcall:

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

Это очень удобно, потому что процесс определения адреса может быть долгим, и блокирование программы на это время будет неэффективным Лучше использовать время с пользой и произвести какие-то подготовительные действия (предварительные расчеты, загрузку локальных файлов в память для последующей отправки по сети), которые могут пригодиться после установки соединения.

Рассмотрим параметры функции wSAAsyncGetHostByName:

• hWnd - дескриптор окна, которому будет послано сообщение по завершении выполнения асинхронного запроса;
• wMsg - сообщение Windows, которое будет сгенерировано по завершении определения IP-адреса;
• name - символьное имя компьютера, адрес которого надо определить;
в buf - буфер, в который будет помещена структура hostent. Буфер должен иметь достаточный объем памяти. Максимальный размер равен 1024 байта, но лучше воспользоваться константой MAXGETHOSTSTRUCT;

• buf 1 en - длина буфера, указанного в параметре buf.

Структура hostent с помощью которой будет получен результат определения адреса, описывается следующим образом:

hostent = record h_name: PChar;
h_aliases: APChar;
h_addrtype: Smallint: hjength: Smallint: h_addr_list: "PChar
end:
THostEnt = hostent:

После объявления структуры hostent стоит псевдоним THostEnt Именно это имя нужно использовать в своих проектах на Delphi.

Рассмотрим параметры структуры hostent:

• h_name - полное имя компьютера. Если в сети используется доменная система, то этот параметр будет содержать полное доменное имя;
• h_al iases - дополнительное имя узла;
• haddrtype - тип возвращаемого адреса;
• hjength - длина каждого адреса в списке адресов;

• haddrlist - список адресов компьютера.

Компьютер может иметь несколько адресов, поэтому структура возвращает нам полный список, заканчивающийся нулем. В большинстве случаев достаточно выбрать первый адрес из списка. Если функция gethostbyname определила какие-нибудь адреса, то чаще всего по любому из них можно будет соединиться с искомым компьютером. Если связь недоступна, то тогда можно попробовать использовать другой адрес.

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

Теперь перейдем непосредственно к функции соединения с сервером connect. Она описывается следующим образом:

function connecte
s: TSocket:
vaг name: TSockAddr;
namelen: Integer ): Integer: stdcal!:

Функция connect имеет такие параметры:

• s - предварительно созданный сокет;
• name - структура SockAddr, содержащая адрес сервера, к которому надо подключиться;

• namelen - размер структуры SockAddr, указанной в качестве второго параметра.

Во второй версии появилась функция WSAConnect, ее объявление есть только в модуле WinSock 2 и выглядит следующим образом:

function WSAConnect( s: TSocket:
const name: PSockAddr;
namelen: Integer:
lpCallerData. lpCalleeData: LPWSABUF;
IpSQOS, lpGQOS: LPQOS ): Integer: stdcal1 :

Первые три параметра нам уже знакомы, и они ничем не отличаются от рассмотренных в функции connect. Поэтому коснемся только новых для нас параметров:

• lpCallerData - указатель на пользовательские данные, которые будут отправ- - лены серверу во время установки соединения;

• lpCalleeData - указатель на буфер, в который будут помещены данные, возвращаемые во время соединения.

Оба параметра имеют тип указателя на структуру WSABUF, которая описывается так:

WSABUF = packed record

len: U_L0NG: // Размер буфера buf: PChar: // Указатель на буфер

end
PWSABUF = -WSABUF: LPWSABUF = PWSABUF:

где первый параметр - размер буфера, а второй параметр является указателем на сам буфер. '

Последние два параметра функции WSAConnect - это 1 pSQOS и 1 pGQOS, которые являются указателями на структуры типа Q0S. Они определяют требования к пропускной способности канала при приеме и передаче данных. Если указать нулевое значение, то это будет означать, что не предъявляется никаких требований к качеству обслуживания.

Во время попытки соединения вы чаще всего можете встретить следующие ошибки:

в WSANOTINITIALISED - сначала необходимо вызвать функцию WSASturtup, а потом создавать сокет;
в WSAENETDOWN - связь нарушена, возможные причины - отошел кабель или произошло отключение от Интернета;
в WSAEADDRINUSE - указанный адрес уже используется;
в WSAEINTR - функцией WSACancel Bl ockingCal 1 блокирующий вызов был отменен;
в WSAEINPROGRESS - выполняется операция в блокирующем режиме. Вы уже запустили на выполнение какую-то функцию и нужно дождаться завершения ее работы;
в WSAEALREADY - указанный сокет занят неблокирующей операцией;
в WSAEADDRNOTAVAIL - указанный адрес не доступен с локальной машины;
в WSAEAFNOSUPPORT - указанная адресация не может использоваться с данным со-кетом. Ошибка возникает, если сокет создан для IP-адресации, а в функции connect указана адресация любого другого несовместимого протокола;
в WSAEFAUL - параметры name или namelen не соответствуют указанной адресации или имеют неправильные размеры;
в WSAEISCONN - сокет уже имеет подключение с удаленным компьютером;
в WSAENETUNREACH - сеть не доступна с локальной машины в данный момент;
в WSAENOBUFS - нет свободных буферов. Сокет не может подключиться;
в WSAEN0TS0CK - дескриптор не является сокетом;
в WSAETIMEDOUT - сервер недоступен. Возможна какая-то проблема на пути соединения;
в WSAECONNREFUSED - на сервере не запущено прослушивание указанного порта;
в WSAEWOULDBLOCK - сокет создан как неблокирующий, и в данный момент операция не может быть завершена. Эта ошибка возникает при любом вызове функции в неблокирующем режиме;

в WSAEACCES - попытка соединиться пакетным сокетом к широковещательному адресу невозможна, потому что не включен параметр S0_BR0ADCAST

4.5. Функции сервера || Оглавление || 4.7. Функции приема и передачи данных


Delphi в шутку и всерьез: что умеют хакеры



Новости за месяц

  • Декабрь
    2021
  • Пн
  • Вт
  • Ср
  • Чт
  • Пт
  • Сб
  • Вс
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31