博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
当接收端的内核缓冲区中的数据没有全部交给应用程序时, 如果接收端关闭socket(比如调用close或者进程挂掉),就会回以RST报文
阅读量:4141 次
发布时间:2019-05-25

本文共 3497 字,大约阅读时间需要 11 分钟。

        在通常情况下,  调用close的时候, 会发FIN包, 但是, 如果接收端没有用recv把内核缓冲区的数据取完, 却执行了关闭socket的操作(比如调用close或者进程挂掉), 那么这就是异常的情况, 此时接收端会回RST报文。

        我们来看看, 服务端程序为:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
int main(){ int sockSrv = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addrSrv; addrSrv.sin_family = AF_INET; addrSrv.sin_addr.s_addr = INADDR_ANY; addrSrv.sin_port = htons(8765); bind(sockSrv, (const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in)); listen(sockSrv, 5); struct sockaddr_in addrClient; int len = sizeof(struct sockaddr_in); int sockConn = accept(sockSrv, (struct sockaddr *)&addrClient, (socklen_t*)&len); getchar(); close(sockConn); while(1); close(sockSrv); return 0;}
      启动它。

      客户端程序为:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(){ int sockClient = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addrSrv; addrSrv.sin_addr.s_addr = inet_addr("10.100.70.140"); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(8765); connect(sockClient, ( const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in)); while(1) { #define N 20000 char szSendBuf[N] = {0}; for(unsigned int i = 0; i < N; i++) //字符数组最后一个字符不要求是‘\0’ { szSendBuf[i] = 'a'; } int iRet = send(sockClient, szSendBuf, sizeof(szSendBuf) , 0); printf("send size is %d, iRet is %d\n", sizeof(szSendBuf), iRet); getchar(); } close(sockClient); return 0;}
       启动它。

       我们看到, 客户端在向服务端发送数据, 但是, 服务端并没有recv的操作, 此时如果在服务端按enter键盘执行close操作, 或者直接ctrl c杀掉进程, 都会关闭服务端的socket, 我们来抓包看看:

19:34:06.307961 IP 10.100.70.140.ultraseek-http > 10.100.70.139.31664: Flags [R.], seq 2861123895, ack 2489467932, win 122, options [nop,nop,TS val 1558194579 ecr 1558194032], length 0        0x0000:  4500 0034 6bad 4000 4006 2d38 0a64 468c  E..4k.@.@.-8.dF.        0x0010:  0a64 468b 223d 7bb0 aa89 4937 9462 441c  .dF."={...I7.bD.        0x0020:  8014 007a 5f6f 0000 0101 080a 5ce0 2993  ...z_o......\.).        0x0030:  5ce0 2770 0000 0000 0000 0000 0000 0000  \.'p............        0x0040:  0000 0000                                ....
       可以看到, 服务端没有把内核缓冲区的数据转移到应用程序时,突然关闭socket, 会发出RST包。 收到RST包后, 客户端并不会回ACK包。

        而且, 如果客户端执行继续发送数据, 那么会有如下结果: send size is 20000, iRet is -1, 实际上就是没有发送任何数据发送, 这一点从tcpdump实际抓包也可以看出来。

        最后一个问题, 此时, 如果客户端关掉close socket或者杀死客户端进程(也就是关闭socket),  那么客户端还会有网络包(比如FIN)发出吗?  不会的! 为什么? 因为在服务端发出RST的时候, 客户端的socket已经被关闭了, 这一点, 不仅仅可以从tcpdump抓包验证, 还可以从客户端打开的socket句柄来验证。 一起来看下, 在服务端发送RST前后, 客户端进程打开socket的变化为:

xxxxxx$ netstat -nao | grep 8765tcp        0      0 10.100.70.139:32972     10.100.70.140:8765      ESTABLISHED off (0.00/0/0)xxxxxx$xxxxxx$xxxxxx$ lsof -i:32972COMMAND  PID    USER   FD   TYPE    DEVICE SIZE/OFF NODE NAMEclient  1897 user_00    3u  IPv4 449256072      0t0  TCP 10.100.70.139:32972->10.100.70.140:ultraseek-http (ESTABLISHED)xxxxxx$ xxxxxx$ xxxxxx$ lsof -i:32972xxxxxx$  xxxxxx$ xxxxxx$ ps -aux | grep 1897user_00   1897  0.0  0.0   3452   636 pts/8    S+   19:47   0:00 ./clientuser_00   3630  0.0  0.0  12152   684 pts/7    R+   19:50   0:00 grep --color=auto 1897xxxxxx$
       可见, 在RST之前,  tcp处理ESTABLISHED的状态, 客户单临时端口为32972,  且可知, 这个端口是client进程打开的。 但是, 在RST之后, client进程打开的这个socke就不存在了(从lsof -i:32972的结果可以看出)。

       所以, 难怪send会失败呢, socket都关闭了, 还send个毛线。

       对了,还有个问题, 客户端的socket被RST关闭后, 如果程序再调用close来关闭socket,  也是没有问题的。

       先说到这里。

转载地址:http://ejwti.baihongyu.com/

你可能感兴趣的文章
Vue动态生成el-checkbox点击无法选中的解决方法
查看>>
MySQL Tricks1
查看>>
python 变量作用域问题(经典坑)
查看>>
pytorch
查看>>
pytorch(三)
查看>>
ubuntu相关
查看>>
C++ 调用json
查看>>
nano中设置脚本开机自启动
查看>>
动态库调动态库
查看>>
Kubernetes集群搭建之CNI-Flanneld部署篇
查看>>
k8s web终端连接工具
查看>>
手绘VS码绘(一):静态图绘制(码绘使用P5.js)
查看>>
手绘VS码绘(二):动态图绘制(码绘使用Processing)
查看>>
基于P5.js的“绘画系统”
查看>>
《达芬奇的人生密码》观后感
查看>>
论文翻译:《一个包容性设计的具体例子:聋人导向可访问性》
查看>>
基于“分形”编写的交互应用
查看>>
《融入动画技术的交互应用》主题博文推荐
查看>>
链睿和家乐福合作推出下一代零售业隐私保护技术
查看>>
Unifrax宣布新建SiFAB™生产线
查看>>