UNIX: разработка сетевых приложений
exit(main(argc, argv));Следовательно, вызывается функция
, а затем и программа очистки стандартного ввода-вывода.exitГлава 15
15.1. Функция
удаляет имя файла из файловой системы, и когда клиент позже вызовет функциюunlink, она не выполнится. Это не влияет на прослушиваемый сокет сервера, но клиенты не смогут выполнить функцииconnectпосле вызова функцииconnect.unlink15.2. Клиент не сможет соединиться с сервером с помощью функции
, даже если полное имя существует, поскольку для успешного соединения с помощью функцииconnectдоменный сокет Unix должен быть открыт и связан с этим полным именем (см. раздел 15.4).connect15.3. При выводе адреса протокола клиента путем вызова функции
мы получим сообщениеsock_ntop(дейтаграмма от (имя не задано)), поскольку по умолчанию с сокетом клиента не связывается никакое имя.datagram from (no pathname bound)Одним из решений является проверить доменный сокет Unix в функциях
иudp_clientи связать с сокетом при помощи функцииudp_connectвременное полное имя. Это приведет к зависимости от протокола в библиотечной функции, но не в нашем приложении.bind15.4. Даже если мы заставим сервер вернуть в функции
1 байт на его 26- байтовый ответ, использование функцииwriteна стороне клиента гарантирует, что все 26 сегментов будут получены до вызова функцииsleep, в результате чего функцияreadвернет полный ответ. Это еще одно подтверждение того, что TCP является потоком байтов с отсутствием границ записей.readЧтобы использовать доменные протоколы Unix, запускаем клиент и сервер с двумя аргументами командной строки
(или/lосаl) и/unix(или любое другое временное имя, которое вы хотите использовать). Ничего не изменится: 26 байт будут возвращаться функцией/tmp/daytimeкаждый раз, когда будет запускаться клиент.readПоскольку для каждой функции
сервер определяет флагsend, каждый байт рассматривается как логическая запись, и функцияMSG_EORпри каждом вызове возвращает 1 байт. Причина в том, что Беркли-реализации поддерживают флагreadпо умолчанию. Однако этот факт не документирован и не может использоваться в серийном коде. В данном примере мы используем эту особенность, чтобы показать разницу между потоком байтов и ориентированным на записи протоколом. С точки зрения реализации, каждая операция вывода идет вMSG_EOR(буфер памяти) и флагmbufсохраняется ядром вместе сMSG_EOR, когдаmbufпереходит из отправляющего сокета в приемный буфер принимающего сокета. Когда вызывается функция read, флагmbufвсе еще присоединен к каждомуMSG_EOR, так что основная подпрограмма ядраmbuf(поддерживающая флагread, поскольку некоторые протоколы используют этот флаг) сама возвращает каждый байт. Если бы вместоMSG_EORмы использовалиread, флагrecvmsgвозвращался бы в полеMSG_EORкаждый раз, когдаmsg_flagsвозвращала бы 1 байт. Такой подход в TCP не срабатывает, поскольку отправляющий TCP не анализирует флагrecvmsgв отсылаемомMSG_EORи в любом случае у нас нет возможности передать этот флаг принимающему TCP в TCP-заголовке. (Выражаем благодарность Мату Томасу (Matt Thomas) за то, что он указал нам это недокументированное «средство».)mbuf15.5. В листинге Д.7 приведена реализация данной программы.
Листинг Д.7. Определение фактического количества собранных в очередь соединений для различных значений аргумента backlog
//debug//backlog.c1 #include "unp.h"2 #define PORT 99993 #define ADDR "127 0.0.1"4 #define MAXBACKLOG 1005 /* глобальные переменные */6 struct sockaddr_in serv;7 pid_t pid; /* дочерний процесс */8 int pipefd[2];9 #define pfd pipefd[1] /* сокет родительского процесса */10 #define cfd pipefd[0] /* сокет дочернего процесса */11 /* прототипы функций */12 void do_parent(void);13 void do_child(void);14 int15 main(int argc, char **argv)16 {17 if (argc != 1)18 err_quit("usage: backlog");19 Socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd);20 bzero(&serv, sizeof(serv));21 serv.sin_family = AF_INET;22 serv.sin_port = htons(PORT);23 Inet_pton(AF_INET, ADDR, &serv.sin_addr);24 if ((pid = Fork()) == 0)25 do_child();26 else27 do_parent();28 exit(0);29 }30 void31 parent_alrm(int signo)32 {33 return; /* прерывание блокированной функции connect() */34 }