Теория и практика программирования на Си в Unix

       

Написанные на языке Си, намеренно


Написанные на языке Си, намеренно упрощенные, примеры были проверены на машинах Sun Sparcstation (4/65 и 4/330) в системе SunOS версия 4.1. и HP 9000 375 в HP-UX версия 7.0. Обработка ошибок, возвращаемых примитивами, чаще всего опус- калась, для того, чтобы не утяжелять код. По этой же причине большая часть примеров приведена не полностью.


сокетов (см. параграф 4.3.5.) с заменой reads() и writes() на readt() и writet(), определенные в файле tli.c */ ...................... }
/* файл serveur.c #include "tli.h"
serveuripc() { int fd; /* дескриптор TLI int nfd; /* дескриптор TLI struct t_call *callptr; /* структура TLI struct t_bind *reg; /* структура TLI struct sockaddr_in serv_addr; /* адрес сервера
/* создание точки входа в транспортный уровень */ fd = t_open("/dev/tcp", O_RDWR, NULL); /* присваивание значения адресу и связывание bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(SERV_PORT); req = (struct t_bind *) t_alloc(fd, T_BIND, T_ALL); req->addr.len = sizeof(serv_addr); req->addr.maxlen = sizeof(serv_addr); req->addr.buf = (char *) &serv_addr; req->qlen = 1; t_bind(fd, req, NULL);
/* распределение структуры t_call, используемой функциями t_listen() и t_accept() */ callptr = (struct t_call *) t_alloc(fd, T_CALL, T_ADDR); /* бесконечный цикл ожидания привходящих связей for (;;) { t_listen(fd, callptr); /* получение новой точки входа в транспортный уровень, используемой для обмена */ nfd = accept_call(fd, callptr); /* обращение к службе "эхо" serveur(nfd); /* закрытие используемой точки входа t_close(nfd); } }
/* прием запроса на связь. Возвращает новую точку входа или - 1 в случае ошибки */ int accept_call(lfd, callptr) int lfd ; /* дескриптор TLI struct t_call *callptr; /* структура TLI { int nfd ; /* дескриптор TLI /* открытие новой точки входа в транспортный уровень nfd = t_open("/dev/tcp", O_RDWR, NULL); /* ей присваивается какой-нибудь адрес t_bind(nfd, NULL, NULL); /* связывание старой и новой точек входа */ /* в нашем примере (итеративный сервер) можно было бы сохранить текущий дескриптор lfd для обмена данными с клиентом */ if (t_accept(lfd, nfd, callptr) < 0) { if (t_errno == TLOOK) { /* если ошибка : связь разорвана ? */ t_rcvdis(lfd, NULL); /* тогда закрываем точку входа */ t_close(nfd); return(-1); } err_sys(" t_accept echoue"); } return(nfd); }


/* функция приема-передачи serveur(nfd) int nfd; /* дескриптор TLI */ { /* обработка, идентичная обработке для сокетов с заменой reads() и writes() на readt() и writet() */ ....................... /* результатом операции может быть отрицательное значение, если клиент разорвал связь */ if (rval < 0) { /* выход, если получено T_DISCONNECT */ if (t_look(nfd) == T_DISCONNECT) return; err_sys ("pb lecture TLI "); } }
/* файл tli.c *****************************/ /* содержит процедуры, используемые, как клиентом, так и сервером : * writet() : запись в точку входа блоками размером по 4К (как показывает тест (на Sun OS 4.1.) нельзя послать блок данных, размер которого превосходит это значение). * readt() : считывает информацию из точек входа до тех пор, пока не считает требуемое количество символов. * err_sys() : выводит на экран сообщение об ошибке и кончает работу. */ #include <stdio.h> #include <tiuser.h> /* запись буфера, состоящего из пос байт в точку входа */ int writet(fd, pbuf, noc) register int fd; /* дескриптор TLI */ register char *pbuf; /* буфер */ register int noc; /* число записываемых байт */ { /*то же, что и writes(), но write() заменяется на t_snd()*/ ........... }
/* считывание буфера, состоящего из пос байт из точки входа int readt(fd, pbuf, noc) register int fd; /* дескриптор TLI */ register char *pbuf; /* буфер */ register int noc; /* число считываемых байт */ { /* то же, что и reads() (Глава 4), но read() заменяется на t_snd() */ ........... }
/* процедура обработки ошибок */ err_sys(mes) char *mes; /* сообщение пользователя */ { t_error(mes); exit(1); } - Модификация предыдущего примера с использованием примити- вов read () и write () на сервере. На сервере создается модуль Stream tirdwr, позволяющий ис- пользовать вызовы read (), write () и close (). Эта операция осуществляется в процедуре accept_call (), вследствие этого измененной. ПРОГРАММА 41 /* модификация процедуры accept_call(), обеспечивающая возможность использования read(),write() и close() */ /* прием запроса на связь: создание дескриптора файла для этой связи. Возвращает или новый дескриптор или, в случае сбоя, -1. */ accept_call(lfd, callptr) int lfd; /* дескриптор TLI */
struct t_call *callptr; /* структура TLI */ { int nfd; /* дескриптор TLI */ /* начало такое же, как и в предыдущем примере */ ............................. /* выполняется "push" для модуля "tirwdr" для нового потока, чтобы обеспечить использование read() и write(). Надо сначала выполнить "pop" для модуля "timod" /* ioct1(nfd, I_POP, (char *)0);
ioct1(nfd, I_PUSH, "tirdwr"); return(nfd); /* возвращает новый дескриптор */ }


Содержание раздела