UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
35-4243-49В листинге 28.26 приведена функция
readable_listenЛистинг 28.26. Обработка нового соединения клиента
//icmpd/readablе_listen.c 1 #include "icmpd.h" 2 int 3 readable_listen(void) 4 { 5 int i, connfd; 6 socklen_t clilen; 7 clilen = sizeof(cliaddr); 8 connfd = Accept(listenfd, (SA*)&cliaddr, &clilen); 9 /* поиск первой свободной структуры в массиве client[] */10 for (i = 0; i < FD_SETSIZE; i++)11 if (client[i].connfd < 0) {12 client[i].connfd = connfd; /* сохранение дескриптора */13 break;14 }15 if (i == FD_SETSIZE) {16 close(connfd); /* невозможно обработать новый клиент */17 return(--nready); /* грубое закрытие нового соединения */18 }19 printf("new connection, i = %d, connfd = %dn", i, connfd);20 FD_SET(connfd, &allset); /* добавление нового дескриптора в набор */21 if (connfd > maxfd)22 maxfd = connfd; /* для select() */23 if (i > maxi)24 maxi = i; /* максимальный индекс в массиве client[] */25 return(--nready);26 }7-25clientКогда присоединенный сокет готов для чтения, вызывается функция
readablе_connЛистинг 28.27. Считывание данных и, возможно, дескриптора от клиента
//icmpd/readable_conn.c 1 #include "icmpd.h" 2 int 3 readable_conn(int I) 4 { 5 int unixfd, recvfd; 6 char c; 7 ssize_t n; 8 socklen_t len; 9 struct sockaddr_storage ss;10 unixfd = client[i].connfd;11 recvfd = -1;12 if ((n = Read_fd(unixfd, &c, 1, &recvfd)) == 0) {13 err_msg("client %d terminated, recvfd = %d", i, recvfd);14 goto clientdone; /* вероятно, клиент завершил работу */15 }16 /* данные от клиента, должно быть, дескриптор */17 if (recvfd < 0) {18 err_msg("read_fd did not return descriptor");19 goto clienterr;20 }13-18read_fdПри написании кода пришлось выбирать, что использовать для связи между приложением и демоном — либо потоковый доменный сокет Unix, либо дейтаграммный доменный сокет Unix. Дескриптор сокета UDP может быть передан через любой доменный сокет Unix. Причина, по которой предпочтение было отдано потоковому сокету, заключается в том, что он позволяет определить момент завершения клиента. Все дескрипторы автоматически закрываются, когда клиент завершает работу, в том числе и доменный сокет Unix, используемый для связи с демоном, в результате чего данный клиент удаляется демоном из массива client. Если бы мы использовали сокет дейтаграмм, то не узнали бы, когда клиент завершил работу.
16-20readable_connЛистинг 28.28. Получение номера порта, который клиент связал с UDP-сокетом
//icmpd/readable_conn.c21 len = sizeof(ss);22 if (getsockname(recvfd, (SA*)&ss, &len) < 0) {23 err_ret("getsockname error");24 goto clienterr;25 }26 client[i].family = ss.ss_family;27 if ((client[i].lport = sock_get_port((SA*)&ss, len)) == 0) {28 client[i].lport = sock_bind_wild(recvfd, client[i].family);29 if (client[i].lport <= 0) {30 err_ret("error binding ephemeral port");
