А. Робачевский - Операционная система UNIX (1114671), страница 82
Текст из файла (страница 82)
За созда!ние нового транспортного узла отвечает сама программа (т. е. необходимявный вызов функциипри этом fd может по!прежнему ис!пользоваться для обслуживания поступающих запросов.Как и в случаечерез аргументудаленном транспортном узле.передается информация обwww.books-shop.comПрограммные интерфейсы433После возврата из функции t_accept(3N) между двумя узламииудаленным узлом!клиентом) образован виртуальный канал, готовый к пе!редаче прикладных данных.Для обмена прикладными данными после установления соединения ис!пользуются две функции:для получения и t_snd(3N) для переда!чи.
Они имеют следующий вид:ttinclude <tiuser.h>int t_rcv(intchar *buf, unsigned nbytes, intint t_snd(int fildes, char *buf, unsigned nbytes, int flags);Первые три аргумента соответствуют аналогичным аргументам системныхвызововиАргумент f l a g s функции t_snd(3N) может со!держать следующие флаги:T_EXPEDITEDT_MOREУказывает на отправление экстренных данныхУказывает, что данные составляют логическую запись, продолже%ние которой будет передано последующими вызовамиНапомним, что TCP обеспечивает неструктурированный поток и,следовательно, не поддерживает данной возможностиЭту информацию принимающий узел получает с помощью t_rcv(3N) такжечерез аргумент f l a g s .Для протоколов без предварительного установления соединения исполь!зуются функцииидля получения и передачисоответственно.
Функции имеют следующий вид:ttincludeintintfildes, struct t_unitdata *unitdata,int *fildes, struct t_unitdataДля передачи данных используется структура unitdata, имеющая сле!дующие поля:struct netbuf addrstruct netbuf optstruct netbuf udataАдрес удаленного транспортного узлаОпции протоколаПрикладные данныеСозданный транспортный узел может быть закрыт с помощью функцииt_close(3N). Заметим, что при этом соединение, или виртуальный канал, скоторым ассоциирован данный узел, в ряде случаев не будет закрыт.Функция t_close(3N) имеет вид:ttincludeintгде f d определяет транспортный узел. Вызов этой функции приведет к ос!вобождению ресурсов, связанных с транспортным узлом, а последующийwww.books-shop.com434Глава 6.сети всистеме UNIXсистемный вызов close(2) освободит и файловый дескриптор. Судьба вир!туального канала (если таковой существует) зависит от того, является литранспортный узел, адресующий данный канал, единственным.
Если этотак, соединение немедленно разрывается. В противном случае, например,когда несколько файловых дескрипторов адресуют один и тот же транс!портный узел, виртуальный канал продолжает существовать.Завершая разговор о программном интерфейсе ТЫ, необходимо упомянутьоб обработке ошибок. Для большинства функций ТЫ свидетельствомошибки является получение !1 в качестве возвращаемого значения. На!против, в случае нормального завершения эти функции возвращают 0. Какправило, при неудачном завершении функции ТЫ код ошибки сохраняет!ся в переменной t_errno, подобно тому, как переменная errno храниткод ошибки системного вызова.
Для вывода сообщения, расшифровываю!щего причину ошибки, используется функцияvoidcharПри вызове t_error(3N) после неудачного завершения какой!либо функцииТЫ будет выведено сообщение errmsg, определенное разработчикомпрограммы, за которым последует расшифровка ошибки, связанной с ко!дом t_errno. Если значение t_errno равно TSYSERR, то расшифровкапредставляет собой стандартное сообщение о системной ошибке, связан!ной с переменной errno.В заключение в качестве иллюстрации программного интерфейса ТЫ при!ведем пример приложения клиент!сервер. Как и в предыдущих примерах,сервер принимает сообщения от клиента и отправляет их обратно. Клиент,в свою очередь, выводит полученное сообщение на экран. В качестве со!общения,как и прежде,выступает жизнерадостное приветствие"Здравствуй,Серверtincludefinclude<arpa/inet.h>iinclude <fcntl.h>/*Номер порта, известныйttdefine1500intcharwww.books-shop.comПрограммные435транспортных узловint tn,int pid, flags;int nport;транспортных узлов сервера иstruct sockaddr_instructstructstruct t_callузел.
В качестве поставщика транспортных услугвыберем модуль{вызоваадрес транспортного узла — он должен быть известен клиенту */nport =/*Приведем в соответствие порядок следования байтов для хоста иnport == AF_INET;===== (charчисло запросов,обработки, установим равным=узел с(struct*)0) < 0){вызоваexit}"Адрес сервера:/*Поскольку в структуре t call нам понадобится только буфер для храненияадреса клиента, разместим ееif=(structt_alloc(tn,{вызова}=== 0;= 0;www.books-shop.com436Глава 6.сети в операционной системе UNIXцикл получения и обработки{поступления запроса на установление(t_listen(s, call) <0){вызова}информацию о клиенте, сделавшемclnt_addr = (structтранспортный узел для обслуживания=(struct t_info *)<0){вызова}/*Пусть система сама свяжет его с подходящимif(struct t_bind(struct*)0) <0){вызова}запрос и переведем его обслуживание на новый транспортныйif{ntn, call) <0)вызовановый процесс для обслуживания запроса.
При этом родительскийпроцесс продолжает принимать запросы от{tвызова}{int nbytes;этот транспортный узел уже не нужен, он используетсяродителем* /while=buf,sizeof(buf),!=0){t_snd(ntn, buf,)twww.books-shop.comПрограммные интерфейсы}процесс: этот транспортный узел не нужен, он используетсядочерним процессом для обмена данными с}}Клиентttincludettincludettincludettinclude <fcntl.h>ttinclude1500argv)charint{int tn;ihtstruct sockaddr_instruct hostentcharstruct t_call/*B качестве аргумента клиенту передается доменное имя хоста, на которомзапущен сервер. Произведем трансляцию доменного имени в{вызова}транспортный узел. В качестве поставщика транспортных услугвыберем модуль{вызова}системе самостоятельно связать узел с подходящим(struct t_bind(struct t_bind *}0) < 0}{вызоваexit}"Адрес клиента:inetwww.books-shop.com438Глава 6.сети в операционной системе UNIX/*Укажем адрес сервера, с которым мы будем=в соответствие порядок следования байтов для хоста и=/*Поскольку в структуре t_call нам понадобится только буфер для храненияадреса сервера, разместим ееif ( (call =(structt_alloc(tn,{вызова}=== (char *)= 0;= 0;соединение сcall, (struct t_call *)0)==1){вызова}сообщение и получим ответ */buf,if (t_rcv(tn, buf,<0){вызоваexit}полученное сообщение наот сервера:завершил}В рассмотренном примере большая часть исходного текста посвящена соз!данию транспортных узлов и установлению соединения, в то время какзавершение сеанса связи представлено скупыми вызовами t_close(3N).
Насамом деле, вызов t_close(3N) приводит к немедленному разрыву соедине!ния, запрещая дальнейшую передачу или прием данных. Однако вирту!альный канал, обслуживаемый протоколом TCP, является полнодуплекс!ным и, как было показано, TCP предусматривает односторонний разрывсвязи, позволяя другой стороне продолжать передачу данных. Действиям,предписываемым TCP, больше соответствуют две функциииt_rcvrel(3N), которые обеспечиваютпрекращение связи (orderlyrelease).
Разумеется, эти рассуждения справедливы лишь для транспорт!ного протокола, обеспечивающего передачу данных с предварительнымустановлением связи, каковым, в частности, является протокол TCP.www.books-shop.comПрограммные439и t_rcvrel(3N) имеют вид:Функцииttinclude;fd);tВызывая функциюпроцесс отправляет другой стороне уве!домление об одностороннем прекращении связи, это означает, что про!цесс не намерен больше передавать данные.
В то же время процесспринимать данные — файловый дескриптор f d доступен для чтения.Другая сторона подтверждает получение уведомления вызовом ф у н к ц и иt_rcvrel(3N). Однако поскольку получение такого уведомления носит асин!хронный характер, процесс должен каким!то образом узнать, что запроспоступил. Такой индикацией является завершение с ошибкой попыткиполучения данных от удаленного узла, например, с помощью функцииВ этом случае вызов функции t_rcv(3N) завершится с ошибкойTLOOK.Эта ошибка свидетельствует, что произошло событие, связанное с комму!н и к а ц и о н н ы м узлом, анализ которого позволяет получить дополнительнуюинформацию о причине неудачи.
Текущее событие может быть получено спомощью функцииФункция возвращает идентификатор, соответствующий одному из собы!тий, перечисленных в табл. 6.6.Таблица 6.6. События, связанные с коммуникационным узломСобытиеЗначениеУзлом получено подтверждение создания соединенияУзлом получен запрос на разрыв соединенияУзлом получены данныеУзлом получены экстренные данныеУзлом получен запрос на установление соединенияT_ORDRELУзлом получен запрос на корректное прекращение связиT_ERRORСвидетельствует о фатальной ошибкеT_UDERRСвидетельствует об ошибкеЕсли в рассматриваемом случае событием, связанным с ошибкойявляетсяэто означает, что удаленный узел завершил передачуданных и более не нуждается в соединении. Если узел, получивший запросна прекращение связи, не возражает против полного прекращения сеанса,Ⱦɚɧɧɚɹɜɟɪɫɢɹɤɧɢɝɢɜɵɩɭɳɟɧɚɷɥɟɤɬɪɨɧɧɵɦɢɡɞɚɬɟɥɶɫɬɜɨɦ%RRNVVKRSɊɚɫɩɪɨɫɬɪɚɧɟɧɢɟɩɪɨɞɚɠɚɩɟɪɟɡɚɩɢɫɶɞɚɧɧɨɣɤɧɢɝɢɢɥɢɟɟɱɚɫɬɟɣɁȺɉɊȿɓȿɇɕɈɜɫɟɯɧɚɪɭɲɟɧɢɹɯɩɪɨɫɶɛɚɫɨɨɛɳɚɬɶɩɨɚɞɪɟɫɭpiracy@books-shop.com440Глава 6.сети в операционной системе UNIXон вызывает функциюВпрочем, при необходимости, комму!н и к а ц и о н н ы й узел может продолжить передачу данных.
Единственное, от!чего ему следует воздержаться, это от попытки получения данных, или,другими словами, от вызовапоскольку в этом случае выполне!ние процесса будет навсегда заблокировано, т. к. данные от удаленногоузла поступать не будут.Проиллюстрируем описанную процедуру фрагментом программы, обраба!тывающей корректное прекращение связи:обработку принятыхif{== T_LOOK==получен запрос на корректное прекращениесогласны на завершение сеанса, поэтому также корректноМыexittexitполучения данных(tПрограммный интерфейс высокого уровня.