Unix网络编程之select版客户端实现

来源:互联网 发布:excel2010数据分析工具 编辑:程序博客网 时间:2024/05/22 15:10

1.当客户端阻塞于某个输入操作时,服务器发送过来的终止连接的消息或者服务器崩溃的FIN,客户端将接受不到,而客户端以为服务器还在正常运行,一味的给服务器发消息。那么客户端将收到一个RST,但是客户端正忙于其他操作,忽略了这个RST,客户端继续调用read方法,如果read方法调用发生在RST到来之前,将返回一个0(EOF),否则返回一个ECONNRESET(对方复位连接错误),最终退出程序。

2.因此,我们可以用select 的i/o复用的方式重新编写我们的代码:

客户端改编之后的代码:

#include "unp.h"intmain(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[i],&servaddr.sin_addr);     Connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));     strcli(stdin,sockfd);     exit(0);}


接下来是strcli函数的select 实现方法:

#include "unp.h"voidstr_cli(FILE *fp, int sockfd){      int maxfdp1,stdineof;           //我们设置一个stdineof的标志位,为零代表它可以往sockfd里面写      fd_set rset;      char buf[MAXLINE]      int  n;            stdineof = 0;      FD_ZERO(&rset);      for(;;){          if(stdineof == 0)FD_SET(fileno(fp),&rset);      //如果标志位为0 , 那么我们把输入流的描述符设置一下。  FD_SET(sockfd,&rset);                //套接字的描述符是都应该设的,因为我们一般只是关闭客户端的写操作,对于服务器发送来的消息还是可以读到的。          maxfdp1 = max(fileno(fp),sockfd)+1;          Select(maxfdp1,&rset,NULL,NULL,NULL);     if(FD_ISSET(sockfd,&rset)){          //判断套接字是否可读,如果可读,读入到buf缓冲区里面。if((n = Read(sockfd,buf,MAXLINE)) == 0){if(stdineof == 1){    //如果我们正处在FIN-WAIT-1 状态下,我们就直接返回就行了,因为我们已经受到了来自服务器端的FIN。return;}elseerr_quit("str_cli : server terminated");}Write(fileno(stdout,buf,MAXLINE));  }  if(FD_ISSET(fileno(stdin),&rset)){      //判断输入流里面是否可读,如果可读,把它读到buf缓冲区里面。if((n = Read(fileno(stdin),buf,MAXLINE)) == 0){stdineof = 1;              //如果我们读到了来自服务器端的FIN,那么我们就直接将stdineof标志位设置成 1Shutdown(sockfd,SHUT_WR);   //然后我们向服务器发送ACK,并且还有我们的FIN。FD_CLR(fileno(fp),&rset);   //接下来我们一定要将rset里面注册的监听描述符移除掉,不让内核再去判断他是否可读continue;}Writen(sockfd,buf,n);  }      }}



0 0
原创粉丝点击