Операционная система UNIX - страница 122
, а процесс (приложение) адресуется 16-разрядным номером порта >sin_port
.
На рис. 3.23 показаны рассмотренные форматы адресов сокетов.
Рис. 3.23. Адреса сокетов
Итак, связывание необходимо для присвоения сокету локального адреса и, таким образом, для определения коммуникационного узла. Можно выделить три случая использования для этого функции bind(2):
1. Сервер регистрирует свой адрес. Этот адрес должен быть заранее известен клиентам, желающим "общаться" с сервером. Связывание необходимо, прежде чем сервер будет готов к приему запросов от клиентов.
2. При взаимодействии без предварительного установления связи и создания виртуального канала клиент также должен предварительно зарегистрировать свой адрес. Этот адрес должен быть уникальным в рамках коммуникационного домена. В случае домена UNIX об этом должно позаботиться само приложение. Этот адрес не должен быть заранее известен серверу, поскольку запрос всегда инициирует клиент, автоматически передавая вместе с ним свой адрес. Полученный адрес удаленного узла затем используется сервером для мультиплексирования сообщений, отправляемым различным клиентам.
3. Даже в случае взаимодействия с использованием виртуального канала клиент может пожелать зарегистрировать собственный адрес, не полагаясь при этом на систему.
Назначение адреса для клиента также можно выполнить с помощью системного вызова connect(2), устанавливающего связь с сервером и автоматически связывающего сокет клиента с локальным коммуникационным узлом. Вызов connect(2) имеет вид:
>#include
>#include
>int connect(int sockfd, struct sockaddr *servaddr, int addrlen);
Характер этого вызова предполагает создание виртуального канала и, таким образом, используется для предварительного установления связи между коммуникационными узлами. В этом случае клиенту нет необходимости явно связывать сокет с помощью системного вызова bind(2). Локальный узел коммуникационного канала указывается дескриптором сокета >sockfd
, для которого система автоматически выбирает приемлемые значения локального адреса и процесса. Удаленный узел определяется аргументом >servaddr
, который указывает на адрес сервера, a >addrlen
задает его длину.
Вызов connect(2) может также применяться и клиентами, использующими без создания виртуального канала. В этом случае connect(2) не вызывает фактического соединения с сервером, а является удобным способом сохранения параметров адресата (сервера), которому будут направляться датаграммы. При этом клиент будет избавлен от необходимости указывать адрес сервера при каждом отправлении данных.
Следующие два вызова используются сервером только при взаимодействии, основанном на предварительном создании виртуального канала между сервером и клиентом.
Системный вызов listen(2) информирует систему, что сервер готов принимать запросы. Он имеет следующий вид:
>#include
>#include
>int listen(int sockfd, int backlog);
Здесь параметр >sockfd
определяет сокет, который будет использоваться для получения запросов. Предполагается, что сокет был предварительно связан с известным адресом. Параметр >backlog
указывает максимальное число запросов на установление связи, которые могут ожидать обработки сервером.[45]
Фактическую обработку запроса клиента на установление связи производит системный вызов
>#include
>#include
>int accept(int sockfd, struct sockaddr *clntaddr,
> int* addrlen);
Вызов accept(2) извлекает первый запрос из очереди и создает новый сокет, характеристики которого не отличаются от сокета >sockfd
, и таким образом завершает создание виртуального канала со стороны сервера. Одновременно accept(2) возвращает параметры удаленного коммуникационного узла — адрес клиента >clntaddr
и его размер >addrlen
. Новый сокет используется для обслуживания созданного виртуального канала, а полученный адрес клиента исключает анонимность последнего. Дальнейший типичный сценарий взаимодействия имеет вид:
>sockfd = socket(...);
Создать сокет
>bind(sockfd, ...);
Связать его с известным локальным адресом