Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
124
Добавлен:
20.06.2014
Размер:
6.61 Mб
Скачать

45. Потоковые сокеты. Клиент – серверная модель.

Перед началом взаимодействия устанавливают соединение. Здесь мы обязательно имеем клиента и сервера. Сервер – прога, ожидающая запроса и производящая действия исключительно в ответ. Клиент – прога, обращающаяся с запросами к серверу.

Организация сервера: чтобы начать ожидание запросов на соединение сервер задает сокет соотв. типа, связывает его с адресом и переводит в «слушающее» состояние (L на схеме). На таком сокете мб осуществлена только 1 операция «принятия» соединения. При установлении соединения ядро создает еще 1 сокет, который используется для передачи данных по установленному соед-ю:

sd - связан с сокетом ФД;

int listen (int sd, int qlen) qlen - задает размер очереди не принятой запросом на соединение (5-6)

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

int accept (int sd, struct sockaddr *addr, socklen_t *addrlen)

sd - ФД слушающего сокета;

addr – структура в которую записывают адрес сокета, с которым установлено соединение.

addrlen – указатель на переменную типа socklen_t. В эту переменную перед вызовом accept следует занести размер адресной структуры. После возврата accept эта переменная будет содержать количетсво байт, записанных в эту структуру.

Возвращает accept ФД нового сокета для нового соединения. Если на момент выполнения accept запросов на соединение еще не поступало, тогда вызов блокирует вызвавший процесс и ожидает запроса на соединение.

Организация клиента: связывать сокет с адресом не обязательно, если этого не сделать система выберет адрес автоматически. Запрос на соединение формируется вызовом:

int connect (int sd, struct sockaddr *addr, int *addrlen)

sd - связан с сокетом ФД;

addr – указывает на структуру, содержащую адрес сервера, т.е. адрес «слушающего» сокета.

addrlen – дб равен размеру этой структуры.

Обмен данными: после успешнгого установления соединения для передачи данных можно использовать read/write. Существуют спец системные вызовы revc(), send(), Отличаются от read/write только наличием флагов.

Завершить работу с сокетом:

int shutdown (int sd, int how) how – что именно надо прекратить (0 – закрыть на чтение, 1 - …на запись,

Закрыть сокет: int close (int sd) 2 - …оба направления)

Shutdown только прекращает обмен данными в сокете, а close уберет сам ФД. Если дальний конец соединения закрыт очередной вызов read или recv вернет 0 => конец файла.

Организация функции преобразования адресов: Порядок байт в представлении целых чисел может варьироваться в зависимости от архитектуры. Архитектура в которой старший байт числа имеет наименьший адрес (прямой порядок) big-endian. Другой вариант: наименьший адрес имеет младший байт (обратный порядок) little-endian. Чтобы сделать возможным взаимодейтсвие по сети между машинами с разными архитектурами принято соглашение, что передача целочисленной информации по сети всегда идет в прямом порядке байт. Чтобы обеспечить переносимость программ на уровне исход кода в UNIX есть стандартные функции для преобразования целых чисел из формата данной машины в сетевой формат. На машине порядок байт в архитектуре которой совпадает с сетевым эти функции вернут аргумент, иначе они произведут преобразование:

unsigned long int htonl (unsigned long int hostlong);

n (network) – сетевой порядок байт

unsigned short int htons (unsigned short int hostshort);

h (host) – порядой байт данной машины

unsigned long int ntohl (unsigned long int netlong);

s – короткие целые, l – длинные целые.

unsigned short int ntohs (unsigned short int netshort);

При работе с сервером можно отметить след. ситуацию: после завершения программы-сервера ее некоторое время можно запустить с тем же номером порта. Это происходит при некорректном завершении проги-сервера, либо если завершение происходит при активных клиентских соединениях. Ядро ОС продолжает читать адрес «занято». Система сокетов позволяет изменить поведение ядра в отношении адресов зависших подобным образом («залипших»). Для этого перед вызовом bind необходимо выставить на будущем «слушающем» сокете опцию: SO_REUSEADDR. Это делается с помощью сист вызова:

int setsockopt (int sd, int level, int optname, const void *optval, int optlen)

sd – дескриптор сокета.

level – уровень стека протоколов. В данной опции уровень SOL_SOCKET.

optname – номер или числовой идентификатор (SO_REUSEADDR).

Т.е. информация связанная с этой опцией может иметь разную сложность. Вызов принимает безтиповый указатель назначения опции и длины опции.

optval = 1; optlen = sizeof(int); int opt = 1

Пример: setsockopt (ls,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));

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

В UNIX предусмотрен вызов: int socketpair (int af, int type, int protocol, int sv[2]);

af, type, protocol – задают семейство адресации, тип и протокол для создаваемого сокета соотв-но AF_UNIX, SOCK_STREAM, 0.

sv – должен указывать на массив из 2х элементов целого типа в котор вызов занесет ФД 2х созданных структур. Сокеты будут уже связаны друг с другом при чем оба конца открыты на чтение и запись.