1.TCP回射服务器程序:main函数
#include "unp.h" int main(int argc, char **argv) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; void sig_chld(int); 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); 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 */ } }
创建TCP套接字。在待绑定到该套接字的网际网套接字地址结构中填入通配地址(INADDR_ANY)和服务器众所周知的端口(SERV_PORT).捆绑通配地址是告诉系统:要是系统是多宿主机,我们将接受目的地址为任何本地接口的连接。listen把该套接字转成一个监听套接字。
服务器阻塞于accept调用,等待客户端连接完成。
fork为每个客户派生给一个处理它们的子进程。子进程关闭监听套接字,父进程关闭已连接的套接字。。子进程调用str_echo处理客户。
#include "unp.h" 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) errr_sys("str_echo:read error"); }
read函数从套接字读入数据,writen函数把其内容回射给客户。如果客户关闭连接,那么接收到客户的FIN将导致服务器子进程的read函数返回0,这又导致str_echo函数的返回,从而终止子进程。
2.TCP回射客户程序:main函数
/* Use standard echo server; baseline measurements for nonblocking version */ #include "unp.h" 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(7); Inet_pton(AF_INET, argv[1], &servaddr.sin_addr); Connect_timeo(sockfd, (SA *) &servaddr, sizeof(servaddr), 10); str_cli(stdin, sockfd); /* do it all */ exit(0); }
3.POSIX信号处理
信号就是告知某个进程发生了某个事件的通知,有时候也称为软件中断,信号通常是异步的,也就是进程预先不知道信号的准确发生时刻。
信号可以:由一个进程发给另一个进程或者自身;由内核发给某个进程。
每个信号都有一个与之关联的处置,也称为行为。