【原创】SIGPIPE 信号处理整理
整理 原创 信号处理
2023-09-14 08:59:46 时间
// 写法四(仅在 IOS 系统上支持 SO_NOSIGPIPE)
#if defined(SO_NOSIGPIPE) !defined(MSG_NOSIGNAL)
// We do not want SIGPIPE if writing to socket.
注:关于传统 signal 系统调用的问题,可以参考《Linux signal那些事儿》
产生 SIGPIPE 的条件
对一个已经收到 FIN 包的 socket 调用 read 方法,如果接收缓冲已空,则返回 0,这就是常说的“连接关闭”表示。
对一个已经收到 FIN 包的 socket 第一次调用 write 方法时,如果发送缓冲没问题,则 write 调用会返回写入的数据量,同时进行数据发送。但是发送出去的报文会导致对端发回 RST 报文。因为对端的 socket 已经调用了 close 进行了完全关闭,已经处于既不发送,也不接收数据的状态。所以第二次调用 write 方法时(假设在收到 RST 之后)会生成 SIGPIPE 信号,导致进程退出(这就是为什么第二次 write 才能触发 SIGPIPE 的原因)。
民间描述:
对一个对端已经关闭的 socket 调用两次 write,第二次 write 将会生成 SIGPIPE 信号,该信号默认结束进程。
APUE 上的描述:
如果在写到管道时读进程已经终止,则产生此信号(管道角度)。当类型为 SOCK_STREAM 的套接字已不再连接时,进程写到该套接字也产生此信号(socket 角度)。
SIGPIPE 的处理方式
为了避免进程退出,既可以对 SIGPIPE 信号进行捕获,也可以将其忽略,即为其设置 SIG_IGN 信号处理函数(在系统头文件 signal.h 中定义的常量):
?
这样,当第二次调用 write 方法时,会返回 -1,同时 errno 会被设置成 EPIPE ,程序便能知道对端已经关闭。
-=-=-=-
关于 signal() 函数的说明:
signal 函数由 ISO C 定义。因为 ISO C 不涉及多进程,进程组以及终端 I/O 等,所以它对信号的定义非常含糊,以至于对 UNIX 系统而言几乎毫无用处。 因为 signal 的语义与系统实现有关,所以最好使用 sigaction 函数代替 signal 函数。 signal 函数的限制:不改变信号的处理方式,就不能确定信号的当前处理方式(因为需要通过 signal 函数的返回值来确定以前的处理配置);sigaction 函数则没有这个问题。 基于 signal 函数实现的信号处理可能是不可靠的(在早期的 UNIX 版本中,进程每次接到信号进行处理时,(内核已经在投递前)将该信号的动作复位为默认值 SIG_DFL,所以从信号发生之后到在信号处理程序中再次调用 signal 函数之前这段时间中有一个时间窗口。若在这个窗口中再发生一次该信号,则会导致执行该信号的默认动作,可能导致进程的终止) -=-=-=-
另外,还有其他方法来处理 SIGPIPE 信号:设置 socket 在进行写操作时不产生 SIGPIPE 信号。
?
这样做的好处在于:在某些情况 下我们并不需要一个全局的 SIGPIPE handler 。但是 SO_NOSIGPIPE 不具有可移植性,后续有说明。
-=-=-=-
查阅资料后找到了两个方法:
使用 signal(SIGPIPE, SIG_IGN) 忽略 SIGPIPE 。经实验在 ios7 模拟器上虽然 xcode 还是会捕获 SIGPIPE,但是程序不会崩溃,继续后可以执行。但是在真机上依然会崩溃。 使用 SO_NOSIGPIPE 。经实验在多个 ios 版本下都不再触发 SIGPIPE,完美解决问题。 SO_NOSIGPIPE 在 mac 中存在,可惜在 android 中不存在。请使用 MSG_NOSIGNAL 来代替
?
Linux YOYO 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Requests not to send SIGPIPE on errors on stream oriented sockets when the other end breaks the connection. The EPIPE error is still returned.
自从 Linux 2.2 开始提供对 MSG_NOSIGNAL 的支持。若设置该 flag 则 socket 远端读被关闭时,内核也不会发送 SIGPIPE 信号给当前进程。设置后,仍然可以得到 EPIPE 错误码。 EPIPE The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
面向连接的 socket 的本地端由于 “Broken Pipe” 关闭时,产生该错误码。该这种情况,如果进程没有设置 MSG_NOSIGNAL 则还会收到 SIGPIPE 信号。
如何对技术视频转换文章投稿进行二次创作 在技术社区经常会收到一些大的平台(华为云博客、infoq 等平台的投稿任务),经过对数千篇通用技术稿件,积攒了一些小技巧。所以,在你创作之前还是要好好的看一下,希望对你有帮助!
知乎高赞:985计算机视觉毕业后找不到工作怎么办?怒刷leetcode,还是另寻他路? 985 研究生,学计算机视觉,出来后找不到工作?本文带你看看这个 70 万浏览量问题下的答案干货:真正的人才什么时候都紧缺,搞扎实自己的基本功比什么都重要。心态放平,好好刷 leetcode,好 offer 总在不远处。
注:关于传统 signal 系统调用的问题,可以参考《Linux signal那些事儿》
产生 SIGPIPE 的条件
对一个已经收到 FIN 包的 socket 调用 read 方法,如果接收缓冲已空,则返回 0,这就是常说的“连接关闭”表示。
对一个已经收到 FIN 包的 socket 第一次调用 write 方法时,如果发送缓冲没问题,则 write 调用会返回写入的数据量,同时进行数据发送。但是发送出去的报文会导致对端发回 RST 报文。因为对端的 socket 已经调用了 close 进行了完全关闭,已经处于既不发送,也不接收数据的状态。所以第二次调用 write 方法时(假设在收到 RST 之后)会生成 SIGPIPE 信号,导致进程退出(这就是为什么第二次 write 才能触发 SIGPIPE 的原因)。
民间描述:
对一个对端已经关闭的 socket 调用两次 write,第二次 write 将会生成 SIGPIPE 信号,该信号默认结束进程。
APUE 上的描述:
如果在写到管道时读进程已经终止,则产生此信号(管道角度)。当类型为 SOCK_STREAM 的套接字已不再连接时,进程写到该套接字也产生此信号(socket 角度)。
SIGPIPE 的处理方式
为了避免进程退出,既可以对 SIGPIPE 信号进行捕获,也可以将其忽略,即为其设置 SIG_IGN 信号处理函数(在系统头文件 signal.h 中定义的常量):
?
这样,当第二次调用 write 方法时,会返回 -1,同时 errno 会被设置成 EPIPE ,程序便能知道对端已经关闭。
-=-=-=-
关于 signal() 函数的说明:
signal 函数由 ISO C 定义。因为 ISO C 不涉及多进程,进程组以及终端 I/O 等,所以它对信号的定义非常含糊,以至于对 UNIX 系统而言几乎毫无用处。 因为 signal 的语义与系统实现有关,所以最好使用 sigaction 函数代替 signal 函数。 signal 函数的限制:不改变信号的处理方式,就不能确定信号的当前处理方式(因为需要通过 signal 函数的返回值来确定以前的处理配置);sigaction 函数则没有这个问题。 基于 signal 函数实现的信号处理可能是不可靠的(在早期的 UNIX 版本中,进程每次接到信号进行处理时,(内核已经在投递前)将该信号的动作复位为默认值 SIG_DFL,所以从信号发生之后到在信号处理程序中再次调用 signal 函数之前这段时间中有一个时间窗口。若在这个窗口中再发生一次该信号,则会导致执行该信号的默认动作,可能导致进程的终止) -=-=-=-
另外,还有其他方法来处理 SIGPIPE 信号:设置 socket 在进行写操作时不产生 SIGPIPE 信号。
?
这样做的好处在于:在某些情况 下我们并不需要一个全局的 SIGPIPE handler 。但是 SO_NOSIGPIPE 不具有可移植性,后续有说明。
-=-=-=-
查阅资料后找到了两个方法:
使用 signal(SIGPIPE, SIG_IGN) 忽略 SIGPIPE 。经实验在 ios7 模拟器上虽然 xcode 还是会捕获 SIGPIPE,但是程序不会崩溃,继续后可以执行。但是在真机上依然会崩溃。 使用 SO_NOSIGPIPE 。经实验在多个 ios 版本下都不再触发 SIGPIPE,完美解决问题。 SO_NOSIGPIPE 在 mac 中存在,可惜在 android 中不存在。请使用 MSG_NOSIGNAL 来代替
?
Linux YOYO 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
Requests not to send SIGPIPE on errors on stream oriented sockets when the other end breaks the connection. The EPIPE error is still returned.
自从 Linux 2.2 开始提供对 MSG_NOSIGNAL 的支持。若设置该 flag 则 socket 远端读被关闭时,内核也不会发送 SIGPIPE 信号给当前进程。设置后,仍然可以得到 EPIPE 错误码。 EPIPE The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.
面向连接的 socket 的本地端由于 “Broken Pipe” 关闭时,产生该错误码。该这种情况,如果进程没有设置 MSG_NOSIGNAL 则还会收到 SIGPIPE 信号。
如何对技术视频转换文章投稿进行二次创作 在技术社区经常会收到一些大的平台(华为云博客、infoq 等平台的投稿任务),经过对数千篇通用技术稿件,积攒了一些小技巧。所以,在你创作之前还是要好好的看一下,希望对你有帮助!
知乎高赞:985计算机视觉毕业后找不到工作怎么办?怒刷leetcode,还是另寻他路? 985 研究生,学计算机视觉,出来后找不到工作?本文带你看看这个 70 万浏览量问题下的答案干货:真正的人才什么时候都紧缺,搞扎实自己的基本功比什么都重要。心态放平,好好刷 leetcode,好 offer 总在不远处。
相关文章
- 容易遗忘的JS知识点整理
- 近5年常考Java面试题及答案整理(三)
- select、poll、epoll之间的区别总结[整理]
- wireshark 抓包整理———— 从一个小案例开始 [一]
- hadoop 日常错误解决方法整理
- 计算机网络再次整理————tcp例子第二前奏[四]
- redis 面试题整理
- arthas命令整理:基础命令、jvm相关、class相关命令
- uniapp滑动到一定的高度后固定某个元素到顶部效果demo(整理)
- js左划出现删除按钮,右滑隐藏demo效果示例(整理)
- 100集华为HCIE安全培训视频教材整理 | IPSec VdPdN高可靠性案例及配置(六)
- 60集Python入门视频PPT整理 | Python迭代器和列表解析
- 操作系统核心知识点整理--进程篇
- 【跟学C++】C++STL标准模板库——算法详细整理(下)(Study18)