shutdown函数和FIN_WAIT2状态

来源:互联网 发布:淘宝宝贝详情如何添加 编辑:程序博客网 时间:2024/06/13 17:29

           玩过英雄联盟的人都不会对shutdown感到陌生,就是你连杀被终结了嘛。在网络编程中也差不多是这个意思,准确来说是从容关闭。有啥用呢?来看代码吧

[mapan@localhost TCP]$ lsclient.cpp  makefile  server.cpp[mapan@localhost TCP]$ cat server.cpp #include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <malloc.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/ioctl.h>#include <stdarg.h>#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#define MAXLINE 4096int 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(8888);   bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));     listen(listenfd,1);      clilen=sizeof(cliaddr);   connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);       char recvBuf[100]={0};   char sendBuf[100]={0};    getchar();   recv(connfd,recvBuf,100-1,0);   printf("%s\n",recvBuf);      scanf("%s",sendBuf);   send(connfd,sendBuf,strlen(sendBuf)+1,0);   printf("sendBuf=%s",sendBuf);       getchar();   getchar();   close(connfd);   close(listenfd);   return 0;}[mapan@localhost TCP]$ cat client.cpp #include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <malloc.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/ioctl.h>#include <stdarg.h>#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#define MAXLINE 4096int main(){   int sockfd;   struct sockaddr_in servaddr;   sockfd=socket(AF_INET,SOCK_STREAM,0);   bzero(&servaddr,sizeof(servaddr));   servaddr.sin_family=AF_INET;   servaddr.sin_port=htons(8888);   servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");   int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));      char sendBuf[100]={0};   char recvBuf[100]={0};      scanf("%s",sendBuf);   send(sockfd,sendBuf,strlen(sendBuf)+1,0);   close(sockfd);      return 0;}[mapan@localhost TCP]$ cat makefile all:server clientserver.o:server.cppg++ -c server.cppclient.o:client.cppg++ -c client.cppserver:server.og++ -o server server.oclient:client.og++ -o client client.oclean:rm -f server client *.o[mapan@localhost TCP]$ 

执行:

[mapan@localhost TCP]$ makeg++ -c server.cppg++ -o server server.og++ -c client.cppg++ -o client client.o[mapan@localhost TCP]$ lsclient  client.cpp  client.o  makefile  server  server.cpp  server.o[mapan@localhost TCP]$ ./server 


此时服务端卡在getchar(),不能接受数据。再打开一个窗口,运行客户端,输入数据,按回车键,此时客户端close了。

[mapan@localhost TCP]$ ./client 
123
[mapan@localhost TCP]$ 


查看网络状态:

[mapan@localhost ~]$ netstat -na | grep 8888tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN      tcp        0      0 127.0.0.1:34998             127.0.0.1:8888              FIN_WAIT2   tcp        5      0 127.0.0.1:8888              127.0.0.1:34998             CLOSE_WAIT
由于服务端没有接收客户单发送的数据,所以客户单发送的数据还在服务端的接收缓冲区里面,123\0+FIN刚好5个字节。服务端按下回车键,并查看网络状态。

[mapan@localhost TCP]$ ./server 123
[mapan@localhost ~]$ netstat -na | grep 8888tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN      tcp        0      0 127.0.0.1:35000             127.0.0.1:8888              FIN_WAIT2   tcp        0      0 127.0.0.1:8888              127.0.0.1:35000             CLOSE_WAIT 
那个5消失了,则服务端应用进程接收到了数据。然后在服务端输入1111111111,查看网络状态

[mapan@localhost ~]$ netstat -na | grep 8888tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN 
服务端一发送数据就直接断开连接了,因为客户端调用了close,服务端向一个已关闭的套接字发送数据(端口已没在使用,未打开),客户端直接回复RST,然后段断开连接。但是书上说:FIN_WAIT2下的主动端可以接收被动端发送过来的数据啊,但是上述情况好像和书上说的不一致。说到这里,shutdown的作用就能体现出来了。顺便说一下,close socket之后,ACK和FIN这种信号是可以传递的,它们通过协议栈接收并且判断是否接收到,close只是作用于应用进程。


改动客户端代码如下:

[mapan@localhost TCP]$ cat client.cpp #include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <malloc.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/ioctl.h>#include <stdarg.h>#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#define MAXLINE 4096int main(){   int sockfd;   struct sockaddr_in servaddr;   sockfd=socket(AF_INET,SOCK_STREAM,0);   bzero(&servaddr,sizeof(servaddr));   servaddr.sin_family=AF_INET;   servaddr.sin_port=htons(8888);   servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");   int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));      char sendBuf[100]={0};   char recvBuf[100]={0};      scanf("%s",sendBuf);   send(sockfd,sendBuf,strlen(sendBuf)+1,0);   shutdown(sockfd,SHUT_WR);   recv(sockfd,recvBuf,100-1,0);   printf("%s\n",recvBuf);   getchar();   getchar();   close(sockfd);      return 0;}

接着执行make clean && make,开启服务端和客户端,操作同上。客户端发送数据后,执行shutdown。

[mapan@localhost ~]$ netstat -na | grep 8888tcp        0      0 0.0.0.0:8888                0.0.0.0:*                   LISTEN      tcp        0      0 127.0.0.1:35008             127.0.0.1:8888              FIN_WAIT2   tcp        5      0 127.0.0.1:8888              127.0.0.1:35008             CLOSE_WAIT  [mapan@localhost ~]$ 


看到没有,执行shutdown之后,客户单确实发送了FIN信号,并且接收到了服务端的ACK信号,然后客户端处于FIN_WAIT2状态。然后服务端向客户端发送数据。

[mapan@localhost TCP]$ ./server 12311111111sendBuf=11111111
[mapan@localhost TCP]$ ./client 12311111111
此时客户端接收到了数据,则证明客户端在FIN_WAIT2状态下是能接收到数据的。

现在大家对FIN_WAIT2状态和shutdown有了一定的了解了吧。












原创粉丝点击