RST包:

假设Server A上面有Process X,它有一个socket M,和另外的Server B上面的Process Y的 Socket N以TCP协议连接上了,那么,据我所知,有2种情况会出现RST包:

(1)X没有close socket就退出了,然后Y继续向M send数据,A的内核就会发送RST 到 socket N;
(2)X设置了SO_LINGER,其中l_onoff 非0, l_linger 为0,这样当A close socket M的时候,也会发送RST到socket N。

当socket N收到了RST,select的结果为socket可读,则:

(a)如果这个时候调用recv,返回-1,errno为ECONNRESET,如果再次调用recv,返回-1,errno为EPIPE,同事产生EPIPE信号;
(b)如果这个时候调用send,返回-1,errno为EPIPE,同时会产生SIGPIPE信号。

#include    "unp.h"#define MAXBUF 40960void processSignal(int signo)
{printf("Signal is %d\n", signo);signal(signo, processSignal);
}ssize_t                        /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{size_t         nleft;ssize_t         nwritten;const char    *ptr;ptr = vptr;nleft = n;while (nleft > 0) {printf("Begin Writen %d\n", nleft);if ( (nwritten = write(fd, ptr, nleft)) <= 0) {if (nwritten < 0 && errno == EINTR) {printf("intterupt\n");nwritten = 0;        /* and call write() again */}elsereturn(-1);            /* error */}nleft -= nwritten;ptr += nwritten;printf("Already write %d, left %d, errno=%d\n", nwritten, nleft, errno);}return(n);
}
/* end writen */void
Writen(int fd, void *ptr, size_t nbytes)
{if (writen(fd, ptr, nbytes) != nbytes)err_sys("writen error");
}void
str_cli(FILE *fp, int sockfd)
{char sendline[MAXBUF], recvline[MAXBUF];while (1) {memset(sendline, 'a', sizeof(sendline));printf("Begin send %d data\n", MAXBUF);Writen(sockfd, sendline, sizeof(sendline));sleep(5);}
}int
main(int argc, char **argv)
{int                     sockfd;struct sockaddr_in     servaddr;signal(SIGPIPE, SIG_IGN);//signal(SIGPIPE, processSignal);if (argc != 2)err_quit("usage: tcpcli [port]");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(atoi(argv[1]));Inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));str_cli(stdin, sockfd);        /* do it all */exit(0);
}

NC模拟服务端

测试1:忽略SIGPIPE信号,writen之前,对方关闭接受进程

本机服务端:    nc -l -p 30000
本机客户端:
./client 30000
    Begin send 40960 data
    Begin Writen 40960
    Already write 40960, left 0, errno=0
    Begin send 40960 data
    Begin Writen 40960
    Already write 40960, left 0, errno=0
    执行到上步停止服务端,client会继续显示:Begin send 40960 data
    Begin Writen 40960
    writen error: Broken pipe(32)
结论:可见write之前,对方socket中断,发送端write会返回-1,errno号为EPIPE(32)

测试2:catch SIGPIPE信号,writen之前,对方关闭接受进程

修改客户端代码,catch sigpipe信号
    //signal(SIGPIPE, SIG_IGN);
    signal(SIGPIPE, processSignal);
本机服务端:
nc -l -p 30000
本机客户端:
./client 30000Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
执行到上步停止服务端,client会继续显示:
Begin send 40960 data
Begin Writen 40960
Signal is 13
writen error: Broken pipe(32)
结论:可见write之前,对方socket中断,发送端write时,会先调用SIGPIPE响应函数,然后write返回-1,errno号为EPIPE(32)

测试3 writen过程中,对方关闭接受进程

为了方便操作,加大1次write的数据量,修改MAXBUF为4096000

本机服务端:
nc -l -p 30000
本机客户端:
./client 30000Begin send 4096000 data
Begin Writen 4096000
执行到上步停止服务端,client会继续显示:
Already write 589821, left 3506179, errno=0
Begin Writen 3506179
writen error: Connection reset by peer(104)

结论:
可见socket write中,对方socket中断,发送端write会先返回已经发送的字节数,
再次write时返回-1,errno号为ECONNRESET(104)

具体解释:

The client's call to readline may happen before the server's RST is received by the client, or it may happen after. If the readline happens before the RST is received, as we've shown in our example, the result is an unexpected EOF in the client. But if the RST arrives first, the result is an ECONNRESET ("Connection reset by peer") error return from readline.

What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.

The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated.
If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE.
以上解释了测试1,2的现象,write一个已经接受到RST的socket,系统内核会发送SIGPIPE给发送进程,如果进程catch/ignore这个信号,write都返回EPIPE错误.

因此,UNP建议应用根据需要处理SIGPIPE信号,至少不要用系统缺省的处理方式处理这个信号,系统缺省的处理方式是退出进程,这样你的应用就很难查处处理进程为什么退出。

EPIPE和ECONNRESET相关推荐

  1. gunicorn源码分析

    服务器端编程(linux epoll模型) #!/usr/bin/env python#-*- coding:utf-8 -*-import socketimport selectimport Que ...

  2. mysql报错代码10051_socket error 10061/11004/10053/10051等错误总结

    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单 ...

  3. 【Socket网络编程】16.UDP 循环读取recvfrom() 与 循环发送 sendto()

    @zhz: 疑问:有时候会看到某些代码,sendto()时用了while循环, 而recvfrom()时没使用while循环? 答:他们都可以使用循环语句,可参考TCP数据粘包的处理. 什么时候需要使 ...

  4. muduo网络库学习(六)缓冲区Buffer及TcpConnection的读写操作

    在tcp的通信过程中,内核其实为tcp维护着一个缓冲区 当调用write/send时,会向内核缓冲区中写入数据,内核和tcp协议栈负责将缓冲区中的数据发送到指定<ip,port>的目标位置 ...

  5. thrift之TTransport层的堵塞的套接字I/O传输类TSocket

    本节将介绍第一个实现具体传输功能的类TSocket,这个类是基于TCP socket实现TTransport的接口.下面具体介绍这个类的相关函数功能实现. 1.构造函数 分析一个类的功能首先看它的定义 ...

  6. 网络协议收发数据问题

    1 如何收取数据? 对于收数据,当接受连接成功得到 clientfd 后,我们会将该 clientfd 绑定到相应的 IO 复用函数上并监听其可读事件.当可读事件触发后,调用 recv 函数从 cli ...

  7. Signal and SIGIO

    第一步:建立信号处理器 信号是内核传给某个进程的一个整数.当进程接收到信号,它便以以下方式之一响应: 忽略该信号: 让内核完成与该信号关联的默 认操作 : 捕获该信号,即让内核将控制传给信号处理例程, ...

  8. 【 C++ 技术】 C++ 高性能服务器网络框架设计细节

    作者:范蠡  原文:C++ 高性能服务器网络框架设计细节 前言 这篇文章我们将介绍服务器的开发,并从多个方面探究如何开发一款高性能高并发的服务器程序.需要注意的是一般大型服务器,其复杂程度在于其业务, ...

  9. NVMe over TCP Write/Read命令下发流程梳理

    总结 本文对NVMe over TCP的write和read命令下发流程进行了梳理 1. 环境 只针对Linux5.4.0版本的nvme内核模块源代码,使用命令 sudo nvme io-passth ...

最新文章

  1. 给图像特征提取开个“ViP”是什么效果?字节牛津提出视觉解析器,全面超越HaloNet!...
  2. apache使用.htaccess删除.html扩展名_Web前端入门:html元素解析
  3. 用Electron开发企业网盘(二)--分片下载
  4. java事务过大影响系统性能吗_Java编程性能优化-影响性能的因素你都知道吗?
  5. SpringMVC校验---SpringMVC学习笔记(八)
  6. ordersta在php中是什么意思,[求助]ststa中的几个问题
  7. dc/os_DC / OS中具有Java和数据库应用程序的服务发现
  8. 信息学奥赛C++语言:求三位数的值
  9. dijkstra 最短路算法
  10. 芒果超媒:子公司与咪咕文化签署合作框架协议
  11. 在线代理和缓存工具(转)
  12. 新站快速收录同时也提高内页的收录
  13. 何谓自顶向下,何谓自底向上
  14. COMSOL6.0软件安装说明+视频教程
  15. pb中数据窗口函数小结(转)
  16. 杭州女程序员自述:疫情之下被迫离职,仲裁说理被公司索赔百万
  17. ajax把参数放body里,ajax请求-jquery发送ajax请求,参数怎么放到http请求的body里面...
  18. 计蒜客 人人都有极客精神(模拟)
  19. 如何给div加遮罩?
  20. BZOJ3713: [PA2014]Iloczyn

热门文章

  1. 口袋里有红黄蓝白黑5种颜色的球若干个。每次从口袋中先后取出3个球,问得到3种不同颜色的可能取法,输出每种排列的情况。
  2. 【网络安全之易混淆概念--常见算法分类】
  3. 如何使用LearnDash创建像Udemy一样的在线课程市场
  4. litesql mysql_SQLlite数据库
  5. 芋道源码 -- 纯源码解析博客
  6. 阿里云抵御全球互联网史上最大DDoS攻击
  7. 360 se html document 广告,360浏览器弹窗广告如何关闭?教你彻底删除屏蔽360se.exe广告!...
  8. Java 校招面经合集
  9. Python爬虫工程师 3个月成为网络爬虫工程师
  10. linux修改文件名为gbk,Linux下文件名编码转换-Convmv