首页 » SEO优化 » phpsocket封闭技巧_腾讯三面socket 优雅的关闭连接

phpsocket封闭技巧_腾讯三面socket 优雅的关闭连接

duote123 2024-11-07 0

扫一扫用手机浏览

文章目录 [+]

序言

close函数的浸染是关闭套接字,并终止TCP连接。
那终止连接之后,还在发送缓冲区的数据还能发送吗?接下来我们来看一下。

CLOSE和SO_LINGER

unix网络编程这本书上是这样说的,我以为这个阐明有人会让人产生误解。
close了某个socket,该socket就真的必须关闭吗?实在不是,close是将该套接字的引用计数减1,当某个套接字的引用计数为0时,该套接字就被关闭了。
不为0,就不会被关闭。
多进程并发做事器中会涌现这种情形,我开始就误解了。

phpsocket封闭技巧_腾讯三面socket 优雅的关闭连接

[mapan@localhost test]$ lsclient.cpp makefile server.cpp[mapan@localhost test]$ 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,acceptfd; socklen_t clilen; struct sockaddr_in cliaddr,servaddr; listenfd=socket(AF_INET,SOCK_STREAM,0); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(8888); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(listenfd,(struct sockaddr )&servaddr,sizeof(struct sockaddr_in)); listen(listenfd,5); acceptfd=accept(listenfd,(struct sockaddr )NULL,NULL); char recvbuf[200000]; while(1) { getchar(); read(acceptfd,recvbuf,sizeof(recvbuf)); } getchar(); close(listenfd); return 0;}[mapan@localhost test]$ 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"); struct linger so_linger; so_linger.l_onoff=0; //so_linger.l_linger=20; setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); int ret=connect(sockfd,(struct sockaddr )&servaddr,sizeof(servaddr)); char sendbuf[200000]; write(sockfd,sendbuf,sizeof(sendbuf)); close(sockfd); return 0;}[mapan@localhost test]$ cat makefile all:server clientserver.o:server.cpp g++ -c server.cppclient.o:client.cpp g++ -c client.cppserver:server.o g++ -o server server.oclient:client.o g++ -o client client.oclean: rm -f server client .o[mapan@localhost test]$

运行做事端和客户端,并查看网络状态。

phpsocket封闭技巧_腾讯三面socket 优雅的关闭连接
(图片来自网络侵删)

[mapan@localhost ~]$ netstat -na | grep 8888tcp 0 0 127.0.0.1:8888 0.0.0.0: LISTEN tcp 0 61101 127.0.0.1:35260 127.0.0.1:8888 FIN_WAIT1 tcp 138900 0 127.0.0.1:8888 127.0.0.1:35260 ESTABLISHED

可以看到的是close立即返回了,套接字关闭了,但客户端发送缓冲区中仍旧还有数据。
当做事端吸收缓冲区有地方后,这些数据将会由系统自动发送给做事端,但是此时客户端讲不会管做事端是否已吸收到数据。
l_onoff=0,便是关闭这个套接字选项,默认close操作。
把稳不雅观察,此时客户真个状态时FIN_WAIT1,便是客户单还没有把数据发送完毕,以是没有接到做事端协议栈返回的ACK,以是客户端为这个状态。

再改变客户端代码:

#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"); struct linger so_linger; so_linger.l_onoff=1; so_linger.l_linger=0; setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); int ret=connect(sockfd,(struct sockaddr )&servaddr,sizeof(servaddr)); char sendbuf[200000]; write(sockfd,sendbuf,sizeof(sendbuf)); getchar(); close(sockfd); return 0;}

还是按照上述操作,编译后启动做事端和客户端。
此时会创造客户端卡在getchar()处,查看此时的网络状态。

[mapan@localhost ~]$ netstat -na | grep 8888tcp 0 0 127.0.0.1:8888 0.0.0.0: LISTEN tcp 138900 0 127.0.0.1:8888 127.0.0.1:35262 ESTABLISHED tcp 0 61100 127.0.0.1:35262 127.0.0.1:8888 ESTABLISHED

客户真个发送缓冲区中还没有数据发送出去,如果是我们说的第一种情形,在客户端按下回车键之后,客户端该当FIN_WAIT1状态。
好,我们在客户端按下回车键后看网络状态。

[mapan@localhost ~]$ netstat -na | grep 8888tcp 0 0 127.0.0.1:8888 0.0.0.0: LISTEN

看,连接直接断开了。
解释close调用后,会丢弃发送缓冲区的内存,并发送一个RST给做事端,从而断开连接,这也避免了time_wait的状态。
这也是将 so_linger.l_onoff=1,so_linger.l_linger=0的close效果。

在看客户端代码:

[mapan@localhost test]$ 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"); struct linger so_linger; so_linger.l_onoff=1; so_linger.l_linger=10; setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); int ret=connect(sockfd,(struct sockaddr )&servaddr,sizeof(servaddr)); char sendbuf[200000]; write(sockfd,sendbuf,sizeof(sendbuf)); //getchar(); close(sockfd); return 0;}

还是重复上述操作,编译运行查看网络状态,此时我将getchar()注释掉了。
你会看到客户端会卡在那里,其缘故原由是调用了close函数,但是它不会立时返回,close等待的韶光是我们设置的超时时间。
看此时的网络状态。

[mapan@localhost ~]$ netstat -na | grep 8888tcp 0 0 127.0.0.1:8888 0.0.0.0: LISTEN tcp 0 61101 127.0.0.1:35266 127.0.0.1:8888 FIN_WAIT1 tcp 138900 0 127.0.0.1:8888 127.0.0.1:35266 ESTABLISHED

当客户端发送缓冲区中的数据全部发送到做事真个协议栈,并且吸收到了做事真个ACK,那么此时close就会返回,条件是在我们设置的超时时间之内。
过了超时时间,close也会返回,那就和我们说的第一种情形一样了。

网络问题本该当用tcpdump抓包来看效果的,但是很遗憾,我正在测试的linux上没有root权限。

总结

SO_LINGER延迟关闭这个选项很有用,通过自己试验学习这个套接字选项,对你理解TCP连接和数据发送帮助都是非常大的。

相关文章

我国土地利用分类代码的构建与应用

土地利用分类代码是我国土地管理的重要组成部分,是土地资源调查、规划、利用和保护的依据。土地利用分类代码的构建与应用显得尤为重要。本...

SEO优化 2025-02-18 阅读1 评论0

微信跳转微信支付便捷支付体验的秘密武器

移动支付已成为人们日常生活中不可或缺的一部分。作为我国领先的社交平台,微信支付凭借其便捷、安全的支付方式,深受广大用户的喜爱。而微...

SEO优化 2025-02-18 阅读1 评论0

探寻会计科目代码背后的奥秘分类与

会计科目代码是会计信息系统中不可或缺的组成部分,它将企业的经济活动进行分类和归纳,为会计核算、财务分析和决策提供重要依据。本文将从...

SEO优化 2025-02-18 阅读1 评论0