SIGPIPE信号详解

当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。

我写了一个服务器程序,在Linux下测试,然后用C++写了客户端用千万级别数量的短链接进行压力测试.  但是服务器总是莫名退出,没有core文件.

最后问题确定为, 对一个对端已经关闭的socket调用两次write, 第二次将会生成SIGPIPE信号, 该信号默认结束进程.

具体的分析可以结合TCP的"四次握手"关闭. TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协议的语义, 表示对端只是关闭了其所负责的那一条单工信道, 仍然可以继续接收数据. 也就是说, 因为TCP协议的限制, 一个端点无法获知对端的socket是调用了close还是shutdown.

对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送). 但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据. 所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出.

为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数:

signal(SIGPIPESIG_IGN);

这样, 第二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE. 程序便能知道对端已经关闭.

linux下写socket的程序的时候,如果尝试send到一个disconnected socket上,就会让底层抛出一个SIGPIPE信号。
这个信号的缺省处理方法是退出进程,大多数时候这都不是我们期望的。因此我们需要重载这个信号的处理方法。调用以下代码,即可安全的屏蔽SIGPIPE

signal (SIGPIPE, SIG_IGN);

我的程序产生这个信号的原因是: 
client端通过 pipe 发送信息到server端后,就关闭client端, 这时server端,返回信息给 client 端时就产生Broken pipe 信号了,服务器就会被系统结束了。

对于产生信号,我们可以在产生信号前利用方法 signal(int signum, sighandler_t handler) 设置信号的处理。如果没有调用此方法,系统就会调用默认处理方法:中止程序,显示提示信息(就是我们经常遇到的问题)。我们可以调用系统的处理方法,也可以自定义处理方法。

系统里边定义了三种处理方法: 
(1)SIG_DFL信号专用的默认动作:
  (a)如果默认动作是暂停线程,则该线程的执行被暂时挂起。当线程暂停期间,发送给线程的任何附加信号都不交付,直到该线程开始执行,但是SIGKILL除外。
  (b)把挂起信号的信号动作设置成SIG_DFL,且其默认动作是忽略信号 (SIGCHLD)。
(2)SIG_IGN忽略信号
  (a)该信号的交付对线程没有影响
  (b)系统不允许把SIGKILL或SIGTOP信号的动作设置为SIG_DFL
3)SIG_ERR

项目中我调用了signal(SIGPIPESIG_IGN), 这样产生  SIGPIPE 信号时就不会中止程序,直接把这个信号忽略掉。

iOS端内处理sigpipe

当使用 socket 进行网络连接时,如果连接中断,在默认情况下,你的 process 会收到一个 SIGPIPE 信号。如果你没有处理这个信号,app 会直接 crash!!!

有两种方法可以解决这个问题,任选其一:

  • 在全局范围内忽略这个信号
signal(SIGPIPE, SIG_IGN);

需要注意的是,这个方法是全局通用的,所有的 SIGPIPE 信号都将被忽略

  • 在一开始的时候设置 socket 不要发送 SIGPIPE 信号
/// sock 就是设置不发送 `SIGPIPE` 信号的 socket 变量
int value = 1;
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));

附上 APPLE 原文(ref1):

Use POSIX sockets efficiently (if at all). If you are using POSIX sockets directly:

  • Handle or disable SIGPIPE.

When a connection closes, by default, your process receives a SIGPIPE signal. If your program does not handle or ignore this signal, your program will quit immediately. You can handle this in one of two ways:

  • Ignore the signal globally with the following line of code:
signal(SIGPIPE, SIG_IGN);
  • Tell the socket not to send the signal in the first place with the following lines of code (substituting the variable containing your socket in place of sock):
int value = 1;
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));

For maximum compatibility, you should set this flag on each incoming socket immediately after calling accept in addition to setting the flag on the listening socket itself.

SIGPIPE信号详解及相关推荐

  1. SIGPIPE信号详解

    SIGPIPE信号详解 当服务器close一个连接时,若client端接着发数据.根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进 ...

  2. signal信号详解

    signal信号详解本文引用其它网站. 信号机制是进程之间相互传递消息的一种方法,信号全称为软中断信号,也有人称作软中断.从它的命名可以看出,它的实质和使用很象中断.所以,信号可以说是进程控制的一部分 ...

  3. Linux信号详解:signal与sigaction函数【2】

    我们已经讨论了Linux操作系统中"信号"."中断"."僵尸进程"'等重要概念.结合C语言中的setjmp.longjump.sigsetj ...

  4. 轮毂电机光电增量编码器的ABZ信号详解

    轮毂电机ABZ信号详解. 轮毂电机的定位使用了霍尔信号和光电增量编码器,1024线的.也就意味着,轮子转一圈,A信号和B信号各有1024个高电平和低电平. 实际应用中,我们将A/B信号的上升沿和下降沿 ...

  5. ASUS笔记本电路信号详解

    ASUS笔记本电路信号详解 BATSEL_2P#:EC通过SM总线得知电池电量信息后,发出BATSEL_2P#信号,给充放电芯片,控制充电电流(控制ICTL).  BATSEL_3S#:EC通过SM总 ...

  6. 【Linux信号专题】五、SIGCHLD信号详解

    欢迎关注博主 Mindtechnist 或加入[Linux C/C++/Python社区]一起探讨和分享Linux C/C++/Python/Shell编程.机器人技术.机器学习.机器视觉.嵌入式AI ...

  7. 《PyQt5高级编程实战》自定义信号详解

    自定义信号详解 1. 创建自定义信号 2. 让自定义信号携带值 3. 自定义信号的重载版本 4. 窗口间通信 5. 线程间通信 PyQt5中各个控件自带的信号已经能够让我们完成许多需求,但是如果想要更 ...

  8. Linux系统的信号详解

    一.信号类型 1) SIGHUP       2) SIGINT       3) SIGQUIT     4) SIGILL        5) SIGTRAP 6) SIGABRT      7) ...

  9. 【Linux】第八讲:Linux进程信号详解(一)_ 认识信号 | 产生信号

    「前言」文章是关于Linux进程信号方面的知识,本文的内容是Linux进程信号第一讲,讲解会比较细,下面开始! 「归属专栏」Linux系统编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫 ...

最新文章

  1. Python并发编程实例教程
  2. 如何在python中创建列表副本,在Python中切片列表而不生成副本
  3. 中小型商业银行的软件安全测试之道
  4. NLP-基础知识-003(词性标注)
  5. c++ 分析core文件 在os x
  6. swagger3 设置值可以为空_【Swagger2】【3】API注解详解,以及注解常用参数配置
  7. 探寻浏览器渲染的秘密
  8. Windows 11 快速体验:开始菜单居中,全系圆角设计!
  9. JS中ptototype和__proto__的关系
  10. ubuntu部署tomcat
  11. 【英语学习】【Level 07】U06 First Time L4 Lost in Shanghai
  12. CS48 D BIT
  13. 双系统重装windows后修复UBUNTU的GRUB
  14. C++ / vs 如何生成自己的静态库(lib)文件
  15. Funcode实现打飞虫1
  16. VMWare虚拟机Linux系统忘记登录密码
  17. 简单人物画像_简易人物画像图
  18. 建筑设计的未来是什么?| 建筑 · 人工智能专栏
  19. 网络安全学习--002--windows基础知识
  20. 龙芯linux内核空间内存划分,最强龙芯+最新内核+最大内存

热门文章

  1. Pg处理MIMIC数据
  2. python实现签名RSA算法
  3. 在相同CDB下进行unplug,plug PDB的操作。(plug or unplug a pdb using same cdb)
  4. 2021年电工(初级)答案解析及电工(初级)作业考试题库
  5. 美亚柏科:与阿里就公安云计算签合作协议
  6. php生成随机数永不重复,PHP生成不重复随机数的方法汇总
  7. 机器学习稀疏矩阵简介(附Python代码)
  8. QT自定义安装包制作原理
  9. http://itunes.apple.com/lookup?id=获取不到版本
  10. Python处理图片