第五章 TCP客户/服务器程序示例:
#include <sys/wait.h> pid_t wait(int * statloc); pid_t waitpid(pid_t pid, int * statloc, int options); pid: == -1, wait any child > 0, wait child which child-gid == gid == 0, wait any-child which child-group-id == parent-group-id < -1, wait any-child which child-group-id == abs(pid) options: WCONTINUED, WNOHANG, WUNTRACED macros of check statloc: WIFEXITED(status) --> WEXITSTATUS(status) WIFSIGNALED(status) --> WTERMSIG(status), WCOREDUMP(status) WIFSTOPPED(status) --> WSTOPSIG(status) WIFCONTINUED(status) if statloc is NULL means we neednot child's exit-status error return 0 or -1
示例:
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> #include <sys/socket.h> #include "str_cli.h" #define SERV_PORT 34567 int main(int argc, char * argv[]) { int sockfd; struct sockaddr_in servaddr; if (argc != 2) { printf("usage: %s <IPaddress>\n", argv[0]); exit(1); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error: %s\n", strerror(errno)); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error: %s\n", strerror(errno)); exit(1); } if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { printf("connect error: %s\n", strerror(errno)); exit(1); } str_cli(stdin, sockfd); /* do it all */ exit(0); }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> #include <sys/socket.h> #include "str_echo.h" #define LISTENQ 5 #define SERV_PORT 34567 int main(int argc, char * argv[]) { int listenfd; int connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr; struct sockaddr_in servaddr; if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error: %s\n", strerror(errno)); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { printf("bind error: %s\n", strerror(errno)); exit(1); } if ((listen(listenfd, LISTENQ)) == -1) { printf("listen error: %s\n", strerror(errno)); exit(1); } for ( ; ; ) { clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); if (connfd == -1) { printf("accept error: %s\n", strerror(errno)); exit(1); } if ((childpid = fork()) < 0) { printf("fork error: %s\n", strerror(errno)); exit(1); } else if (childpid == 0) { if (close(listenfd) == -1) { printf("close listenfd error: %s\n", strerror(errno)); exit(1); } str_echo(connfd); /* process the request */ exit(0); } else { if (close(connfd) == -1) { printf("close connfd error: %s\n", strerror(errno)); exit(1); } } } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include "myio.h" #define MAXLINE 1024 void str_cli(FILE *fp, int sockfd) { int n; char sendline[MAXLINE]; char recvline[MAXLINE]; while (fgets(sendline, MAXLINE, fp) != NULL) { n = strlen(sendline); if (writen(sockfd, sendline, n) != n) { printf("writen error: %s\n", strerror(errno)); exit(1); } if ((n = readline(sockfd, recvline, MAXLINE)) < 0) { printf("readline error: %s\n", strerror(errno)); exit(1); } else if (n == 0) { printf("str_cli: server terminated prematurely\n"); exit(0); } if (fputs(recvline, stdout) == EOF) { printf("fputs error: %s\n", strerror(errno)); exit(1); } } if (ferror(fp)) { printf("fget error: %s\n", strerror(errno)); exit(1); } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include "myio.h" #define MAXLINE 1024 void str_echo(int sockfd) { ssize_t n; char buf[MAXLINE]; again: while ((n = read(sockfd, buf, MAXLINE)) > 0) { if (writen(sockfd, buf, n) != n) { printf("writen error: %s\n", strerror(errno)); exit(1); } } if (n < 0) { if (errno == EINTR) { goto again; } else { printf("str_echo: read error: %s\n", strerror(errno)); exit(0); } } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> #include <sys/socket.h> #include "str_cli.h" #define SERV_PORT 34567 int main(int argc, char * argv[]) { int i; int sockfd[5]; struct sockaddr_in servaddr; if (argc != 2) { printf("usage: %s <IPaddress>\n", argv[0]); exit(1); } for (i = 0; i < 5; ++i) { if ((sockfd[i] = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error: %s\n", strerror(errno)); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error: %s\n", strerror(errno)); exit(1); } if (connect(sockfd[i], (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { printf("connect error: %s\n", strerror(errno)); exit(1); } } str_cli(stdin, sockfd[0]); /* do it all */ exit(0); }
#include <stdio.h> #include <errno.h> #include <signal.h> typedef void Sigfunc(int); Sigfunc * my_signal(int signo, Sigfunc * func) { struct sigaction act; struct sigaction oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; #endif } else { #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif } if (sigaction(signo, &act, &oact) < 0) { return SIG_ERR; } else { return oact.sa_handler; } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <sys/wait.h> #include <netinet/in.h> #include <sys/socket.h> #include "str_echo.h" #include "my_signal.h" #define LISTENQ 5 #define SERV_PORT 34567 void sig_chld(int signo) { pid_t pid; int stat; while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { /* waitpid + WNOHANG */ printf("child %d terminated\n", pid); } return; } int main(int argc, char * argv[]) { int listenfd; int connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr; struct sockaddr_in servaddr; if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error: %s\n", strerror(errno)); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { printf("bind error: %s\n", strerror(errno)); exit(1); } if ((listen(listenfd, LISTENQ)) == -1) { printf("listen error: %s\n", strerror(errno)); exit(1); } if (my_signal(SIGCHLD, sig_chld) == SIG_ERR) { /* must call waitpid() */ printf("my_signal error: %s\n", strerror(errno)); exit(1); } for ( ; ; ) { clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); if (connfd < 0) { if (errno == EINTR) { continue; /* back to for */ } else { printf("accept error: %s\n", strerror(errno)); exit(1); } } if ((childpid = fork()) < 0) { printf("fork error: %s\n", strerror(errno)); exit(1); } else if (childpid == 0) { if (close(listenfd) == -1) { printf("close listenfd error: %s\n", strerror(errno)); exit(1); } str_echo(connfd); /* process the request */ exit(0); } else { if (close(connfd) == -1) { printf("close connfd error: %s\n", strerror(errno)); exit(1); } } } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include "myio.h" void str_echo(int sockfd) { long arg1; long arg2; ssize_t n; char line[MAXLINE]; for ( ; ; ) { if ((n = readline(sockfd, line, MAXLINE)) < 0) { printf("readline error: %s\n", strerror(errno)); exit(1); } else if (n == 0) { return; /* connection closed by other end */ } if (sscanf(line, "%ld%ld", &arg1, &arg2) == 2) { snprintf(line, sizeof(line), "%ld\n", arg1 + arg2); } else { snprintf(line, sizeof(line), "input error\n"); } n = strlen(line); if (writen(sockfd, line, n) != n) { printf("writen error: %s\n", strerror(errno)); exit(1); } } }
struct args { long arg1; long arg2; }; struct result { long sum; };
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include "sum.h" #include "myio.h" #define MAXLINE 1024 void str_cli(FILE * fp, int sockfd) { int n; char sendline[MAXLINE]; struct args arg; struct result ret; while (fgets(sendline, MAXLINE, fp) != NULL) { if (sscanf(sendline, "%ld%ld", &arg.arg1, &arg.arg2) != 2) { printf("invalid input: %s", sendline); continue; } if (writen(sockfd, &arg, sizeof(arg)) != sizeof(arg)) { printf("writen error: %s\n", strerror(errno)); exit(1); } if ((n = readn(sockfd, &ret, sizeof(ret))) == 0) { printf("str_cli: server terminated prematurely"); exit(0); } else if (n != sizeof(ret)) { printf("cli %d/%d readn error: %s\n", n, sizeof(ret), strerror(errno)); exit(1); } else { printf("%ld\n", ret.sum); } } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include "sum.h" #include "myio.h" void str_echo(int sockfd) { ssize_t n; struct args arg; struct result ret; for ( ; ; ) { if ((n = readn(sockfd, &arg, sizeof(arg))) == 0) { return; /* connection closed by other end */ } else if (n != sizeof(arg)) { printf("readn error: %s\n", strerror(errno)); exit(1); } ret.sum = arg.arg1 + arg.arg2; if (writen(sockfd, &ret, sizeof(ret)) != sizeof(ret)) { printf("writen error: %s\n", strerror(errno)); exit(1); } } }
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> #include <sys/socket.h> #include "my_signal.h" #define SERV_PORT 34567 void sig_pipe(int signo) { printf("SIGPIPE received\n"); return; } int main(int argc, char * argv[]) { int sockfd; struct sockaddr_in servaddr; if (argc != 2) { printf("usage: %s <IPaddress>\n", argv[0]); exit(1); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error: %s\n", strerror(errno)); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error: %s\n", strerror(errno)); exit(1); } if (my_signal(SIGPIPE, sig_pipe) == SIG_ERR) { /* must call waitpid() */ printf("my_signal error: %s\n", strerror(errno)); exit(1); } if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { printf("connect error: %s\n", strerror(errno)); exit(1); } sleep(2); if (write(sockfd, "hello", 5) != 5) { printf("write 1 error: %s\n", strerror(errno)); exit(1); } sleep(2); if (write(sockfd, "world", 5) != 5) { printf("write 2 error: %s\n", strerror(errno)); exit(1); } exit(0); }