UNP-UNIX网络编程 第五章:TCP客户/服务器程序示例
2018-01-16 20:10
375 查看
{ int n; if((n = socket(family, type, protocol)) < 0) { printf("socket() error!"); exit(0); } else return n; }
服务器
{ ssize_t n; char buf[MAXLINE]; again://接收到客户的FIN,read()返回0,函数返回,子进程终止 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"); }
{//因为当父进程同时收到很多 SIGCHLD 信号时 信号函数只执行一次或多次,但是不能肯定一定是 5 次, //所以会导致还会有僵尸进程。基于此原因,我们用 waitpid() 代替 wait() 函数,修改信号捕获函数如下: pid_t pid; int stat; //pid = wait(&stat);//处理1个 //printf("child %d terminated\n", pid); while((pid=waitpid(-1,&stat,WNOHANG)>0)//处理多个 printf("child %d terminated\n",pid); return; }
我们不要忘了当有尚未终止的子进程时会阻塞,而 waitpid 函数可以通过设置第三个参数为 WNOHANG 来告知 waitpid ,
当有尚未终止的子进程的时候不要阻塞,所以就可以通过循环处理所有终止的子进程,故不会有僵尸进程残留!
客户端
#include "unp.h" int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if (argc != 2) err_quit("usage: tcpcli <IPaddress>"); //创建TCP套接字,用服务器的IP地址和端口号装填 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); } void str_cli(FILE *fp, int sockfd) { char sendline[MAXLINE], recvline[MAXLINE]; while (Fgets(sendline, MAXLINE, fp) != NULL) //从客户端读入文本 { //Writen(sockfd, sendline,1); sleep(1);//最后用不到 Writen(sockfd, sendline, strlen(sendline));//写给服务器 if (Readline(sockfd, recvline, MAXLINE) == 0)//从套接字读入回射行 err_quit("str_cli: server terminated prematurely"); Fputs(recvline, stdout);//写到标准输出 } } void str_cli(FILE *fp, int sockfd)//这个函数是由select调用来驱动。而上面的函数是由fgets函数驱动的。 { int maxfdp1; //第一个参数 fd_set rset; //读-集合指针 //char sendline[MAXLINE], recvline[MAXLINE]; char buf[MAXLINE]; int n; stdineof = 0; FD_ZERO(&rset); //由FD_ZERO初始化可读性描述符集 for ( ; ; ) { if(stdineof == 0)//1.只要标志为0,主循环中总是select标准输入的可读性 FD_SET(fileno(fp), &rset); //并用FD_SET打开两位,一个对应于标准I/O文件指针fp FD_SET(sockfd, &rset); //一位对应于套接口sockfd maxfdp1 = max(fileno(fp), sockfd) + 1; //fileno函数把标准I/O文件指针转换为其对应的描述字 Select(maxfdp1, &rset, NULL, NULL, NULL); //上面计算出了两个描述符的较大后值,读-集合指针 //如果在selecrt返回时套接口是可读的,则由readline来读,由fputs输出。 if (FD_ISSET(sockfd, &rset)) /* socket is readable */ { if (n=Read(sockfd, recvline, MAXLINE) == 0) //把对文本行变为对缓冲区,从套接字读入 { if(stdineof == 1) return;//遇到EOF正常终止 else//否则服务器就是过早终止了 err_quit("str_cli: server terminated prematurely");//同原来 Write(fileno(stdout),buf,n) //把对文本行变为对缓冲区,写到标准输出 } } //如果标准输入可读,则由fgets读入一行,并用writen将其写到套接口 if (FD_ISSET(fileno(fp), &rset)) /* input is readable */ { if ((n=Read(fileno(fp), buf,MAXLINE)) == NULL) //把对文本行变为对缓冲区,从客户端读入文本 { stdineof =1; //在标准输入碰到EOF,stdineof 置位1 Shutdown(sockfd,SHUT_WR);//调用SHUT_WR来send FIN FDCLR(fileno(fp), &rset); continue; } Writen(sockfd, buf,n);//把对文本行变为对缓冲区,写给服务器 } } }
(1)服务器进程在客户之前终止,也就是说,终止前是有给客户端发送FIN的,服务器主机关机也跟这类终止相同。
此时:客户:CLOSE_WAIT,服务器:FIN_WAIT2;
但是虽然发送的FIN可以得到客户TCP的ACK回复,但是正阻塞在fgets调用的客户端程序却没有察觉,(select和poll)
如果此时客户端输入并且将数据发送给对端,这时服务端会回复RST,为什么?
因为这个和一般的终止连接不同,对端进程已经终止,没有进程能识别这个数据。此时客户调用readline读取到刚开始的FIN,这时readline返回0,报告连接终止。
我们再继续往不存在的连接发送数据就会产生SIGPIPE信号;当一个进程向某个已经接受到RST的套接字执行写操作时,内核向应用进程发送一个SIGPIPE信号,该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿地被终止。我们调用writen两次,第一次引发RST,第二次再写产生SIGPIPE。
(2)服务器关机,会发送SIGTERM信号,类似(1)客户端通过select/poll函数,使得服务器进程一终止,就能被客户检测到。
(3)服务器主机崩溃,那么用户发送的数据(此时才检测到服务器崩溃)将使得路由器相应一个destination/ unreachable的ICMP消息。客户端将会产生数次重传。处理这种问题可以有两种方法:
1.对readline调用设置一个更短的超时
2.采用SO_KEEPALIVE选项
(4)服务器重启后,它的TCP丢失了崩溃前的所有连接消息,因此服务器TCP对于所有收到的来自客户的数据分节响应一个RST。而此时客户正阻塞在readline调用,导致该调用返回ECONNRESET
相关文章推荐
- UNIX网络编程笔记 第五章 TCP客户/服务器程序示例
- UNIX网络编程卷一 笔记 第五章 TCP客户/服务器程序示例
- UNP——Chapter 5:TCP客户/服务器程序示例
- UNIX网络编程---TCP客户/服务器程序示例(五)
- UNP - 第五章 TCP客户/服务器示例 - 学习笔记
- Unix网络编程 第一卷 套接口API 第五章 TCP客户/服务器程序例子
- UNP卷1:第五章(TCP客户/服务器程序示例)
- UNPV3第五章TCP客户/服务器程序示例
- 【UNIX网络编程(三)】TCP客户/服务器程序示例
- UNIX网络编程笔记(4)—TCP客户/服务器程序示例
- UNIX网络编程 第5章 TCP客户/服务器程序示例
- 《UNIX网络编程 卷1》 笔记: TCP 客户/服务器程序示例
- Unix网络编程代码 第5章 TCP客户/服务器程序示例
- UNIX网络编程---TCP客户/服务器程序示例(五)
- UNIX网络编程卷一 第五章 TCP客户/服务器程序示例
- 【UNIX网络编程】TCP客户/服务器程序示例
- UNIX网络编程卷1:套接字联网-第5章:TCP客户/服务器程序示例
- TCP客户/服务器程序示例
- TCP客户/服务器程序示例
- 第5章-unix网络编程 TCP/服务端程序示例