Общепринятая последовательность вызова функций при создании сетевых приложений с использованием гнeзд-сокетов, страница 2

Функция WSAAsyncSelect переводит гнездо s  в асинхронный режим. Параметры HWindow и wMsg - дескриптор окна, принимающего сообщения о событии и идентификатор этого события соответственно; параметр lEvent определяет, при возникновении каких событий гнездо посылает сообщение (lEvent суть комбинация двоичных флагов, см. табл. ниже).

Символ флага

Значение

Событие

FD_READ

$01

Имеются данные для приема

FD_WRITE

$02

Имеются данные в буфере для отправления

FD_OOB

$04

FD_ACCEPT

$08

Запрос на соединение для приема

FD_CONNECT

$10

Соединение с удаленной ЭВМ завершено

FD_CLOSE

$20

Соединение закрыто

Для настройки разрешения гнезду посылать сообщения о нескольких событиях необходимо объединить флаги этих событий с помощью поразрядного оператора OR. Например,  в нижеследующем примере гнезду OpenSocket_001 разрешается посылать определенное пользователем событие UWM_SOCKETEVENT окну с идентификатором handle_001 каждый раз, когда гнездо OpenSocket_001 закрывается удаленной ЭВМ, но при этом имеет поступающие данные для приема или место в буфере для отправления данных

WSAAsyncSelect(OpenSocket_001,  handle_001;

UWM_SOCKETEVENT,

FD_CONNECT or FD_READ or

FD_WRITE or FD_CLOSE);

Программист должен самостоятельно разработать процедуру-обработчик данного сообщения, памятуя, что вышеопределенный FD-флаг помещается в атрибут LParamHi объекта TMessage. При вощникновении события в атрибут LParamLo объекта TMessage помещается константа SOCKET_ERROR (см. пример)

procedure TForm_001.UWM_SocketEvent(varMsg: TMessage)

{ возникла какая-то ошибка ? }

begin

if (Msg.LParamHi = SOCKET_ERROR ) then { ошибка сокета ! }

Process_SocketError { обработка ошибки сокета }

else

begin

{ ошибки нет, выполнить обработку соответствующих ситуаций }

case Msg:LparamLO of

FD_CONNECT:   Process_FD_CONNECT; { обработчики... }

FD_READ:          Process_FD_READ;

FD_WRITE:        Process_FD_WRITE;

FD_CLOSE:        Process_FD_CLOSE;

end;

end;

end; { конец процедуры UWM_SocketEvent }

6. Поиск адреса удаленного компьютера. Используются функции типа (где name - имя удаленного компьютера для поиска, buf - буфер для приeма найденного адреса ЭВМ) :

function

WSAAsyncGetHostByName(HWindow: HWND; wMsag: u_int;

name, buf: PChar; buflen: Integer);

THandle;

Другими функциями этой группы являются WSAAsyncGetHostByAddr(), WSAGetServByName(), WSAGetServByPort(), WSAGetProtoByName(), WSAGetProtoByNumber().

Получить  адрес и порт сокета s на данной ЭВМ можно с помощью функции (адрес помещается в name)

function

getsockname(s: TSocket; var name: TSockaddr;

var namelen: Integer): Integer;

а сокета на удаленной ЭВМ, к которому в данный момент подключены

function

getpeername(s: TSocket; var name: TSockaddr;

var namelen: Integer): Integer;

6.Технология сокетов применяется и для работы с  протоколом UDP (User Datagram Protocol). В отличие от  TCP/IP (Transmission Control Protocol / Intenet Protocol ) протокол UDP не гарантирует доставку пакетов и допускает нарушение исходного порядка сообщений (допускается также случайное дублирование пакетов). Программист обязан в этом случае проводить контроль данных на уровне прикладной программы, для чего потребуется организация подтверждения доставки и повторная пересылка данных.

Для сокетов UDP существуют две новых функции (нижеприводятся  в С-стиле). Эти вызовы могут быть использованы и при работе с TCP/IP, но обычно применяются в UDP-модели (чтобы сервер мого получить информацию об отправителе и послать ответ). Тип сокета (TCP/IP или UDP) определяется параметрами type и  protocol в момент вызова soket); при protocol=0 в случае type=SOCK_STREAM используется протокол TCP/IP, а при type=SOCK_DGRAM - протокол UDP.

N0

Используемая функция

Описание действия

1. 

ssize_t

recvfrom(int sockfd, void *buff, size_t length, int flags, struct sockaddr *send_addr,

size_t *add_len);

Прием UDP-пакетов через гнездо sockfd в буфер buff длиной length. Адрес и порт,   откуда пришли данные, запоминаются (для последующего ответа)  в структуре send_addr длиной add_len (при send_addr=NULL вызов recvfrom абсолютно аналогичен вышеприведенному recv)

2.   

ssize_t

sendto(int sockfd, const  void *buff, size_t length, int flags, const  struct sockaddr *dest_addr, size_t *dest_len);

Передача UDP-пакетов через гнездо sockfd из буфера buff длиной length. Данные передаются на адрес и порт, заданные структурой dest_addr размером dest_len