Программирование в стандарте POSIX


Описание функций последовательного доступа


#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. Пример программы, принимающей через сокеты целочисленные данные.
Закрыть окно



Содержание раздела