Unix网络编程代码 第8章 基本UDP套接字编程

来源:互联网 发布:软件项目里程碑计划 编辑:程序博客网 时间:2024/06/05 01:10

第8章 基本UDP套接字编程

8.3 UDP回射服务器程序

#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<string.h>#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<stdarg.h>/* ANSI C header file */#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Bind(int fd, const struct sockaddr *sa, socklen_t salen){if (bind(fd, sa, salen) < 0)err_sys("bind error");}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr *sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}void dg_echo(int sockfd, SA * pcliaddr, socklen_t clilen){int n;socklen_t len;char mesg[MAXLINE];for (;;) {len = clilen;n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);Sendto(sockfd, mesg, n, 0, pcliaddr, len);}}int main(){int sockfd;struct sockaddr_in servaddr, cliaddr;sockfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(sockfd, (SA *) & servaddr, sizeof(servaddr));dg_echo(sockfd, (SA *) & cliaddr, sizeof(cliaddr));}

8.5 UDP回射客户程序

#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<stdarg.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#include<errno.h>#include<arpa/inet.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) < 0)err_sys("inet_pton error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}char *Fgets(char *ptr, int n, FILE * stream){char *rptr;if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))err_sys("fgets error");return (rptr);}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr * sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}void Fputs(const char *ptr, FILE * stream){if (fputs(ptr, stream) == EOF)err_sys("fputs error");}void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen){int n;char sendline[MAXLINE], recvline[MAXLINE + 1];while (Fgets(sendline, MAXLINE, fp) != NULL) {Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr,       servlen);n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);recvline[n] = 0;/* null terminate */Fputs(recvline, stdout);}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);sockfd = Socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));exit(0);}

8.8 验证接收到的响应

#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<sys/un.h>#include<stdarg.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#include<errno.h>#include<arpa/inet.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) < 0)err_sys("inet_pton error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}char *Fgets(char *ptr, int n, FILE * stream){char *rptr;if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))err_sys("fgets error");return (rptr);}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr * sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}void Fputs(const char *ptr, FILE * stream){if (fputs(ptr, stream) == EOF)err_sys("fputs error");}void *Malloc(size_t size){void *ptr;if ((ptr = malloc(size)) == NULL)err_sys("malloc error");return (ptr);}char *sock_ntop(const struct sockaddr *sa, socklen_t salen){char portstr[8];static char str[128];/* Unix domain is largest */switch (sa->sa_family) {case AF_INET:{struct sockaddr_in *sin = (struct sockaddr_in *)sa;if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))    == NULL)return (NULL);if (ntohs(sin->sin_port) != 0) {snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));strcat(str, portstr);}return (str);}/* end sock_ntop */#ifdefIPV6case AF_INET6:{struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;str[0] = '[';if (inet_ntop    (AF_INET6, &sin6->sin6_addr, str + 1,     sizeof(str) - 1) == NULL)return (NULL);if (ntohs(sin6->sin6_port) != 0) {snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));strcat(str, portstr);return (str);}return (str + 1);}#endif#ifdefAF_UNIXcase AF_UNIX:{struct sockaddr_un *unp = (struct sockaddr_un *)sa;/* OK to have no pathname bound to the socket: happens on   every connect() unless client calls bind() first. */if (unp->sun_path[0] == 0)strcpy(str, "(no pathname bound)");elsesnprintf(str, sizeof(str), "%s", unp->sun_path);return (str);}#endif#ifdefHAVE_SOCKADDR_DL_STRUCTcase AF_LINK:{struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;if (sdl->sdl_nlen > 0)snprintf(str, sizeof(str), "%*s (index %d)", sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index);elsesnprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);return (str);}#endifdefault:snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen);return (str);}return (NULL);}char *Sock_ntop(const struct sockaddr *sa, socklen_t salen){char *ptr;if ((ptr = sock_ntop(sa, salen)) == NULL)err_sys("sock_ntop error");/* inet_ntop() sets errno */return (ptr);}void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen){int n;char sendline[MAXLINE], recvline[MAXLINE + 1];socklen_t len;struct sockaddr *preply_addr;preply_addr = (struct sockaddr *)Malloc(servlen);while (Fgets(sendline, MAXLINE, fp) != NULL) {Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr,       servlen);len = servlen;n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);if (len != servlen || memcmp(pservaddr, preply_addr, len) != 0) {printf("reply from %s (ignored)\n",       Sock_ntop(preply_addr, len));continue;}recvline[n] = 0;/* null terminate */Fputs(recvline, stdout);}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);sockfd = Socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));exit(0);}

8.12 dg_cli函数(修订版)

//调用connect版本//运行结果跟书上不符:向一个不可达的主机发起连接,没有返回连接拒绝的错误,read永远阻塞#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<stdarg.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#include<errno.h>#include<arpa/inet.h>#include<unistd.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) < 0)err_sys("inet_pton error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}char *Fgets(char *ptr, int n, FILE * stream){char *rptr;if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))err_sys("fgets error");return (rptr);}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr * sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}void Fputs(const char *ptr, FILE * stream){if (fputs(ptr, stream) == EOF)err_sys("fputs error");}void Connect(int fd, const struct sockaddr *sa, socklen_t salen){if (connect(fd, sa, salen) < 0)err_sys("connect error");}void Write(int fd, void *ptr, int nbytes){if (write(fd, ptr, nbytes) != nbytes)err_sys("write error");}ssize_t Read(int fd, void *ptr, size_t nbytes){ssize_t n;if ((n = read(fd, ptr, nbytes)) == -1)err_sys("read error");return (n);}void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen){int n;char sendline[MAXLINE], recvline[MAXLINE + 1];Connect(sockfd, (SA *) pservaddr, servlen);while (Fgets(sendline, MAXLINE, fp) != NULL) {Write(sockfd, sendline, strlen(sendline));n = Read(sockfd, recvline, MAXLINE);recvline[n] = 0;/* null terminate */Fputs(recvline, stdout);}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);sockfd = Socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));exit(0);}

8.13 UDP缺乏流量控制

8.13.1 写固定数目的数据报的客户端

#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<stdarg.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#include<errno.h>#include<arpa/inet.h>#include<unistd.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) < 0)err_sys("inet_pton error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}char *Fgets(char *ptr, int n, FILE * stream){char *rptr;if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))err_sys("fgets error");return (rptr);}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr * sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}#defineNDG2000/* datagrams to send */#defineDGLEN1400/* length of each datagram */void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen){int i;char sendline[DGLEN];for (i = 0; i < NDG; i++) {Sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);sockfd = Socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));exit(0);}

8.13.2 对接收数目进行计数的服务器端

#define _POSIX_SOURCE#include<strings.h>#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<string.h>#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<stdarg.h>/* ANSI C header file */#include<signal.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrtypedef void Sigfunc(int);/* for signal handlers */void err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Bind(int fd, const struct sockaddr *sa, socklen_t salen){if (bind(fd, sa, salen) < 0)err_sys("bind error");}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr *sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}static int count;void recvfrom_int(int signo){printf("\nreceived %d datagrams\n", count);exit(0);}Sigfunc *signal(int signo, Sigfunc * func){struct sigaction act, oact;act.sa_handler = func;sigemptyset(&act.sa_mask);act.sa_flags = 0;if (signo == SIGALRM) {#ifdefSA_INTERRUPTact.sa_flags |= SA_INTERRUPT;/* SunOS 4.x */#endif} else {#ifdefSA_RESTARTact.sa_flags |= SA_RESTART;/* SVR4, 44BSD */#endif}if (sigaction(signo, &act, &oact) < 0)return (SIG_ERR);return (oact.sa_handler);}Sigfunc *Signal(int signo, Sigfunc * func){/* for our signal() function */Sigfunc *sigfunc;if ((sigfunc = signal(signo, func)) == SIG_ERR)err_sys("signal error");return (sigfunc);}void dg_echo(int sockfd, SA * pcliaddr, socklen_t clilen){socklen_t len;char mesg[MAXLINE];Signal(SIGINT, recvfrom_int);for (;;) {len = clilen;Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);count++;}}int main(){int sockfd;struct sockaddr_in servaddr, cliaddr;sockfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(sockfd, (SA *) & servaddr, sizeof(servaddr));dg_echo(sockfd, (SA *) & cliaddr, sizeof(cliaddr));}

8.13.3 增大套接字接收队列大小

#define _POSIX_SOURCE#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<string.h>#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<stdarg.h>/* ANSI C header file */#include<signal.h>#include<strings.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrtypedef void Sigfunc(int);/* for signal handlers */void err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Bind(int fd, const struct sockaddr *sa, socklen_t salen){if (bind(fd, sa, salen) < 0)err_sys("bind error");}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr *sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}static int count;void recvfrom_int(int signo){printf("\nreceived %d datagrams\n", count);exit(0);}Sigfunc *signal(int signo, Sigfunc * func){struct sigaction act, oact;act.sa_handler = func;sigemptyset(&act.sa_mask);act.sa_flags = 0;if (signo == SIGALRM) {#ifdefSA_INTERRUPTact.sa_flags |= SA_INTERRUPT;/* SunOS 4.x */#endif} else {#ifdefSA_RESTARTact.sa_flags |= SA_RESTART;/* SVR4, 44BSD */#endif}if (sigaction(signo, &act, &oact) < 0)return (SIG_ERR);return (oact.sa_handler);}Sigfunc *Signal(int signo, Sigfunc * func){/* for our signal() function */Sigfunc *sigfunc;if ((sigfunc = signal(signo, func)) == SIG_ERR)err_sys("signal error");return (sigfunc);}void Setsockopt(int fd, int level, int optname, const void *optval,socklen_t optlen){if (setsockopt(fd, level, optname, optval, optlen) < 0)err_sys("setsockopt error");}void dg_echo(int sockfd, SA * pcliaddr, socklen_t clilen){int n;socklen_t len;char mesg[MAXLINE];Signal(SIGINT, recvfrom_int);n = 220 * 1024;Setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));for (;;) {len = clilen;Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);count++;}}int main(){int sockfd;struct sockaddr_in servaddr, cliaddr;sockfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(sockfd, (SA *) & servaddr, sizeof(servaddr));dg_echo(sockfd, (SA *) & cliaddr, sizeof(cliaddr));}

8.14 UDP中的外出接口的确定

#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<stdarg.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#include<errno.h>#include<arpa/inet.h>#include<unistd.h>#include<sys/un.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) < 0)err_sys("inet_pton error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}char *Fgets(char *ptr, int n, FILE * stream){char *rptr;if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))err_sys("fgets error");return (rptr);}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr * sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}void Connect(int fd, const struct sockaddr *sa, socklen_t salen){if (connect(fd, sa, salen) < 0)err_sys("connect error");}void Getsockname(int fd, struct sockaddr *sa, socklen_t * salenptr){if (getsockname(fd, sa, salenptr) < 0)err_sys("getsockname error");}char *sock_ntop(const struct sockaddr *sa, socklen_t salen){char portstr[8];static char str[128];/* Unix domain is largest */switch (sa->sa_family) {case AF_INET:{struct sockaddr_in *sin = (struct sockaddr_in *)sa;if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))    == NULL)return (NULL);if (ntohs(sin->sin_port) != 0) {snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));strcat(str, portstr);}return (str);}/* end sock_ntop */#ifdefIPV6case AF_INET6:{struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;str[0] = '[';if (inet_ntop    (AF_INET6, &sin6->sin6_addr, str + 1,     sizeof(str) - 1) == NULL)return (NULL);if (ntohs(sin6->sin6_port) != 0) {snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));strcat(str, portstr);return (str);}return (str + 1);}#endif#ifdefAF_UNIXcase AF_UNIX:{struct sockaddr_un *unp = (struct sockaddr_un *)sa;/* OK to have no pathname bound to the socket: happens on   every connect() unless client calls bind() first. */if (unp->sun_path[0] == 0)strcpy(str, "(no pathname bound)");elsesnprintf(str, sizeof(str), "%s", unp->sun_path);return (str);}#endif#ifdefHAVE_SOCKADDR_DL_STRUCTcase AF_LINK:{struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;if (sdl->sdl_nlen > 0)snprintf(str, sizeof(str), "%*s (index %d)", sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index);elsesnprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);return (str);}#endifdefault:snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen);return (str);}return (NULL);}char *Sock_ntop(const struct sockaddr *sa, socklen_t salen){char *ptr;if ((ptr = sock_ntop(sa, salen)) == NULL)err_sys("sock_ntop error");/* inet_ntop() sets errno */return (ptr);}int main(int argc, char **argv){int sockfd;socklen_t len;struct sockaddr_in cliaddr, servaddr;if (argc != 2)err_quit("usage: udpcli <IPaddress>");sockfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) & servaddr, sizeof(servaddr));len = sizeof(cliaddr);Getsockname(sockfd, (SA *) & cliaddr, &len);printf("local address %s\n", Sock_ntop((SA *) & cliaddr, len));exit(0);}

8.15 使用select函数的TCP和UDP回射服务器程序

#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */#include<strings.h>#include<sys/select.h>#include<string.h>#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<stdarg.h>/* ANSI C header file */#include<signal.h>#include<unistd.h>#include<sys/wait.h>#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */#defineLISTENQ1024/* 2nd argument to listen() */#definemax(a,b)((a) > (b) ? (a) : (b))#defineSAstruct sockaddrtypedef void Sigfunc(int);/* for signal handlers */void err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)err_sys("socket error");return (n);}void Bind(int fd, const struct sockaddr *sa, socklen_t salen){if (bind(fd, sa, salen) < 0)err_sys("bind error");}ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr *sa, socklen_t * salenptr){ssize_t n;if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)err_sys("recvfrom error");return (n);}void Sendto(int fd, const void *ptr, size_t nbytes, int flags,    const struct sockaddr *sa, socklen_t salen){if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)err_sys("sendto error");}Sigfunc *Signal(int signo, Sigfunc * func){/* for our signal() function */Sigfunc *sigfunc;if ((sigfunc = signal(signo, func)) == SIG_ERR)err_sys("signal error");return (sigfunc);}void Setsockopt(int fd, int level, int optname, const void *optval,socklen_t optlen){if (setsockopt(fd, level, optname, optval, optlen) < 0)err_sys("setsockopt error");}void Listen(int fd, int backlog){char *ptr;/*4can override 2nd argument with environment variable */if ((ptr = getenv("LISTENQ")) != NULL)backlog = atoi(ptr);if (listen(fd, backlog) < 0)err_sys("listen error");}int Accept(int fd, struct sockaddr *sa, socklen_t * salenptr){int n; again:if ((n = accept(fd, sa, salenptr)) < 0) {#ifdefEPROTOif (errno == EPROTO || errno == ECONNABORTED)#elseif (errno == ECONNABORTED)#endifgoto again;elseerr_sys("accept error");}return (n);}pid_t Fork(void){pid_t pid;if ((pid = fork()) == -1)err_sys("fork error");return (pid);}void Close(int fd){if (close(fd) == -1)err_sys("close error");}ssize_t writen(int fd, const void *vptr, size_t n){size_t nleft;ssize_t nwritten;const char *ptr;ptr = (const char *)vptr;nleft = n;while (nleft > 0) {if ((nwritten = write(fd, ptr, nleft)) <= 0) {if (nwritten < 0 && errno == EINTR)nwritten = 0;/* and call write() again */elsereturn (-1);/* error */}nleft -= nwritten;ptr += nwritten;}return (n);}void Writen(int fd, void *ptr, int nbytes){if (writen(fd, ptr, nbytes) != nbytes)err_sys("writen error");}void str_echo(int sockfd){ssize_t n;char buf[MAXLINE]; again:while ((n = read(sockfd, buf, MAXLINE)) > 0)Writen(sockfd, buf, n);if (n < 0 && errno == EINTR)goto again;else if (n < 0)err_sys("str_echo: read error");}void sig_chld(int signo){pid_t pid;int stat;while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)printf("child %d terminated\n", pid);return;}int main(){int listenfd, connfd, udpfd, nready, maxfdp1;char mesg[MAXLINE];pid_t childpid;fd_set rset;ssize_t n;socklen_t len;const int on = 1;struct sockaddr_in cliaddr, servaddr;/* 4create listening TCP socket */listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));Bind(listenfd, (SA *) & servaddr, sizeof(servaddr));Listen(listenfd, LISTENQ);/* 4create UDP socket */udpfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(udpfd, (SA *) & servaddr, sizeof(servaddr));/* end udpservselect01 *//* include udpservselect02 */Signal(SIGCHLD, sig_chld);/* must call waitpid() */FD_ZERO(&rset);maxfdp1 = max(listenfd, udpfd) + 1;for (;;) {FD_SET(listenfd, &rset);FD_SET(udpfd, &rset);if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {if (errno == EINTR)continue;/* back to for() */elseerr_sys("select error");}if (FD_ISSET(listenfd, &rset)) {len = sizeof(cliaddr);connfd = Accept(listenfd, (SA *) & cliaddr, &len);if ((childpid = Fork()) == 0) {/* child process */Close(listenfd);/* close listening socket */str_echo(connfd);/* process the request */exit(0);}Close(connfd);/* parent closes connected socket */}if (FD_ISSET(udpfd, &rset)) {len = sizeof(cliaddr);n = Recvfrom(udpfd, mesg, MAXLINE, 0, (SA *) & cliaddr,     &len);Sendto(udpfd, mesg, n, 0, (SA *) & cliaddr, len);}}}