shutdown函数和FIN_WAIT2状态
? ? ? ? ? ?玩過英雄聯盟的人都不會對shutdown感到陌生,就是你連殺被終結了嘛。在網絡編程中也差不多是這個意思,準確來說是從容關閉。有啥用呢?來看代碼吧
?
[mapan@localhost TCP]$ ls client.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.cpp client.o:client.cppg++ -c client.cpp server:server.og++ -o server server.o client:client.og++ -o client client.oclean:rm -f server client *.o [mapan@localhost TCP]$?
執行:
?
[mapan@localhost TCP]$ make g++ -c server.cpp g++ -o server server.o g++ -c client.cpp g++ -o client client.o [mapan@localhost TCP]$ ls client 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 8888 tcp 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 8888 tcp 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 8888 tcp 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 8888 tcp 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 123 11111111 sendBuf=11111111 [mapan@localhost TCP]$ ./client 12311111111此時客戶端接收到了數據,則證明客戶端在FIN_WAIT2狀態下是能接收到數據的。
?
現在大家對FIN_WAIT2狀態和shutdown有了一定的了解了吧。
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的shutdown函数和FIN_WAIT2状态的全部內容,希望文章能夠幫你解決所遇到的問題。