Операционная система UNIX - Страница 142
Транспортный уровень является самым верхним в системе и призван обеспечить необходимую адресацию и требуемые характеристики передачи данных, определенных коммуникационным узлом процесса, которым является сокет. Например, сокет потока предполагает надежную последовательную доставку данных, и в семействе TCP/IP модуль данного уровня реализует протокол TCP. Следующий, сетевой, уровень обеспечивает передачу данных, адресованных удаленному сетевому или транспортному модулю. Для этого модуль данного уровня должен иметь доступ к информации о маршрутах сети (таблице маршрутизации). Наконец, последний уровень отвечает за передачу данных хостам, подключенным к одной физической среде передачи (например, находящимся в одном сегменте Ethernet).
Внутренняя структура сетевой подсистемы изолирована от непосредственного доступа прикладных процессов. Единым (и единственным) интерфейсом доступа к сетевым услугам является интерфейс сокетов, рассмотренный в главе 3 в разделе "Межпроцессное взаимодействие в BSD UNIX. Сокеты". Для обеспечения возможности работы с конкретным коммуникационным протоколом соответствующий модуль экспортирует интерфейсу сокетов функцию пользовательского запроса. При этом данные от прикладного процесса передаются от интерфейса сокетов требуемым транспортным модулям с помощью соответствующих вызовов экспортированных функций. И наоборот, данные, полученные из сети, проходят обработку в соответствующих модулях протоколов и помещаются в очередь приема сокета-адресата.
Движение данных вниз (т.е. от верхних уровней к нижним) обычно инициируется системными вызовами и может иметь синхронный характер. Принимаемые данные из сети поступают в случайные моменты времени и передаются сетевым драйвером в очередь приема соответствующего протокола. При этом функции модуля протокола и обработка данных не вызываются непосредственно сетевым драйвером. Вместо этого последний устанавливает бит соответствующего программного прерывания, в контексте которого система позднее и запускает необходимые функции. Если данные предназначены протоколу верхнего уровня (транспортному), его функция обработки будет вызвана непосредственно модулем сетевого уровня. Если же сообщение предназначено другому хосту, и система выполняет функции шлюза, сообщение будет передано уровню сетевого интерфейса для последующей передачи.
Прежде чем более подробно ознакомиться со взаимодействием различных модулей сетевой подсистемы BSD UNIX, рассмотрим сначала структуры данных, определяющие сокет, коммуникационный протокол и сетевой интерфейс.
Структуры данных
Структура данных
socket
so_type
so_state
so_proto
Рис. 6.21. Структуры данных сокета
Сокет является коммуникационным узлом и обеспечивает буферизацию получаемых и отправляемых данных. Как только данные попадают в распоряжение сокета в результате системного вызова (например, write(2) или send(2)), сокет немедленно передает их модулю протокола для последующего отправления. Данные передаются в виде связанного списка специальных буферов mbuf, структура которых также показана на рис. 6.21. Модуль протокола может ожидать подтверждения получения отправленных данных или отложить их отправку. В обоих случаях сообщения остаются в буфере передачи сокета до момента окончательной отправки или получения подтверждения. Аналогично, данные, полученные из сети, в конечном итоге буферизуются в приемной очереди сокета-адресата, пока не будут извлечены оттуда системным вызовом (например, read(2) или recv(2)).
Для избежания переполнения буфер (структура
sockbuf
sb_hiwat
Сокеты, используемые для приема и обработки запросов на установление связи (зарегистрированные с помощью системного вызова listen(2)), адресуют два связанных списка: список сокетов, связь для которых не полностью установлена, и список сокетов, обеспечивающих доступ к созданным каналам передачи данных.
Следующая структура данных, которую мы рассмотрим, относится к коммуникационным протоколам. Каждый модуль протокола представляет собой набор функций обработки и структур данных и описывается структурой данных, называемой коммутатором протокола. Коммутатор протокола хранит адреса стандартных функций протокола, например, функций ввода (
pr_input()
pr_output()
Рис. 6.22. Коммутатор протокола
Перед первым использованием модуля вызывается функция его инициализации
pr_init()
pr_fasttimo()
pr_slowtimo()
pr_drain()
С помощью функции
pr_usrreq()
pr_usrreq()
Таблица 6.7. Запросы функции pr_usrreq()
Системный вызов | Значение | Запрос |
---|---|---|
close(2) | Прекратить обмен данными | PRU_ABORT |
accept(2) | Обработать запрос на установление связи | PRU_ACCEPT |
bind(2) | Связать сокет с адресом | PRU_BIND |
connect(2) | Установить связь | PRU_CONNECT |
listen(2) | Разрешить обслуживание запросов | PRU_LISTEN |
send(2), sendto(2) | Отправить данные | PRU_SEND |
fstat(2) | Определить состояние сокета | PRU_SENSE |
getsockname(2) | Получить адрес локального сокета | PRU_SOCKADDR |
getpeername(2) | Получить адрес удаленного сокета | PRU_PEERADDR |
ioctl(2) | Передать команду модулю протокола | PRU_CONTROL |