Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Psp_bilety_ekzamen.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
142.82 Кб
Скачать

3) Примеры Установление связи

Со стороны клиента связь устанавливается с помощью стандартной функции connect: error = connect(s, serveraddr, serveraddrlen); которая инициирует установление связи на сокете, используя дескриптор сокета s и информацию из структуры serveraddr, имеющей тип sockaddr_in, которая содержит адрес сервера и номер порта на который надо установить связь. Если сокет не был связан с адресом, connect автоматически вызовет системную функцию bind.

Connect возвращает 0, если вызов прошел успешно. Возвращенная величина -1 указывает на то, что в процессе установления связи произошла некая ошибка. В случае успешного вызова функции процесс может работать с дескриптором сокета, используя функции read и write, и закрывать канал используя функцию close.

Со стороны сервера процесс установления связи сложнее. Когда сервер желает предложить один из своих сервисов, он связывает сокет с общеизвестным адресом, ассоциирующимся с данным сервисом, и пассивно слушает этот сокет. Для этих целей используется системный вызов listen:

error = listen(s, qlength); где s это дескриптор сокета, а qlength это максимальное количество запросов на установление связи, которые могут стоять в очереди, ожидая обработки сервером; это количество может быть ограничено особенностями системы.

Когда сервер получает запрос от клиента и принимает решение об установлении связи, он создает новый сокет и связывает его с ассоциацией, эквивалентной 'слушающему сокету'. Для Internet домена это означает тот же самый номер порта. Для этой цели используется системный вызов accept: newsock = accept(s, clientaddr, clientaddrlen);

Сокет, ассоциированный клиентом, и сокет, который был возвращен функцией accept, используются для установления связи между сервером и клиентом.

Процесс установления связи показан на рисунке 1.

  Рис. 1: Взаимодействие клиента и сервера

Передача данных

Когда связь установлена, с помощью различных функций может начаться процесс передачи данных. При наличии связи, пользователь может посылать и получать сообщения с помощью функций read и write: write(s, buf, sizeof(buf)); read(s, buf, sizeof(buf));

Вызовы send и recv практически идентичны read и write, за исключением того, что добавляется аргумент флагов.

send(s, buf, sizeof(buf), flags); recv(s, buf, sizeof(buf), flags);

Могут быть указаны один или более флагов с помощью ненулевых значений, таких, как следующие:

  • MSG_OOB - Посылать/получать данные, характерные для сокетов типа stream.

  • MSG_PEEK - Просматривать данные без чтения. когда указывается в recv, любые присутствующие данные возвращаются пользователю, но сами данные остаются как "непрочитанные". Следующий read или recv вызванный на данном сокете вернет прочитанные в прошлый раз данные.

  • MSG_DONTROUTE - посылать данные без маршрутизации пакетов. (Используется только процессами, управляющими таблицами маршрутизации.)

21 Билет

1. Закрытие сокетов.

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

«От отправителя больше нет данных» (этот бит еще называется FIN бит).

Если сокет больше не используется, процесс может закрыть его с помощью функции close, вызвав ее с соответствующим дескриптором сокета в качестве аргумента: close(s);

Если данные были ассоциированы с сокетом, обещающим доставку (сокет типа stream), система будет пытаться осуществить передачу этих данных. Тем не менее, по истечении довольно длительного промежутка времени, если данные все еще не доставлены, они будут отброшены. Если пользовательский процесс желает прекратить любую передачу данных, он может сделать это с помощью вызова shutdown на данном сокете для его закрытия. Вызов shutdown осуществляет «моментальное» отбрасывание всех стоящих в очереди данных. Формат вызова следующий: shutdown(s, how);

Параметр how имеет одно из следующих значений:

0 - пользователь больше не желает читать данные;

1 - данные больше не будут посылаться;

2 - данные не будут ни посылаться, ни получаться.

2. Мультиплексирование ввода-вывода. Функции poll и select.

В случае использования протокола UDP соединение не устанавливается и для обработки нескольких клиентов. Чтобы избежать блокирования процесса в случае чтения из сокетов, можно использовать функции мультиплексированного ввода-вывода.

Функции select и poll ожидают разнообразных событий в файловых дескрипторах.

Системный вызов select.

int select(int n, fd_set *readfds, fd_set *writefds,

fd_set *exceptfds, struct timeval);

В качестве первого параметра в функции select указывают максимальное значение обслуживаемого файлового дескриптора плюс 1,readfds-множество файловых дескрипторов, в которых ожидается события на чтение, writefds- на запись, exceptfds- на удаление. Последний параметр используется для задания тайм-аута, по истечении которого, даже если никакого события не произошло, программа разблокируется, а select возвращает 0. В случае, если какое-либо событие все-таки произошло,функция возвращает номер файлового дескриптора в множестве. В случае ошибки возвращается -1. Рассмотрим пример использования функции select, в нем ожидается в течение 5 секунд ввод с клавиатуры, в противном случае программа заканчивается с сообщением о том, что вышел тайм-аут:

fd_set rfds;

struct timeval tv;

int retval;

/* Ждем, пока на стандартном вводе (fd 0) что-нибудь появится. */

FD_ZERO(&rfds);

FD_SET(0, &rfds);

/* Ждем не больше пяти секунд. */tv.tv_sec = 5; tv.tv_usec = 0; retval = select(1, &rfds, NULL, NULL, &tv);

/* Не полагаемся на значение tv! */if (retval) printf("Данные доступны.\n");

/* Теперь FD_ISSET(0, &rfds) вернет истинное значение. */

else

printf("Данные не появились в течение пяти секунд.\n");

...

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

•FD_ZERO- очищает набор;

•FD_SET и FD_CLR- добавляют или удаляют заданный де

скриптор из набора;

•FD_ISSET- проверяет, является ли дескриптор частью набора;

этот макрос полезен после возврата из функции select.

Системный вызов poll.

int poll(struct pollfd *ufds, unsigned int nfds, int timeout);

Системный вызов poll имеет аналогичную функциональность с select.

Здесь задается массив из nfds структур типа

struct pollfd {

int fd; /* файловый дескриптор */

short events; /* запрошенные события */

short revents; /* возвращенные события */

};

И timeout в миллисекундах. Отрицательное значение означает бесконечный тайм-аут. Необходимо заполнить значение полей

fd, установив номер открытого файлового дескриптора, и

events, в который нужно установить тип обрабатываемого события, например, POLLIN для чтения данных или POLLOUT

для записи. Поле revents- выходной параметр, куда ядро помещает информацию о произошедших событиях- запрошенных или событий типа

POLLERR(произошла ошибка),POLLHUP(закрыли дескриптор),

POLLNVAL(неверный запрос:fd не открыт).

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