Взаимодействие с прикладными процессами
Взаимодействие с прикладными процессами
Рассмотренный ранее программный интерфейс TLI полностью реализует функциональность TPI. Легко заметить соответствие между отдельными функциями TLI и примитивами TPI, приведенными в табл. 6.10. Схема вызова функций TPI и обмена соответствующими примитивами TPI между клиентом и сервером для типичного TCP-сеанса приведена на рис. 6.32.
Рис. 6.32. Функции TLI и примитивы TPI
Программный интерфейс потоков был рассмотрен в главе 5 при обсуждении подсистемы STREAMS. Основными функциями, обеспечивающими передачу и получение сообщений, являются системные вызовы putmsg(2) и getmsg(2). Таким образом, большинство функций TLI, составляющих программный интерфейс доступа прикладных процессов к транспортным протоколам, являются удобной оболочкой (реализованной в виде библиотеки, например, libnsl.so) более фундаментальным системным вызовам putmsg(2) и getmsg(2).
В качестве примера рассмотрим функцию t_connect(3N). Ее реализация может иметь следующий вид:
int t_connect(int fd, struct t_call *sndcall,
struct t_call *recvcall) {
struct T_conn_req *connreq;
struct T_conn_con* conncon;
struct T_ok_ack *okack;
struct T_error_ack *errack;
struct strbuf connect, ack, confirm, m_data;
struct netbuf addr, opt, udata;
char *buf;
int flags;
...
/* Сохраним адреса буферов netbuf запроса sndcall */
addr = sndcall->addr; opt = sndcall->opt;
udata = sndcall->udata;
/* Заполним поля структуры strbuf для формирования
управляющей части (блок M_PROTO) сообщения T_CONN_REQ */
connect.len =
sizeof(struct T_conn_req) + addr.len + opt.len;
connect.maxlen =
sizeof(struct Т_conn_req) + addr.maxlen + opt.maxlen;
buf = (char*)malloc(connect.maxlen);
connect.buf = buf;
/* Заполним поля заголовка блока M_PROTO сообщения T_CONN_REQ в
соответствии с форматом структуры T_conn_req */
connreq = (struct T_conn_req*)buf;
connreq->PRIM_type = T_CONN_REQ;
connreq->DEST_length = addr.len;
connreq->DEST_offset = sizeof (struct T_conn_req);
buf += sizeof(struct T_conn_req);
memcpy(buf, addr.buf, addr.len);
connreq->OPT_length = opt.len;
connreq->OPT_offset = connreq->DEST_offset + opt.len;
buf += addr.len;
memcpy(buf, opt.buf, opt.len);
/* Заполним поля структуры strbuf для формирования блока данных
(блок M_DATA) */
m_data.len = udata.len;
m_data.maxlen = udata.maxlen;
m_data.buf = udata.buf;
/* Отправим запрос Т_CONN_REQ поставщику транспортных услуг
по потоку fd */
putmsg(fd, &connect, &m_data, 0);
/* Подготовимся к приему подтверждения. Выделим максимальный
размер для получения негативного подтверждения, поскольку
примитив T_ERROR_ACK занимает больше места */
ack.len = ack.maxlen = sizeof(struct T_error_ack);
ack.buf = udata.buf;
/* Подтверждение является приоритетным, поэтому установим флаг
RS_HIPRI. До получения подтверждения не предпринимаем
никаких действий */
flags = RS_HIPRI;
getmsg(fd, &ack, (struct strbuf*)0, &flags);
free(connect.buf);
okack = (struct T_ok_ack*)ack.buf;
/* Проверим получено ли положительное или
негативное подтверждение */
if (okack->PRIM_type == T_OK_ACK) {
/* Если подтверждение положительное, подготовимся к получению
согласия удаленного пользователя на установление связи
(примитив T_CONN_CON) */
free(ack.buf);
if (recvcall != NULL) {
addr = recvcall->addr;
opt = recvcall->opt;
udata = recvcall->udata;
confirm.len = sizeof(struct T_conn_con) + addr.len + opt.len;
confirm.maxlen =
sizeof(struct T_conn_con) + addr.maxlen + opt.maxlen;
buf = (char*)malloc(confirm.maxlen);
confirm.buf = buf;
m_data.len = udata.len;
m_data.maxlen = udata.maxlen;
m_data.buf = udata.buf;
/* Получим примитив T_CONN_CON */
getmsg(fd, &confirm, &m_data, &flags);
free(buf);
conncon = (struct T_conn_con*)confirm.buf;
if (conncon->PRIM_type == T_CONN_CON) {
/* Если это действительно согласие, заполним
структуру rcvcall для пользователя TLI */
addr.len = conncon->OPT_length;
opt.len = conncon->OPT_length;
memcpy(addr.buf, conncon+conncon->RES_offset, addr.len);
memcpy(opt.buf, conncon+conncon->OPT_offset, opt.len);
free(confirm.buf);
/* Все закончилось удачно — возвращаем 0 */
return 0;
}
} else {
/* В случае отказа мы готовы обработать примитив
T_DISCON_IND */
...
return -1;
}
} else {
/* Если получен примитив T_ERROR_ACK — обработаем его */
errack = (struct T_error_ack*)ack.buf;
...
return -1;
}
}
Подобным образом реализовано большинство функций TLI. Заметим, что в конкретном случае использования транспортного протокола TCP прием и передача данных осуществляются в виде потока, не содержащего каких-либо логических записей. В этом случае не требуется формирование примитивов типа T_DATA_REQ и T_DATA_IND. В то же время, для передачи и получения экстренных данных будут использованы примитивы T_EXDATA_REQ и T_EXDATA_IND. При использовании протокола UDP все данные будут передаваться с помощью примитивов T_UNITDATA_REQ и T_UNITDATA_IND.
Описанная реализация программного интерфейса TLI имеет один существенный недостаток — операции функций не являются атомарными. Другими словами, выполнение функции t_connect(3N) может быть прервано другими процессами, которые могут также связываться с удаленным узлом. Это возможно, поскольку выполнение значительной части операций происходит в режиме задачи. Если для функции t_connect(3N) нарушение атомарности допустимо, то ряд функций, таких, например, как связывание (t_bind(3N)), получение информации (t_open(3N), t_getinfo(3N)) и установка или получение опций протокола (t_optmgmt(3N)) должны быть защищены от возможного нарушения целостности данных по причине прерывания операции. Единственным способом гарантировать атомарность является перевод выполнения критических участков (например, между отправлением примитива и получением подтверждения от поставщика транспортных услуг) в режим ядра. Для этого подсистема STREAMS предлагает механизм обмена управляющими командами с помощью вызова ioctl(2).
Однако с помощью ioctl(2), как было показано в разделе "Подсистема STREAMS" главы 5, можно формировать лишь сообщения типа M_IOCTL. Для преобразования этих сообщений в примитивы TPI служит дополнительный модуль timod(7M), встраиваемый в поток между головным и транспортным модулями. На рис. 6.33 показано местоположение модуля timod(7M) и схематически отображены его функции.
Рис. 6.33. Архитектура доступа к транспортным услугам
Для всех сообщений STREAMS, за исключением сообщений M_IOCTL, которые генерируются головным модулем в ответ на системный вызов ioctl(fd, I_STR, ...), модуль timod(7M) является прозрачным, т.е. он просто передает эти сообщения следующему модулю вниз по потоку без какой-либо обработки. Несколько сообщений M_IOCTL обрабатываются модулем и преобразуются в соответствующие примитивы TPI.
При этом вызов ioctl(2) имеет следующий формат:
#include <sys/stropts.h>
struct strioctl my_strioctl
...
strioctl.ic_cmd = cmd;
strioctl.ic_timeout = INFTIM;
strioctl.ic_len = size;
strioctl.ic_dp = (char*)buf;
ioctl(fd, I_STR, &my_strioctl);
При вызове ioctl(2) поле size устанавливается равным размеру соответствующего примитива TPI, определенного полем cmd и расположенного в буфере buf. При возврате из функции поле size содержит размер примитива, возвращенного поставщиком транспортных услуг и расположенного в буфере buf.
Модуль timod(7M) служит для обработки следующих команд cmd:
Значение cmd Обработка модулем timod(7M) TI_BIND Команда преобразуется в примитив T_BIND_REQ. При успешном завершении функции ioctl(2) в буфере buf находится примитив T_BIND_ACK. TI_UNBIND Команда преобразуется в примитив T_UNBIND_REQ. При успешном завершении функции ioctl(2) в буфере buf находится примитив T_OK_ACK. TI_GETINFO Команда преобразуется в примитив T_INFO_REQ. При успешном завершении функции ioctl(2) в буфере buf находится примитив T_INFO_ACK. TI_OPTMGMT Команда преобразуется в примитив T_OPTMT_REQ. При успешном завершении функции ioctl(2) в буфере buf находится примитив T_OPTMGMT_ACK.Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
9.1. Создание и управление процессами
9.1. Создание и управление процессами В отличие от многих предшествующих и последующих операционных систем, создание процессов в Unix задумывалось (и было сделано) дешевым. Более того, Unix разделяет идеи «создания нового процесса» и «запуска данной программы в процессе». Это
ГЛАВА 11 Взаимодействие между процессами
ГЛАВА 11 Взаимодействие между процессами В главе 6 было показано, как создавать процессы и управлять ими, тогда как главы 7—10 были посвящены описанию методов управления потоками, которые выполняются внутри процессов, и объектов, обеспечивающих их синхронизацию. Вместе с
Управление процессами
Управление процессами Время — это средство, с помощью которого Природа не дает всему происходить сразу. В компьютерах таким средством служат процессы. Процесс — это исполняющаяся программа. Он состоит из исполняемой программы, данных программы и некоторой информации
Подсистема управления процессами
Подсистема управления процессами Запущенная на выполнение программа порождает в системе один или более процессов (или задач). Подсистема управления процессами контролирует:? Создание и удаление процессов? Распределение системных ресурсов (памяти, вычислительных
Создание и управление процессами
Создание и управление процессами Работая в командной строке shell вы, возможно, не задумывались, каким образом запускаются программы. На самом деле каждый раз порождается новый процесс, а затем загружается программа. В UNIX эти два этапа четко разделены. Соответственно
Взаимодействие между процессами
Взаимодействие между процессами Как уже обсуждалось, в UNIX процессы выполняются в собственном адресном пространстве и по существу изолированы друг от друга. Тем самым сведены к минимуму возможности влияния процессов друг на друга, что является необходимым в
ГЛАВА 7. УПРАВЛЕНИЕ ПРОЦЕССАМИ
ГЛАВА 7. УПРАВЛЕНИЕ ПРОЦЕССАМИ В предыдущей главе был рассмотрен контекст процесса и описаны алгоритмы для работы с ним; в данной главе речь пойдет об использовании и реализации системных функций, управляющих контекстом процесса. Системная функция fork создает новый
7.2.3 Посылка сигналов процессами
7.2.3 Посылка сигналов процессами Для посылки сигналов процессы используют системную функцию kill. Синтаксис вызова функции:kill(pid, signum)где в pid указывается адресат посылаемого сигнала (область действия сигнала), а в signum — номер посылаемого сигнала. Связь между значением pid и
Глава 26 Управление процессами
Глава 26 Управление процессами Данная глава посвящена процессам операционной системы Linux. Поскольку администрирование операционной системы в конечном счете сводится к управлению процессами, вполне логично выделить отдельную главу на описание столь важной темы.Каждый
8.4. Управление процессами
8.4. Управление процессами Первым делом научимся определять, какие процессы в системе запущены. Для этого в Linux (как и во всех UNIX-системах) имеется команда ps. Если ее запустить без всяких параметров, то она выдает список процессов, запущенных в текущей сессии. Если вы хотите
5.3. Команды управления процессами
5.3. Команды управления процессами Команда psКоманда ps предназначена для вывода информации о выполняемых в текущий момент процессах. Данная команда имеет много параметров, о которых вы можете прочитать в руководстве (man ps). Здесь я опишу лишь наиболее часто используемые
14.1.3. Манипулирование процессами
14.1.3. Манипулирование процессами В этом разделе мы обсудим манипулирование процессами, хотя создание нового процесса необязательно связано с запуском внешней программы. Основной способ создания нового процесса — это метод fork, название которого в соответствии с
Взаимодействие с процессами в рамках платформы .NET
Взаимодействие с процессами в рамках платформы .NET Хотя процессы и потоки сами по себе не являются чем-то новым, способы взаимодействия с этими примитивами в рамках платформы .NET существенно изменены (к лучшему). Чтобы успешно пройти путь к пониманию приемов построения
3.1. Знакомство с процессами
3.1. Знакомство с процессами Пользователю достаточно войти в систему, чтобы в ней начали выполняться процессы. Даже если пользователь ничего не запускает, а просто сидит перед экраном и пьет кофе. в системе все равно "теплится жизнь". Любой выполняющейся программе
Управление процессами
Управление процессами Функция Краткое описание abort завершить процесс execl выполнить порождаемый процесс со списком аргументов execle выполнить порождаемый процесс со списком аргументов и заданным окружением (контекстом имен командного языка операционной