UNIX: разработка сетевых приложений
UNIX: разработка сетевых приложений читать книгу онлайн
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
35-42
43-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-25
client
Когда присоединенный сокет готов для чтения, вызывается функция
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-18
read_fd
При написании кода пришлось выбирать, что использовать для связи между приложением и демоном — либо потоковый доменный сокет Unix, либо дейтаграммный доменный сокет Unix. Дескриптор сокета UDP может быть передан через любой доменный сокет Unix. Причина, по которой предпочтение было отдано потоковому сокету, заключается в том, что он позволяет определить момент завершения клиента. Все дескрипторы автоматически закрываются, когда клиент завершает работу, в том числе и доменный сокет Unix, используемый для связи с демоном, в результате чего данный клиент удаляется демоном из массива client. Если бы мы использовали сокет дейтаграмм, то не узнали бы, когда клиент завершил работу.
16-20
readable_conn
Листинг 28.28. Получение номера порта, который клиент связал с UDP-сокетом
//icmpd/readable_conn.c
21 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");