第3章 套接字编程简介
3.4 字节排序函数
#include <stdio.h> #include <stdlib.h> #define CPU_VENDOR_OS "i686-pc-linux-gnu" int main(int argc, char **argv) { union { short s; char c[sizeof(short)]; } un; un.s = 0x0102; printf("%s: ", CPU_VENDOR_OS); if (sizeof(short) == 2) { if (un.c[0] == 1 && un.c[1] == 2) printf("big-endian\n"); else if (un.c[0] == 2 && un.c[1] == 1) printf("little-endian\n"); else printf("unknown\n"); } else printf("sizeof(short) = %d\n", sizeof(short)); exit(0); }
第5章 TCP客户/服务器程序示例
5.2 TCP回射服务器程序
#include <strings.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <stdarg.h> /* ANSI C header file */ #include <syslog.h> /* for syslog() */ #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> int daemon_proc; /* set nonzero by daemon_init() */ #define SA struct sockaddr #define MAXLINE 4096 /* max text line length */ #define SERV_PORT 9877 /* TCP and UDP */ #define LISTENQ 1024 /* 2nd argument to listen() */ void err_doit(int errnoflag, int level, const char *fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; /* value caller might want printed */ #ifdef HAVE_VSNPRINTF vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ #else vsprintf(buf, fmt, ap); /* not safe */ #endif n = strlen(buf); if (errnoflag) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); strcat(buf, "\n"); if (daemon_proc) { syslog(level, "%s",buf); } else { fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(stderr); } return; } void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_ERR, 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"); } 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) { #ifdef EPROTO if (errno == EPROTO || errno == ECONNABORTED) #else if (errno == ECONNABORTED) #endif goto again; else err_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 /* Write "n" bytes to a descriptor. */ 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 */ else return (-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"); } int main() { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; 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); Bind(listenfd, (SA *) & servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); for (;;) { clilen = sizeof(cliaddr); connfd = Accept(listenfd, (SA *) & cliaddr, &clilen); 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 */ } }
5.4 TCP回射客户程序
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <strings.h> #include <stdarg.h> /* ANSI C header file */ #include <syslog.h> /* for syslog() */ #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #define MAXLINE 4096 /* max text line length */ #define SERV_PORT 9877 /* TCP and UDP */ int daemon_proc; /* set nonzero by daemon_init() */ #define SA struct sockaddr void err_doit(int errnoflag, int level, const char *fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; /* value caller might want printed */ #ifdef HAVE_VSNPRINTF vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ #else vsprintf(buf, fmt, ap); /* not safe */ #endif n = strlen(buf); if (errnoflag) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); strcat(buf, "\n"); if (daemon_proc) { syslog(level, "%s",buf); } else { fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(stderr); } return; } void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, LOG_ERR, fmt, ap); va_end(ap); exit(1); } void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_ERR, 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 */ } void Connect(int fd, const struct sockaddr *sa, socklen_t salen) { if (connect(fd, sa, salen) < 0) err_sys("connect 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 */ else return (-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"); } 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); } void Fputs(const char *ptr, FILE * stream) { if (fputs(ptr, stream) == EOF) err_sys("fputs error"); } static int read_cnt; static char *read_ptr; static char read_buf[MAXLINE]; static ssize_t my_read(int fd, char *ptr) { if (read_cnt <= 0) { again: if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) goto again; return (-1); } else if (read_cnt == 0) return (0); read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return (1); } ssize_t readline(int fd, void *vptr, int maxlen) { ssize_t n, rc; char c, *ptr; ptr = (char *)vptr; for (n = 1; n < maxlen; n++) { if ((rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '\n') break; /* newline is stored, like fgets() */ } else if (rc == 0) { *ptr = 0; return (n - 1); /* EOF, n - 1 bytes were read */ } else return (-1); /* error, errno set by read() */ } *ptr = 0; /* null terminate like fgets() */ return (n); } ssize_t Readline(int fd, void *ptr, size_t maxlen) { ssize_t n; if ((n = readline(fd, ptr, maxlen)) < 0) err_sys("readline error"); return (n); } void str_cli(FILE * fp, int sockfd) { char sendline[MAXLINE], recvline[MAXLINE]; while (Fgets(sendline, MAXLINE, fp) != NULL) { Writen(sockfd, sendline, strlen(sendline)); if (Readline(sockfd, recvline, MAXLINE) == 0) err_quit("str_cli: server terminated prematurely"); Fputs(recvline, stdout); } } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if (argc != 2) err_quit("usage: tcpcli <IPaddress>"); sockfd = Socket(AF_INET, SOCK_STREAM, 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)); str_cli(stdin, sockfd); /* do it all */ exit(0); }
5.10 wait和waitpid函数
//带上信号处理函数的server #define _POSIX_SOURCE #include <strings.h> #include <signal.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <stdarg.h> /* ANSI C header file */ #include <syslog.h> /* for syslog() */ #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int daemon_proc; /* set nonzero by daemon_init() */ #define SA struct sockaddr #define MAXLINE 4096 /* max text line length */ #define SERV_PORT 9877 /* TCP and UDP */ #define LISTENQ 1024 /* 2nd argument to listen() */ typedef void Sigfunc(int); /* for signal handlers */ void err_doit(int errnoflag, int level, const char *fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; /* value caller might want printed */ #ifdef HAVE_VSNPRINTF vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ #else vsprintf(buf, fmt, ap); /* not safe */ #endif n = strlen(buf); if (errnoflag) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); strcat(buf, "\n"); if (daemon_proc) { syslog(level, "%s", buf); } else { fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(stderr); } return; } void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_ERR, 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"); } 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"); } 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 /* Write "n" bytes to a descriptor. */ 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 */ else return (-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; } 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) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ #endif } else { #ifdef SA_RESTART act.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); } int main() { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; 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); Bind(listenfd, (SA *) & servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); Signal(SIGCHLD, sig_chld); /* must call waitpid() */ for (;;) { clilen = sizeof(cliaddr); if ((connfd = accept(listenfd, (SA *) & cliaddr, &clilen)) < 0) { if (errno == EINTR) continue; /* back to for() */ else err_sys("accept error"); } 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 */ } }