SIGPIPE信号

SIGPIPE信号详解

当服务器端kill掉一个已连接的子进程时(也就是close一个连接),如果客户端不理会 该操作,反而写入更多的数据到服务器上,会发生什么呢?这种情况是可能发生的,举例来说,客户可能在读回任何数据之前执行两次针对服务器的写操作,而RST是由其中第一次写操作引发的。

适用于此的规则是:当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿地被终止。

不论该进程是捕获了该信号并从其信号处理函数返回,还是简单地忽略该信号,写操作都将返回EPIPE错误。

具体的分析可以结合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(SIGPIPE, SIG_IGN);

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


在Linux下写socket程序的时候,如果尝试send到一个disconnected socket上,就会让底层抛出一个SIGPIPE信号。

这个信号的缺省处理方法就是退出进程,大多数时候这不是我们期望的结果。因此我们需要重载这个信号的处理方法。调用以下代码即可安全的屏蔽SIGPIPE

signal(SIGPIPE, SIG_IGN);

我们的程序产生这个信号的原因是:

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


对于产生信号,我们可以父进程开始时登记一个SIGPIPE信号,并调用自己的信号处理函数signal(SIGPIPE, handler_sigpipe),具体怎么处理该信号,就要看自己的handler_sigpipe函数是怎么写的了。如果没有调用此方法,系统就会调用默认的处理方法:终止程序,显示提示信息。


系统中定义了三种处理方法:

1)SIG_DFL信号专用的默认动作

  • 如果默认动作是暂停线程,则该线程的执行 被暂时挂起。当线程暂停期间,发送给线程的任何附加信号都不交付,知道该线程开始执行,但是SIGKILL除外。
  • 把挂起信号的信号动作设置成SIG_DFL,且其默认动作是忽略信号(SIGCHLD)。
2)SIG_IGN忽略信号
  • 该信号的交付对线程没有影响
  • 系统不允许把SIGKILL或SIGSTOP信号的动作设置为SIG_DFL
3)SIG_ERR


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值