Читаем без скачивания Операционная система UNIX - Андрей Робачевский
Шрифт:
Интервал:
Закладка:
Перейдем к основным функциям TLI.
Как видно из рис. 6.18 и 6.19, в качестве первого этапа создания коммуникационного узла используется функция t_open(3N). Как и системный вызов open(2), она возвращает дескриптор, который в дальнейшем адресует узел в функциях TLI. Функция имеет вид:
#include <tiuser.h>
#include <fcitl.h>
int t_open(const char *path, int oflags, struct t_info *info);
Аргумент path является именем специального файла устройства, являющегося поставщиком транспортных услуг, например, /dev/tcp или /dev/udp. Аргумент oflags определяет флаги открытия файла и соответствует аналогичному аргументу системного вызова open(2). Приложение может получить информацию о поставщике транспортных услуг в структуре info, имеющей следующие поля:
addr Определяет максимальный размер адреса транспортного протокола. Значение -1 говорит, что размер не ограничен, -2 означает, что прикладная программа не имеет доступа к адресам протокола. Протокол TCP устанавливает размер этого адреса (адрес порта) равным 16. options Определяет размер опций для данного протокола. Значение -1 свидетельствует, что размер не ограничен, -2 означает, что прикладная программа не имеет возможности устанавливать опции протокола. tsdu Определяет максимальный размер пакета данных протокола (Transport Service Data Unit, TSDU). Нулевое значение означает, что протокол не поддерживает пакетную передачу (т.е. не сохраняет границы записей). Значение -1 свидетельствует, что размер не ограничен, -2 означает, что передача обычных данных не поддерживается. Поскольку протокол TCP обеспечивает передачу неструктурированного потока данных, значение tsdu для него равно 0. Напротив, UDP поддерживает пакетную передачу. etsdu Определяет максимальный размер пакета экстренных данных протокола (Expedited Transport Service Data Unit, ETSDU). Нулевое значение означает, что протокол не поддерживает пакетную передачу (т.е. не сохраняет границы записей). Значение -1 свидетельствует, что размер не ограничен, -2 означает, что передача экстренных данных не поддерживается. TCP обеспечивает такую поддержку, а UDP — нет. connect Некоторые протоколы допускают передачу прикладных данных вместе с запросом на соединение. Поле connect определяет максимальный размер таких данных. Значение -1 свидетельствует, что размер не ограничен, -2 означает, что данная возможность не поддерживается. И TCP и UDP не поддерживают этой возможности. discon Определяет то же, что и connect, но при запросе на прекращение соединения. И TCP и UDP не поддерживают этой возможности. servtype Определяет тип транспортных услуг, предоставляемых протоколом. Значение T_COTS означает передачу с предварительным установлением соединения, T_COTS_ORD — упорядоченную передачу с предварительным установлением соединения, T_CLTS — передачу без предварительного установления соединения. Протокол TCP обеспечивает услугу T_COTS_ORD, a UDP — T_CLTS.Прежде чем передача данных будет возможна, транспортному узлу должен быть присвоен адрес. Эта фаза называется операцией связывания и мы уже сталкивались с ней при разговоре о сокетах в главе 3 и при обсуждении сетевой поддержки в BSD UNIX ранее в этой главе. В рассмотренных случаях связывание выполнял вызов bind(2). В TLI для этого служит функция t_bind(3N), имеющая вид:
#include <tiuser.h>
int t_bind(int fd, const struct t_bind *req,
struct t_bind *ret);
Аргумент fd адресует коммуникационный узел. Аргумент req позволяет программе явно указать требуемый адрес, а через аргумент ret возвращается значение, установленное протоколом.
Два последних аргумента описываются структурой t_bind, имеющей следующие поля:
struct netbuf addr Адрес unsigned qlen Максимальное число запросов на установление связи, которые могут ожидать обработки. Имеет смысл только для протоколов с предварительным установлением соединенияРассмотрим три возможных формата аргумента req:
req == NULL Позволяет поставщику транспортных услуг самому выбрать подходящий адрес req != NULL req->addr.len == 0 Позволяет поставщику транспортных услуг самому брать подходящий адрес, но определяет максимальное число запросов на установление связи, которые могут ожидать обработки req != NULL req->addr.len > 0 Явно указывает требуемый адрес и максимальное число запросов на установление связи, которые могут ожидать обработкиВо всех случаях фактическое значение адреса возвращается в структуре ret. Даже если программа явно указала требуемый адрес, необходимо проверить, совпадает ли он с адресом, указанным в ret.
Для протоколов с предварительным установлением соединения программе-клиенту необходимо использовать функцию t_connect(3N), отправляющую запрос на создание соединения с удаленным транспортным узлом. Функция t_connect(3N) имеет вид:
#include <tiuser.h>
int t_connect(int fd, const struct t_call* sndcall,
struct t_call *rcvcall);
Аргумент sndcall содержит информацию, необходимую поставщику транспортных услуг для создания виртуального канала. Формат этой информации описывается структурой t_call, имеющей следующие поля:
struct netbuf addr Адрес удаленного транспортного узла struct netbuf opt Требуемые опции протокола struct netbuf udata Прикладные данные, отправляемые вместе с управляющей информацией (запрос на установление соединения или подтверждение) int sequence В данном случае не имеет смыслаЧерез аргумент revcall программе возвращается информация о виртуальном канале после его создания: адрес удаленного узла, опции и прикладные данные, переданные удаленным узлом. Как уже отмечалось, ни TCP, ни UDP не позволяют передавать данные вместе с управляющей информацией. Программа может установить значение rcvcall равным NULL, если информация о канале ее не интересует.
Обычно возврат из функции t_connect(3N) происходит после окончательного установления соединения, когда виртуальный канал готов к передаче данных (конечно, в случае успешного завершения).
Для протоколов с предварительным установлением соединения программа-сервер вызывает функцию t_listen(3N), блокируя свое выполнение до получения запроса на создание виртуального канала.
#include <tiuser.h>
int t_listen(int fd, struct t_call *call);
Информация, возвращаемая транспортным протоколом в аргументе call, содержит параметры, переданные удаленным узлом с помощью соответствующего вызова t_connect(3N): его адрес, установленные опции протокола, а также, в ряде случаев, прикладные данные, переданные вместе с запросом. Поле sequence аргумента call содержит уникальный идентификатор данного запроса.
Хотя t_listen(3N), несмотря на название, напоминает функцию accept(2), используемую для сокетов, сервер должен выполнить вызов другой функции — t_accept(3N) для того, чтобы фактически принять запрос и установить соединение. Функция t_accept(3N) имеет вид:
#include <tiuser.h>
int t_accept(int fd, int connfd, struct t_call *call);
Аргумент fd адресует транспортный узел, принявший запрос (тот же, что и для функции t_listen(3N)). Аргумент connfd адресует транспортный узел, для которого будет установлено соединение с удаленным узлом. За создание нового транспортного узла отвечает сама программа (т.е. необходим явный вызов функции t_open(3N)), при этом fd может по-прежнему использоваться для обслуживания поступающих запросов.
Как и в случае t_listen(3N), через аргумент call передается информация об удаленном транспортном узле.