当接收端的内核缓冲区中的数据没有全部交给应用程序时, 如果接收端关闭socket(比如调用close或者进程挂掉),就会回以RST报文
来源:互联网 发布:入驻淘宝企业店铺 编辑:程序博客网 时间:2024/05/09 19:30
在通常情况下, 调用close的时候, 会发FIN包, 但是, 如果接收端没有用recv把内核缓冲区的数据取完, 却执行了关闭socket的操作(比如调用close或者进程挂掉), 那么这就是异常的情况, 此时接收端会回RST报文。
我们来看看, 服务端程序为:
#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>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 <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>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 20000char 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, 也是没有问题的。
先说到这里。
- 当接收端的内核缓冲区中的数据没有全部交给应用程序时, 如果接收端关闭socket(比如调用close或者进程挂掉),就会回以RST报文
- socket对应的内核缓冲区(发送,接收)的大小
- 服务端 write时,收到RST响应(对端socket中断),导致服务器进程关闭
- 如何获取/设置socket对应的内核缓冲区(发送,接收)的大小
- 当对端IP可达但没有监听对应的端口时候, 对端会发出RST报文
- Socket接收字节缓冲区
- Socket接收字节缓冲区
- 面试题:非阻塞tcp socket调用close时缓冲区未发送数据的处理逻辑
- socket的发送与接收缓冲区(转)
- socket的发送与接收缓冲区(转)
- 设置SOCKET的发送与接收缓冲区
- socket的发送与接收缓冲区
- 设置SOCKET的发送与接收缓冲区
- 设置SOCKET的发送与接收缓冲区 .
- tcp socket的发送与接收缓冲区
- tcp socket的发送与接收缓冲区 .
- tcp socket的发送与接收缓冲区
- tcp socket的发送与接收缓冲区
- 查找单链表中倒数第k个节点
- Java学习笔记Day03
- POJ 3207 Ikki's Story IV
- 【数据结构】栈与队列
- Java实践(四)---编写一个完美的equals方法
- 当接收端的内核缓冲区中的数据没有全部交给应用程序时, 如果接收端关闭socket(比如调用close或者进程挂掉),就会回以RST报文
- TCP编程
- 笑来前辈---与时间做朋友----你比他们害惨么?--lincoln/悲催的11月小男孩
- Shell 进阶指南
- 对VS 2017中ASP.NET Core项目解决:Add-Migration : 无法将“Add-Migration”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
- CODE[VS] 4416 FFF团卧底的后宫
- BZOJ 1050 [HAOI2006]旅行comf Kruskal
- 【数据结构】KMP算法
- jzoj. 1286. 太空电梯