Описание функций последовательного доступа
#include <netdb.h> void sethostent (int stayopen); struct hostent *gethostent (void); void endhostent (void); |
Листинг 11.1. Описание функций последовательного доступа к сетевой базе данных о хостах - узлах сети. |
Закрыть окно |
#include <stdio.h> #include <netdb.h> int main (void) { struct hostent *pht; char *pct; int i, j; sethostent (1); while ((pht = gethostent ()) != NULL) { printf (" Официальное имя хоста: %s\n", pht->h_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->h_aliases [i]) != NULL; i++) { printf (" %s\n", pct); } printf ("Тип адреса хоста: %d\n", pht->h_addrtype); printf ("Длина адреса хоста: %d\n", pht->h_length); printf ("Сетевые адреса хоста:\n"); for (i = 0; (pct = pht->h_addr_list [i]) != NULL; i++) { for (j = 0; j < pht->h_length; j++) { printf (" %d", (unsigned char) pct [j]); } printf ("\n"); } } endhostent (); return 0; } |
Листинг 11.2. Пример программы, осуществляющей последовательный доступ к сетевой базе данных о хостах - узлах сети. |
Закрыть окно |
Официальное имя хоста: localhost Альтернативные имена: Тип адреса хоста: 2 Длина адреса хоста: 4 Сетевые адреса хоста: 127 0 0 1 . . . Официальное имя хоста: t01 Альтернативные имена: niisi.msk.ru t01.niisi.msk.ru mail mailhost loghost server server3 server3.systud.msk.su www www.systud.msk.su t01.systud.msk.su Тип адреса хоста: 2 Длина адреса хоста: 4 Сетевые адреса хоста: 193 232 173 1 . . . Официальное имя хоста: t17 Альтернативные имена: galatenko Тип адреса хоста: 2 Длина адреса хоста: 4 Сетевые адреса хоста: 193 232 173 17 . . . |
Листинг 11.3. Фрагмент возможных результатов работы программы, осуществляющей последовательный доступ к сетевой базе данных о хостах - узлах сети. |
Закрыть окно |
#include <sys/socket.h> #include <netdb.h> void freeaddrinfo (struct addrinfo *ai); int getaddrinfo (const char *restrict nodename, const char * restrict servname, const struct addrinfo *restrict hints, struct addrinfo **restrict res); int getnameinfo (const struct sockaddr *restrict sa, socklen_t salen, char *restrict node, socklen_t nodelen, char *restrict service, socklen_t servicelen, int flags); |
Листинг 11.4. Описание функций freeaddrinfo(), getaddrinfo(), getnameinfo(). |
Закрыть окно |
#include <arpa/inet.h> in_addr_t inet_addr (const char *cp); char *inet_ntoa (struct in_addr in); int inet_pton ( int af, const char *restrict src, void *restrict dst); const char *inet_ntop (int af, const void *restrict src, char *restrict dst, socklen_t size); |
Листинг 11.5. Описание функций преобразования IP-адресов из текстового представления в числовое и наоборот. |
Закрыть окно |
#include <arpa/inet.h> uint32_t htonl (uint32_t hostlong); uint16_t htons (uint16_t hostshort); uint32_t ntohl (uint32_t netlong); uint16_t ntohs (uint16_t netshort); |
Листинг 11.6. Описание функций преобразования целочисленных значений из хостового порядка байт в сетевой и наоборот. |
Закрыть окно |
#include <stdio.h> #include <netdb.h> #include <arpa/inet.h> int main (void) { struct addrinfo hints = {AI_CANONNAME, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; struct addrinfo *addr_res; if (getaddrinfo ("www", "http", &hints, &addr_res) != 0) { perror ("GETADDRINFO"); } else { printf ("Результаты для сервиса http\n"); /* Пройдем по списку возвращенных структур */ do { printf ("Адрес сокета: Порт: %d IP-адрес: %s\n", ntohs (((struct sockaddr_in *) addr_res->ai_addr)->sin_port), inet_ntoa (((struct sockaddr_in *) addr_res->ai_addr)->sin_addr)); printf ("Официальное имя хоста: %s\n", addr_res->ai_canonname); } while ((addr_res = addr_res->ai_next) != NULL); } return 0; } |
Листинг 11.7. Пример программы, использующей функцию getaddrinfo(). |
Закрыть окно |
Результаты для сервиса http Адрес сокета: Порт: 80 IP-адрес: 193.232.173.1 Официальное имя хоста: t01 |
Листинг 11.8. Возможный результат работы программы, использующей функцию getaddrinfo(). |
Закрыть окно |
#include <netdb.h> const char *gai_strerror (int ecode); |
Листинг 11.9. Описание функции gai_strerror(). |
Закрыть окно |
. . . int res; if ((res = getaddrinfo ("www", "HTTP", &hints, &addr_res)) != 0) { perror ("GETADDRINFO"); fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); } else { printf ("Результаты для сервиса HTTP\n"); . . . |
Листинг 11.10. Модифицированный фрагмент программы, использующей функции getaddrinfo() и gai_strerror(). |
Закрыть окно |
GETADDRINFO: No such file or directory GETADDRINFO: Servname not supported for ai_socktype |
Листинг 11.11. Диагностические сообщения от функций perror() и gai_strerror(), выданные по результатам работы функции getaddrinfo(). |
Закрыть окно |
#include <netdb.h> void setnetent (int stayopen); struct netent *getnetent (void); struct netent *getnetbyaddr ( uint32_t net, int type); struct netent *getnetbyname (const char *name); void endnetent (void); |
Листинг 11.12. Описание функций доступа к базе данных сетей. |
Закрыть окно |
#include <netdb.h> void setprotoent (int stayopen); struct protoent *getprotoent (void); struct protoent *getprotobyname (const char *name); struct protoent *getprotobynumber (int proto); void endprotoent (void); |
Листинг 11.13. Описание функций доступа к базе данных сетевых протоколов. |
Закрыть окно |
#include <stdio.h> #include <netdb.h> int main (void) { struct protoent *pht; char *pct; int i; setprotoent (1); while ((pht = getprotoent ()) != NULL) { printf (" Официальное имя протокола: %s\n", pht->p_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->p_aliases [i]) != NULL; i++) { printf (" %s\n", pct); } printf ("Номер протокола: %d\n\n", pht->p_proto); } if ((pht = getprotobyname ("ipv6")) != NULL) { printf ("Номер протокола ipv6: %d\n\n", pht->p_proto); } else { fprintf (stderr, "Протокол ip в базе не найден\n"); } if ((pht = getprotobyname ("IPV6")) != NULL) { printf ("Номер протокола IPV6: %d\n\n", pht->p_proto); } else { fprintf (stderr, "Протокол IPV6 в базе не найден\n"); } endprotoent (); return 0; } |
Листинг 11.14. Пример программы, осуществляющей последовательный и случайный доступ к базе данных сетевых протоколов. |
Закрыть окно |
Официальное имя протокола: ip Альтернативные имена: IP Номер протокола: 0 Официальное имя протокола: icmp Альтернативные имена: ICMP Номер протокола: 1 . . . Официальное имя протокола: tcp Альтернативные имена: TCP Номер протокола: 6 . . . Официальное имя протокола: udp Альтернативные имена: UDP Номер протокола: 17 . . . Официальное имя протокола: ipv6 Альтернативные имена: IPv6 Номер протокола: 41 . . . Официальное имя протокола: ipv6-crypt Альтернативные имена: IPv6-Crypt Номер протокола: 50 . . . Официальное имя протокола: visa Альтернативные имена: VISA Номер протокола: 70 . . . Официальное имя протокола: iso-ip Альтернативные имена: ISO-IP Номер протокола: 80 . . . Официальное имя протокола: sprite-rpc Альтернативные имена: Sprite-RPC Номер протокола: 90 . . . Официальное имя протокола: ipx-in-ip Альтернативные имена: IPX-in-IP Номер протокола: 111 . . . Официальное имя протокола: fc Альтернативные имена: FC Номер протокола: 133 Номер протокола ipv6: 41 Протокол IPV6 в базе не найден |
Листинг 11.15. Фрагмент возможных результатов работы программы, осуществляющей последовательный и случайный доступ к базе данных сетевых протоколов. |
Закрыть окно |
#include <netdb.h> void setservent (int stayopen); struct servent *getservent (void); struct servent *getservbyname (const char *name, const char *proto); struct servent *getservbyport ( int port, const char *proto); void endservent (void); |
Листинг 11.16. Описание функций доступа к базе данных сетевых сервисов. |
Закрыть окно |
#include <stdio.h> #include <netdb.h> int main (void) { struct servent *pht; char *pct; int i; setservent (1); while ((pht = getservent ()) != NULL) { printf (" Официальное имя сервиса: %s\n", pht->s_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->s_aliases [i]) != NULL; i++) { printf (" %s\n", pct); } printf ("Номер порта: %d\n", ntohs ((in_port_t) pht->s_port)); printf ("Имя протокола: %s\n\n", pht->s_proto); } if ((pht = getservbyport (htons ((in_port_t) 21), "udp")) != NULL) { printf ("Официальное имя сервиса: %s\n", pht->s_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->s_aliases [i]) != NULL; i++) { printf (" %s\n", pct); } printf ("Номер порта: %d\n", ntohs ((in_port_t) pht->s_port)); printf ("Имя протокола: %s\n\n", pht->s_proto); } else { perror ("GETSERVBYPORT"); } if ((pht = getservbyport (htons ((in_port_t) 21), (char *) NULL)) != NULL) { printf ("Официальное имя сервиса: %s\n", pht->s_name); printf ("Альтернативные имена:\n"); for (i = 0; (pct = pht->s_aliases [i]) != NULL; i++) { printf (" %s\n", pct); } printf ("Номер порта: %d\n", ntohs ((in_port_t) pht->s_port)); printf ("Имя протокола: %s\n\n", pht->s_proto); } else { perror ("GETSERVBYPORT"); } endservent (); return 0; } |
Листинг 11.17. Пример программы, использующей функции доступа к базе данных сервисов, а также функции преобразования между хостовым и сетевым порядками байт. |
Закрыть окно |
. . . Официальное имя сервиса: ftp- data Альтернативные имена: Номер порта: 20 Имя протокола: tcp Официальное имя сервиса: ftp-data Альтернативные имена: Номер порта: 20 Имя протокола: udp Официальное имя сервиса: ftp Альтернативные имена: Номер порта: 21 Имя протокола: tcp Официальное имя сервиса: ftp Альтернативные имена: fsp fspd Номер порта: 21 Имя протокола: udp . . . Официальное имя сервиса: kerberos Альтернативные имена: kerberos5 krb5 Номер порта: 88 Имя протокола: tcp Официальное имя сервиса: kerberos Альтернативные имена: kerberos5 krb5 Номер порта: 88 Имя протокола: udp . . . Официальное имя сервиса: auth Альтернативные имена: authentication tap ident Номер порта: 113 Имя протокола: tcp Официальное имя сервиса: auth Альтернативные имена: authentication tap ident Номер порта: 113 Имя протокола: udp . . . Официальное имя сервиса: printer Альтернативные имена: spooler Номер порта: 515 Имя протокола: tcp Официальное имя сервиса: printer Альтернативные имена: spooler Номер порта: 515 Имя протокола: udp . . . Официальное имя сервиса: fido Альтернативные имена: Номер порта: 60179 Имя протокола: tcp Официальное имя сервиса: fido Альтернативные имена: Номер порта: 60179 Имя протокола: udp Официальное имя сервиса: ftp Альтернативные имена: fsp fspd Номер порта: 21 Имя протокола: udp Официальное имя сервиса: ftp Альтернативные имена: Номер порта: 21 Имя протокола: tcp |
Листинг 11.18. Фрагмент возможных результатов работы программы, использующей функции доступа к базе данных сервисов, а также функции преобразования между хостовым и сетевым порядками байт. |
Закрыть окно |
#include <sys/socket.h> int socket ( int af, int type, int protocol); int socketpair (int af, int type, int protocol, int sds [2]); |
Листинг 11.19. Описание функций socket() и socketpair(). |
Закрыть окно |
#include <sys/socket.h> int bind ( int sd, const struct sockaddr *address, socklen_t address_len); |
Листинг 11.20. Описание функции bind(). |
Закрыть окно |
#include <sys/socket.h> int getsockname ( int sd, struct sockaddr *restrict address, socklen_t *restrict address_len); |
Листинг 11.21. Описание функции getsockname(). |
Закрыть окно |
#include <sys/socket.h> int listen ( int sd, int backlog); |
Листинг 11.22. Описание функции listen(). |
Закрыть окно |
#include <sys/socket.h> int accept ( int sd, struct sockaddr *restrict address, socklen_t *restrict address_len); |
Листинг 11.23. Описание функции accept(). |
Закрыть окно |
#include <sys/socket.h> int connect ( int sd, const struct sockaddr *address, socklen_t address_len); |
Листинг 11.24. Описание функции connect(). |
Закрыть окно |
#include <sys/select.h> int pselect (int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set * restrict errorfds, const struct timespec *restrict timeout, const sigset_t *restrict sigmask); int select (int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout); void FD_CLR (int fd, fd_set *fdset); int FD_ISSET (int fd, fd_set *fdset); void FD_SET (int fd, fd_set *fdset); void FD_ZERO (fd_set *fdset); |
Листинг 11.25. Описание функций семейства select*(). |
Закрыть окно |
#include <sys/socket.h> int getsockopt ( int sd, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len); int setsockopt (int sd, int level, int option_name, const void *option_value, socklen_t option_len); |
Листинг 11.26. Описание функций getsockopt() и setsockopt(). |
Закрыть окно |
#include <sys/socket.h> int getpeername ( int sd, struct sockaddr *restrict address, socklen_t *restrict address_len); |
Листинг 11.27. Описание функции getpeername(). |
Закрыть окно |
#include <sys/socket.h> ssize_t recvfrom (int sd, void * restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len); ssize_t recv (int sd, void *buffer, size_t length, int flags); ssize_t recvmsg (int sd, struct msghdr *message, int flags); ssize_t sendto (int sd, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len); ssize_t send (int sd, const void *buffer, size_t length, int flags); ssize_t sendmsg (int sd, const struct msghdr *message, int flags); |
Листинг 11.28. Описание функций обмена данными через сокет. |
Закрыть окно |
#include <sys/socket.h> int shutdown ( int sd, int how); |
Листинг 11.29. Описание функции shutdown(). |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа копирует строки со стандартного ввода на стандартный вывод, */ /* "прокачивая" их через пару сокетов. */ /* Используются функции ввода/вывода нижнего уровня */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/socket.h> #include <sys/wait.h> #define MY_PROMPT "Вводите строки\n" #define MY_MSG "Вы ввели: " int main (void) { int sds [2]; char buf [1]; int new_line = 1; /* Признак того, что надо выдать сообщение MY_MSG */ /* перед отображением очередной строки */ /* Создадим пару соединенных безымянных сокетов */ if (socketpair (AF_UNIX, SOCK_STREAM, 0, sds) < 0) { perror ("SOCKETPAIR"); exit (1); } switch (fork ()) { case -1: perror ("FORK"); exit (2); case 0: /* Чтение из сокета sds [0] и выдачу на стандартный вывод */ /* реализуем в порожденном процессе */ while (read (sds [0], buf, 1) == 1) { if (write (STDOUT_FILENO, buf, 1) != 1) { perror ("WRITE TO STDOUT"); break; } } exit (0); } /* Чтение со стандартного ввода и запись в сокет sds [1] */ /* возложим на родительский процесс */ if (write (sds [1], MY_PROMPT, sizeof (MY_PROMPT) - 1) != sizeof (MY_PROMPT) - 1) { perror ("WRITE TO SOCKET-1"); } while (read (STDIN_FILENO, buf, 1) == 1) { /* Перед отображением очередной строки */ /* нужно выдать сообщение MY_MSG */ if (new_line) { if (write (sds [1], MY_MSG, sizeof (MY_MSG) - 1) != sizeof (MY_MSG) - 1) { perror ("WRITE TO SOCKET-2"); break; } } if (write (sds [1], buf, 1) != 1) { perror ("WRITE TO SOCKET-3"); break; } new_line = (buf [0] == '\n'); } shutdown (sds [1], SHUT_WR); (void) wait (NULL); return (0); } |
Листинг 11.30. Пример программы, использующей сокеты адресного семейства AF_UNIX. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса, читающего строки со стандартного ввода */ /* и посылающего их в виде датаграмм другому процессу */ /* (будем называть его сервером), */ /* который должно выдать их на свой стандартный вывод. */ /* Имя серверного хоста - аргумент командной строки */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #include <string.h> #define MY_PROMPT "Вводите строки\n" int main (int argc, char *argv []) { int sd; /* Дескриптор передающего сокета */ char line [LINE_MAX]; /* Буфер для копируемых строк */ /* Структура - аргумент sendmsg */ struct msghdr msg = {NULL, 0, NULL, 0, NULL, 0, 0}; struct iovec iovbuf; /* Структура для сборки отправляемых данных */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {0, AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ int msg_len; /* Длина очередной введенной строки, */ /* включая завершающий нулевой байт */ if (argc != 2) { fprintf (stderr, "Использование: %s имя_серверного_хоста\n", argv [0]); return (1); } /* Создадим сокет, через который будем отправлять */ /* прочитанные строки */ if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror ("SOCKET"); return (2); } /* Выясним целевой адрес для датаграмм */ /* Воспользуемся портом для сервиса spooler */ if ((res = getaddrinfo (argv [1], "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (3); } /* Заполним структуру msghdr */ msg.msg_name = addr_res->ai_addr; msg.msg_namelen = addr_res->ai_addrlen; msg.msg_iov = &iovbuf; msg.msg_iovlen = 1; iovbuf.iov_base = line; /* Цикл чтения строк со стандартного ввода */ /* и отправки их через сокет в виде датаграмм */ fputs (MY_PROMPT, stdout); while (fgets (line, sizeof (line), stdin) != NULL) { msg_len = strlen (line) + 1; iovbuf.iov_len = msg_len; if (sendmsg (sd, &msg, 0) != msg_len) { perror ("SENDMSG"); break; } } return (0); } |
Листинг 11.31. Пример программы, использующей сокеты адресного семейства AF_INET для отправки датаграмм. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса (будем называть его сервером), */ /* читающего сообщения (строки) из датаграммного сокета */ /* и выдающего их на стандартный вывод */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #define MY_MSG "Вы ввели: " int main (void) { int sd; /* Дескриптор приемного сокета */ char line [LINE_MAX]; /* Буфер для копируемых строк */ /* Структура - аргумент recvmsg */ struct msghdr msg = {NULL, 0, NULL, 0, NULL, 0, 0}; struct iovec iovbuf; /* Структура для разнесения принимаемых данных */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {AI_PASSIVE, AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ /* Создадим сокет, через который будем принимать */ /* прочитанные строки */ if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror ("SOCKET"); return (1); } /* Привяжем этот сокет к адресу сервиса spooler на локальном хосте */ if ((res = getaddrinfo (NULL, "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (2); } if (bind (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("BIND"); return (3); } /* Можно освободить память, которую запрашивала функция getaddrinfo() */ freeaddrinfo (addr_res); /* Заполним структуру msghdr */ msg.msg_iov = &iovbuf; msg.msg_iovlen = 1; iovbuf.iov_base = line; iovbuf.iov_len = sizeof (line); /* Цикл приема и выдачи строк */ while (1) { if (recvmsg (sd, &msg, 0) < 0) { perror ("RECVMSG"); break; } fputs (MY_MSG, stdout); fputs (line, stdout); } return (0); } |
Листинг 11.32. Пример программы, использующей сокеты адресного семейства AF_INET для приема датаграмм. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса, читающего строки со стандартного ввода */ /* и посылающего их в виде датаграмм другому процессу */ /* (будем называть его сервером), */ /* который должно выдать их на свой стандартный вывод. */ /* Имя серверного хоста - аргумент командной строки */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #define MY_PROMPT "Вводите строки\n" int main (int argc, char *argv []) { int sd; /* Дескриптор передающего сокета */ FILE *ss; /* Поток, соответствующий передающему сокету */ char line [LINE_MAX]; /* Буфер для копируемых строк */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {0, AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ if (argc != 2) { fprintf (stderr, "Использование: %s имя_серверного_хоста\n", argv [0]); return (1); } /* Создадим сокет, через который будем отправлять */ /* прочитанные строки */ if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror ("SOCKET"); return (2); } /* Выясним целевой адрес для датаграмм */ /* Воспользуемся портом для сервиса spooler */ if ((res = getaddrinfo (argv [1], "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (3); } /* Воспользуемся функцией connect() для достижения двух целей: */ /* фиксации целевого адреса и привязки к некоему локальному */ if (connect (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("CONNECT"); return (4); } /* Сформирует поток по дескриптору сокета */ if ((ss = fdopen (sd, "w")) == NULL) { perror ("FDOPEN"); return (5); } /* Отменим буферизацию для этого потока */ setbuf (ss, NULL); /* Цикл чтения строк со стандартного ввода */ /* и отправки их через сокет в виде датаграмм */ fputs (MY_PROMPT, stdout); while (fgets (line, sizeof (line), stdin) != NULL) { fputs (line, ss); } return (0); } |
Листинг 11.33. Модифицированный вариант программы, использующей сокеты адресного семейства AF_INET для отправки датаграмм. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса (будем называть его сервером), */ /* читающего сообщения из датаграммного сокета */ /* и копирующего их на стандартный вывод */ /* с указанием адреса, откуда они поступили */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> int main (void) { int sd; /* Дескриптор приемного сокета */ /* Буфер для принимаемых сообщений */ /* Оставлено место для вставки нулевого байта */ char lbuf [BUFSIZ + 1]; /* Структура - аргумент recvmsg */ struct msghdr msg = {NULL, 0, NULL, 0, NULL, 0, 0}; struct iovec iovbuf; /* Структура для разнесения принимаемых данных */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {AI_PASSIVE, AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ /* Структура для исходного адреса датаграмм */ struct sockaddr_in sai; ssize_t lmsg; /* Длина принятой датаграммы */ /* Создадим сокет, через который будем принимать */ /* прочитанные строки */ if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror ("SOCKET"); return (1); } /* Привяжем этот сокет к адресу сервиса spooler на локальном хосте */ if ((res = getaddrinfo (NULL, "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (1); } if (bind (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("BIND"); return (2); } /* Можно освободить память, которую запрашивала функция getaddrinfo() */ freeaddrinfo (addr_res); /* Заполним структуру msghdr */ msg.msg_name = &sai; msg.msg_namelen = sizeof (struct sockaddr_in); msg.msg_iov = &iovbuf; msg.msg_iovlen = 1; iovbuf.iov_base = lbuf; /* Оставим место для вставки нулевого байта */ iovbuf.iov_len = sizeof (lbuf) - 1; /* Цикл приема и выдачи строк */ while (1) { if ((lmsg = recvmsg (sd, &msg, 0)) < 0) { perror ("RECVMSG"); break; } printf ("Вы ввели и отправили с адреса %s, порт %d :", inet_ntoa (((struct sockaddr_in *) msg.msg_name)->sin_addr), ntohs (((struct sockaddr_in *) msg.msg_name)->sin_port)); if (msg.msg_flags & MSG_TRUNC) { printf ("Датаграмма была урезана\n"); } lbuf [lmsg] = 0; fputs (lbuf, stdout); } return (0); } |
Листинг 11.34. Модифицированный вариант программы, использующей сокеты адресного семейства AF_INET для приема датаграмм. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса, читающего строки со стандартного ввода */ /* и посылающего их в виде потока другому процессу */ /* (будем называть его сервером), */ /* который должно выдать строки на свой стандартный вывод. */ /* Имя серверного хоста - аргумент командной строки */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #define MY_PROMPT "Вводите строки\n" int main (int argc, char *argv []) { int sd; /* Дескриптор передающего сокета */ FILE *ss; /* Поток, соответствующий передающему сокету */ char line [LINE_MAX]; /* Буфер для копируемых строк */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {0, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ if (argc != 2) { fprintf (stderr, "Использование: %s имя_серверного_хоста\n", argv [0]); return (1); } /* Создадим сокет, через который будем отправлять */ /* прочитанные строки */ if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror ("SOCKET"); return (2); } /* Выясним целевой адрес для соединения */ /* Воспользуемся портом для сервиса spooler */ if ((res = getaddrinfo (argv [1], "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (3); } /* Воспользуемся функцией connect() для достижения двух целей: */ /* установления соединения и привязки к некоему локальному адресу */ if (connect (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("CONNECT"); return (4); } /* Сформируем поток по дескриптору сокета */ if ((ss = fdopen (sd, "w")) == NULL) { perror ("FDOPEN"); return (5); } /* Отменим буферизацию для этого потока */ setbuf (ss, NULL); /* Цикл чтения строк со стандартного ввода */ /* и отправки их через сокет в виде потока */ fputs (MY_PROMPT, stdout); while (fgets (line, sizeof (line), stdin) != NULL) { fputs (line, ss); } shutdown (sd, SHUT_WR); return (0); } |
Листинг 11.35. Пример программы, использующей режим с установлением соединения и сокеты типа SOCK_STREAM для пересылки строк. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса (будем называть его демоном), */ /* принимающего запросы на установления соединения */ /* и запускающего процессы для их обслуживания */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <netdb.h> #include <sys/socket.h> #include <sys/wait.h> int main (void) { int sd; /* Дескриптор слушающего сокета */ int ad; /* Дескриптор приемного сокета */ /* Буфер для принимаемых строк */ struct addrinfo hints = {AI_PASSIVE, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ /* Создадим слушающий сокет */ if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror ("SOCKET"); return (1); } /* Привяжем этот сокет к адресу сервиса spooler на локальном хосте */ if ((res = getaddrinfo (NULL, "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (1); } if (bind (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("BIND"); return (2); } /* Можно освободить память, которую запрашивала функция getaddrinfo() */ freeaddrinfo (addr_res); /* Пометим сокет как слушающий */ if (listen (sd, SOMAXCONN) < 0) { perror ("LISTEN"); return (3); } /* Цикл приема соединений и запуска обслуживающих процессов */ while (1) { /* Примем соединение. */ /* Адрес партнера по общению нас в данном случае не интересует */ if ((ad = accept (sd, NULL, NULL)) < 0) { perror ("ACCEPT"); return (4); } /* Запустим обслуживающий процесс */ switch (fork ()) { case -1: perror ("FORK"); return (5); case 0: /* Сделаем сокет ad стандартным вводом */ (void) close (STDIN_FILENO); (void) fcntl (ad, F_DUPFD, STDIN_FILENO); (void) close (ad); /* Сменим программу процесса на обслуживающую */ if (execl ("./gsce", "gsce", (char *) NULL) < 0) { perror ("EXECL"); return (6); } } /* В родительском процессе дескриптор принятого соединения нужно закрыть */ (void) close (ad); /* Обслужим завершившиеся порожденные процессы */ while (waitpid ((pid_t) (-1), NULL, WNOHANG) > 0) ; } return (0); } |
Листинг 11.36. Пример программы, принимающей запросы на установление соединения. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа обслуживающего процесса, */ /* выдающего принимаемые строки на стандартный вывод. */ /* Дескриптор приемного сокета передан */ /* в качестве стандартного ввода */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> int main (void) { char line [LINE_MAX]; /* Буфер для принимаемых строк */ /* Структура для записи адреса */ struct sockaddr_in sai; /* Длина адреса */ socklen_t sai_len = sizeof (struct sockaddr_in); /* Опросим адрес партнера по общению (передающего сокета) */ if (getpeername (STDIN_FILENO, (struct sockaddr *) &sai, &sai_len) < 0) { perror ("GETPEERNAME"); return (1); } /* Цикл чтения строк из сокета */ /* и выдачи их на стандартный вывод */ while (fgets (line, sizeof (line), stdin) != NULL) { printf ("Вы ввели и отправили с адреса %s, порт %d :", inet_ntoa (sai.sin_addr), ntohs (sai.sin_port)); fputs (line, stdout); } /* Закрытие соединения */ shutdown (STDIN_FILENO, SHUT_RD); return (0); } |
Листинг 11.37. Пример программы, обрабатывающей данные, поступающие через сокет типа SOCK_STREAM. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса (будем называть его демоном), */ /* принимающего запросы на установления соединения */ /* и запускающего процессы для их обслуживания */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <netdb.h> #include <sys/socket.h> #include <sys/wait.h> #include <signal.h> #include <errno.h> /* Функция обработки сигнала SIGCHLD */ static void chldied (int dummy) { /* Вдруг число завершившихся потомков отлично от единицы? */ while (waitpid ((pid_t) (-1), NULL, WNOHANG) > 0) ; } int main (void) { int sd; /* Дескриптор слушающего сокета */ int ad; /* Дескриптор приемного сокета */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {AI_PASSIVE, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ /* Структура для задания реакции на сигнал SIGCHLD */ struct sigaction sact; /* Создадим слушающий сокет */ if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror ("SOCKET"); return (1); } /* Привяжем этот сокет к адресу сервиса spooler на локальном хосте */ if ((res = getaddrinfo (NULL, "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (1); } if (bind (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("BIND"); return (2); } /* Можно освободить память, которую запрашивала функция getaddrinfo() */ freeaddrinfo (addr_res); /* Пометим сокет как слушающий */ if (listen (sd, SOMAXCONN) < 0) { perror ("LISTEN"); return (3); } /* Установим обработку сигнала о завершении потомка */ sact.sa_handler = chldied; (void) sigemptyset (&sact.sa_mask); sact.sa_flags = 0; (void) sigaction (SIGCHLD, &sact, (struct sigaction *) NULL); /* Цикл приема соединений и запуска обслуживающих процессов */ while (1) { /* Примем соединение с учетом того, что ожидание может быть прервано */ /* доставкой обрабатываемого сигнала. */ /* Адрес партнера по общению в данном случае нас не интересует */ while ((ad = accept (sd, NULL, NULL)) < 0) { if (errno != EINTR) { perror ("ACCEPT"); return (4); } } /* Запустим обслуживающий процесс */ switch (fork ()) { case -1: perror ("FORK"); return (5); case 0: /* Сделаем сокет ad стандартным вводом */ (void) close (STDIN_FILENO); (void) fcntl (ad, F_DUPFD, STDIN_FILENO); (void) close (ad); /* Сменим программу процесса на обслуживающую */ if (execl ("./gsce", "gsce", (char *) NULL) < 0) { perror ("EXECL"); return (6); } } /* В родительском процессе дескриптор принятого соединения нужно закрыть */ (void) close (ad); } return (0); } |
Листинг 11.38. Пример программы, принимающей запросы на установление соединения с учетом того, что ожидание может быть прервано доставкой обрабатываемого сигнала. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса (будем называть его сервером), */ /* принимающего запросы на установления соединения */ /* и обслуживающего их с использованием select() */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/select.h> /* Структура для хранения дескрипторов приемных сокетов */ /* и ассоциированной информации */ #define MY_MSG_LN 128 struct sads { int ad; FILE *sd; char my_msg [MY_MSG_LN]; }; /* Максимальное число параллельно обслуживаемых запросов */ #define MY_MAX_QS FD_SETSIZE /* Функция для освобождения элемента массива */ /* дескрипторов приемных сокетов */ static void free_elem (struct sads *sadsp) { shutdown (sadsp->ad, SHUT_RD); close (sadsp->ad); sadsp->ad = -1; } int main (void) { int sd; /* Дескриптор слушающего сокета */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {AI_PASSIVE, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ fd_set rdset; /* Набор дескрипторов для чтения */ /* Структура для записи адреса */ struct sockaddr_in sai; socklen_t sai_len; /* Длина адреса */ char line [LINE_MAX]; /* Буфер для принимаемых строк */ /* Массов для хранения дескрипторов приемных сокетов */ /* и ассоциированной информации. */ /* Последний элемент - фиктивный, */ /* нужен для упрощения поиска свободного */ struct sads sadsarr [MY_MAX_QS + 1]; int sads_max; /* Верхняя граница дескрипторов, проверяемых select() */ int i; /* Создадим слушающий сокет */ if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror ("SOCKET"); return (1); } /* Привяжем этот сокет к адресу сервиса spooler на локальном хосте */ if ((res = getaddrinfo (NULL, "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (1); } if (bind (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("BIND"); return (2); } /* Можно освободить память, которую запрашивала функция getaddrinfo() */ freeaddrinfo (addr_res); /* Пометим сокет как слушающий */ if (listen (sd, SOMAXCONN) < 0) { perror ("LISTEN"); return (3); } /* Инициализируем массив sadsarr. */ /* -1 в поле ad означает, что элемент свободен */ for (i = 0; i < (MY_MAX_QS + 1); i++) { sadsarr [i].ad = -1; } /* Цикл приема соединений и обслуживания запросов */ while (1) { /* Подготовим наборы дескрипторов для select() */ FD_ZERO (&rdset); FD_SET (sd, &rdset); sads_max = sd + 1; for (i = 0; i < MY_MAX_QS; i++) { if (sadsarr [i].ad >= 0) { FD_SET (sadsarr [i].ad, &rdset); if ((sadsarr [i].ad + 1) > sads_max) { sads_max = sadsarr [i].ad + 1; } } } /* Подождем запроса на установление соединения */ /* или готовности данных для чтения. */ /* Время ожидания зададим как бесконечное */ if (select (sads_max, &rdset, NULL, NULL, NULL) == -1) { perror ("PSELECT"); return (4); } /* Посмотрим, есть ли запросы, ждущие установления соединения */ if (FD_ISSET (sd, &rdset)) { /* Примем запрос на установление соединения, */ /* если есть свободный элемент массива дескрипторов. */ /* Последний элемент считаем фиктивным; он всегда свободен */ i = -1; while (sadsarr [++i].ad >= 0) ; if (i < MY_MAX_QS) { /* Свободный элемент нашелся */ sai_len = sizeof (struct sockaddr_in); if ((sadsarr [i].ad = accept (sd, (struct sockaddr *) &sai, &sai_len)) == -1) { perror ("ACCEPT"); continue; } /* Сформируем сообщение, выдаваемое перед принятой строкой */ (void) sprintf (sadsarr [i].my_msg, "Вы ввели и отправили с адреса %s, порт %d :", inet_ntoa (sai.sin_addr), ntohs (sai.sin_port)); /* Сформируем поток по дескриптору сокета */ /* и отменим буферизацию для этого потока */ if ((sadsarr [i].sd = fdopen (sadsarr [i].ad, "r")) == NULL) { perror ("FDOPEN"); free_elem (&sadsarr [i]); continue; } setbuf (sadsarr [i].sd, NULL); } } /* Посмотрим, есть ли данные, готовые для чтения */ for (i = 0; i < MY_MAX_QS; i++) { if ((sadsarr [i].ad >= 0) & FD_ISSET (sadsarr [i].ad, &rdset)) { /* Есть данные, готовые для чтения, */ /* или установлен признак конца файла */ if (fgets (line, sizeof (line), sadsarr [i].sd) != NULL) { /* Выведем полученную строку */ fputs (sadsarr [i].my_msg, stdout); fputs (line, stdout); } else { /* Отправитель закрыл соединение. */ /* Закроем его и мы */ fclose (sadsarr [i].sd); free_elem (&sadsarr [i]); } } } } return (0); } |
Листинг 11.39. Пример программы, мультиплексирующей ввод через сокеты с помощью функции select(). |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа вычисляет несколько первых строк треугольника Паскаля */ /* и отправляет их через сокет сервису spooler. */ /* Имя целевого хоста - аргумент командной строки. */ /* Передаваемые данные снабжаются однобайтными маркерами типа */ /* и кратности и преобразуются к сетевому порядку байт */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <netdb.h> #include <sys/socket.h> /* Количество вычисляемых строк треугольника Паскаля */ #define T_SIZE 16 /* Маркеры типов передаваемых данных */ #define T_UCHAR 1 #define T_UINT16 2 #define T_UINT32 4 #define T_HDR "\nТреугольник Паскаля:" int main (int argc, char *argv []) { uint32_t tp [T_SIZE]; /* Массив для хранения текущей строки треугольника */ unsigned char mtl; /* Переменная для хранения маркеров типа и кратности */ uint32_t ntelem; /* Текущий элемент строки в сетевом порядке байт */ int sd; /* Дескриптор передающего сокета */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {0, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ int i, j; if (argc != 2) { fprintf (stderr, "Использование: %s имя_серверного_хоста\n", argv [0]); return (1); } /* Создадим передающий сокет и установим соединение */ if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror ("SOCKET"); return (2); } if ((res = getaddrinfo (argv [1], "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (3); } if (connect (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("CONNECT"); return (4); } /* Инициализируем массив для хранения текущей строки треугольника Паскаля, */ /* чтобы далее все элементы можно было считать и передавать единообразно */ tp [0] = 1; for (i = 1; i < T_SIZE; i++) { tp [i] = 0; } /* Передадим заголовок */ mtl = T_UCHAR; if (write (sd, &mtl, 1) != 1) { perror ("WRITE-1"); return (5); } mtl = sizeof (T_HDR) - 1; if (write (sd, &mtl, 1) != 1) { perror ("WRITE-2"); return (6); } if (write (sd, T_HDR, mtl) != mtl) { perror ("WRITE-3"); return (7); } /* Вычислим и передадим строки треугольника Паскаля */ for (i = 0; i < T_SIZE; i++) { /* Элементы очередной строки нужно считать от конца к началу */ /* Элемент tp [0] пересчитывать не нужно */ for (j = i; j > 0; j--) { tp [j] += tp [j - 1]; } /* Вывод строки треугольника в сокет */ mtl = T_UINT32; if (write (sd, &mtl, 1) != 1) { perror ("WRITE-4"); return (8); } mtl = i + 1; if (write (sd, &mtl, 1) != 1) { perror ("WRITE-5"); return (9); } /* Преобразование элементов строки к сетевому порядку байт и вывод */ for (j = 0; j <= i; j++) { ntelem = htonl (tp [j]); if (write (sd, &ntelem, sizeof (ntelem)) != sizeof (ntelem)) { perror ("WRITE-6"); return (10); } } } shutdown (sd, SHUT_WR); return (close (sd)); } |
Листинг 11.40. Пример программы, передающей через сокеты целочисленные данные. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа процесса (будем называть его наивным сервером), */ /* принимающего запросы на установления соединения */ /* и осуществляющего вывод поступающих числовых данных */ /* без порождения процессов и мультиплексирования */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> /* Маркеры типов передаваемых данных */ #define T_UCHAR 1 #define T_UINT16 2 #define T_UINT32 4 int main (void) { int sd; /* Дескриптор слушающего сокета */ int ad; /* Дескриптор приемного сокета */ /* Структура - входной аргумент getaddrinfo */ struct addrinfo hints = {AI_PASSIVE, AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; /* Указатель - выходной аргумент getaddrinfo */ struct addrinfo *addr_res; int res; /* Результат getaddrinfo */ /* Структура для записи адреса */ struct sockaddr_in sai; socklen_t sai_len; /* Длина адреса */ char mt; /* Маркер типа поступающих данных */ char ml; /* Маркер кратности поступающих данных */ char bufc; /* Буфер для приема символьных данных */ uint16_t buf16; /* Буфер для приема 16-разрядных целых */ uint32_t buf32; /* Буфер для приема 16-разрядных целых */ /* Создадим слушающий сокет */ if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror ("SOCKET"); return (1); } /* Привяжем этот сокет к адресу сервиса spooler на локальном хосте */ if ((res = getaddrinfo (NULL, "spooler", &hints, &addr_res)) != 0) { fprintf (stderr, "GETADDRINFO: %s\n", gai_strerror (res)); return (1); } if (bind (sd, addr_res->ai_addr, addr_res->ai_addrlen) < 0) { perror ("BIND"); return (2); } /* Можно освободить память, которую запрашивала функция getaddrinfo() */ freeaddrinfo (addr_res); /* Пометим сокет как слушающий */ if (listen (sd, SOMAXCONN) < 0) { perror ("LISTEN"); return (3); } /* Цикл приема соединений и обслуживания запросов на вывод */ while (1) { /* Примем соединение */ sai_len = sizeof (struct sockaddr_in); if ((ad = accept (sd, (struct sockaddr *) &sai, &sai_len)) < 0) { perror ("ACCEPT"); continue; } /* Цикл приема поступающих данных и их вывода */ printf ("Получено с адреса %s, порт %d :", inet_ntoa (sai.sin_addr), ntohs (sai.sin_port)); while (read (ad, &mt, 1) == 1) { /* Есть очередная порция данных, начинающаяся с типа. */ /* Прочитаем кратность, потом сами данные */ if (read (ad, &ml, 1) != 1) { perror ("READ-1"); return (4); } while (ml-- > 0) { switch (mt) { case T_UCHAR: if (read (ad, &bufc, sizeof (bufc)) != sizeof (bufc)) { perror ("READ-2"); return (5); } printf ("%c", bufc); continue; case T_UINT16: if (read (ad, &buf16, sizeof (buf16)) != sizeof (buf16)) { perror ("READ-3"); return (6); } printf (" %d", ntohs (buf16)); continue; case T_UINT32: if (read (ad, &buf32, sizeof (buf32)) != sizeof (buf32)) { perror ("READ-4"); return (7); } printf (" %d", ntohl (buf32)); continue; } } /* Вывод порции завершим переводом строки */ printf ("\n"); } /* Конец обслуживания соединения */ (void) close (ad); } return (0); } |
Листинг 11.41. Пример программы, принимающей через сокеты целочисленные данные. |
Закрыть окно |