Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
BakalVoprosy - KC-2010_pre_Answers.doc
Скачиваний:
4
Добавлен:
07.07.2019
Размер:
1.01 Mб
Скачать
  1. Передача даних через сокети у режимі дейтаграм.

Кроме функции открытия сокета socket() и связывания его с портом и локальным адресом bind() , при передаче в режиме датаграм не зависимо от выбранного протокола (UDP или IPX) используются функции передачи данных sendto() и приёма данных recvfrom().

В конце обмена сообщением оба сокета закрываются функцией closesocket().

Для посылки датаграмы через сокет используется функция sendto():

int sendto (SOCKET s,const char FAR *buff, int len, int flags, struct sockaddr FAR *to, int tolen);

Первый параметр s – дескриптор открытого ранее сокета. За ним идет указатель на буфер, содержащий пересылаемые данные и длинна этого буфера. Последние два параметра используются для указания адреса и порта назначения. Параметр flags позволяет задавать флаги управления передачей данных в рамках IP-протокола (приоритет, надежность и т.д.). Однако, этим не следует пользоваться, т.к. нет гарантий, что эти службы имеются на сети. Поэтому следует задать flags=0.

Если функция sendto() срабатывает корректно, она возвращает количество посланных байтов. В случае ошибки, она возвращает SOCKET_ERROR. Для определения кода ошибки необходимо использовать функцию WSAGetLastError() .

При попытке послать датаграму большего размера, чем максимально допустимый в данной реализации Winsock, код ошибки равен WSAEMSGSIZE. Максимально допустимый размер датаграмы можно узнать при вызове функции WSAStartup().

Прием данных в режиме датаграм выполняется функцией recvfrom():

int recvfrom (SOCKET s, char FAR *buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen);

Первый параметр s – дескриптор открытого ранее сокета. За ним идут указатель на буфер для приема датаграмы и длина этого буфера. Параметр flags=0 или flags=MSG_PEEK, чтобы датаграмы оставались во входной очереди. Последние два параметра используются для получения адреса WS, пославшей датаграмы. Именно по этому адресу следует посылать ответ. Т.о., с помощью recvfrom() можно получить не только саму датаграму , но и узнать сетевой адрес с которого она послана.

При успешном получении датаграмы функция recvfrom() возвращает количество принятых байт,

при ошибке – SOCKET_ERROR, и для анализа причин ошибки необходимо вызвать WSAGetLastError().

  1. Передача даних через сокети у режимі та сесій.

После установления соединения, приложения могут обмениваться данными как потоком байт (STREAM) т.е., переходить из режимов приема на передачу и наоборот не обязательно. Можно просто считывать данные из входного потока и посылать их в выходной поток. Для режима датаграм необходимо переключение на прием/передачу после каждой датаграмы.

Взаимодействие между WS в режиме каналов предполагает вначале установить соединение, а уже потом обмениваться данными через входной/выходной поток.

Клиент всегда выступает инициатором соединения (вызывая функцию connect ()), а сервер пассивно ожидает запроса на соединение (функции Listen() и accept() ).

На стороне сервера после создания сокета и его привязки к локальному порту и адресу, вызывается функция Listen() , переводящая сервер в режим ожидания соединения:

int Listen (SOCKET s, int backlog).

Параметр backlog определяет максимальную длину очереди для ожидающих соединений (1-5). Ожидающий соединения сокет посылает автоматически каждому запрашиваемому соединение клиенту в ответ на запрос connect() подтверждение о том, что сервер принял запрос на установление соединения.

Само же соединение открывается функцией accept(), вызываемой на стороне сервера:

SOCKET accept (SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);

В качестве первого параметра передается сокет, ожидающий запроса. Второй и третий параметры используются для указания адреса структуры сокета клиента и его длины. Это такая же структура, как и та, что используется в функции bind() , однако, в неё следует занести адрес удаленного компьютера, а не локального. К счастью, это делается автоматически самой реализацией Winsock по приходу запроса connect() от клиента: программист должен только выделить место для размещения адреса.

Если соединение открывается успешно, функция accept() возвращает дискриптор нового сокета, который и будет теперь использоваться для передачи данных по этому соединению, т.е. соединяет его с клиентом, пославшим запрос на соединение. Первый же сокет, открытый функцией socket() освобождается и переходит в режим ожидания запросов от любого другого сетевого компьютера (т.е. в состояние после listen()). Таким образом, реализация сокетов позволяет осуществить как последовательную, так и параллельную обработку пребывающих запросов. Новое соединение вновь открывается с помощью функции accept() и так до пяти отдельных соединений.

Запрос на установление (открытие) соединения посылается со стороны клиента с помощью функции connect():

int connect (SOCKET s, const struct sockaddr FAR *name, int namelen);

Первый параметр s – дискриптор ранее открытого сокета с помощью socket(). Параметры sockaddr и namelen используются для указания удаленного адреса и порта (sockaddr) и длины этой структуры (namelen). Структура sockaddr, передаваемая в функцию connect() на клиенте должна быть идентичной структуре передаваемой в функцию bind() на сервере. До того, как вызвать функцию connect() информацию об адресах удаленного компьютера необходимо занести в структуру данных сокета.

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

После установления соединения между сокетом клиента и сокетом сервера, пересылка данных выполняется с помощью функции send():

int send (SOCKET s, const char FAR *buf, int len, int flags);

Первый параметр – открытый сокет, второй – указатель на буфер, содержащий пересылаемые данные, третий – длина буфера. Четвертый параметр позволяет задавать флаги для привилегированной обработки, рекомендуется flags=0.

Прием данных через соединенные сокеты осуществляется функцией recv():

int recv (SOCKET s, char FAR *buf,int len,int flags);

Параметры buf и len определяют соответственно указатель на буфер для приема данных и его длину. Рекомендуется flags=0. Если flags=MSG_PEEK, данные будут извлекаться без удаления из входной очереди.

Функции send() и recv() возвращают количество переданных и принятых байт соответственно

Приложение, принимающее данные должно вызывать recv() в цикле до тех пор, пока не будут приняты все переданные данные. То есть на одну функцию send() может приходиться несколько вызовов recv().

В случае ошибки обе функции возврашают SOCKET_ERROR, а для ее анализа необходимо вызвать WSAGetLastError().

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]