[TCP]向已关闭的socket执行send(),会出现“signal SIGPIPE, Broken pipe“错误,导致server进程退出的原因和对策

现象

最近写了一个reactor模型代码,使用wrk来测试性能时,发现wrk结束运行后,reactor也会结束运行。
左侧的reactor进程随着wrk结束而结束了

reactor应该在mainloop中循环,不应该直接退出才对。

原因

我在各个关键函数中加了printf,发现reactor退出时,send()后面的printf没有输出。
又用gdb运行一次,gdb返回的结果是:
gdb的结果
的确是在send处出了问题,原因是:

Program received signal SIGPIPE, Broken pipe.

Broken Pipe错误通常是与一个已关闭的管道进行通信时出现的。

我的reactor代码运行时可能发生了这样的事:
1.wrk向reactor发送了数据,然后wrk关闭了fd。
2.reactor代码中,接受了数据后,自动把fd的event修改为EPOLLOUT,这样就一定会执行send()。
3.此时fd已经被关闭了,send()失败,函数向系统发出了一个SIGPIPE信号,系统接到信号后,默认结束了reactor进程。
//↑这是我猜的,等待后续验证

解决办法

解决办法就是不让send()发出SIGPIPE信号。
send()的第三个参数可以设置MSG_NOSIGNAL Flag,来禁止发送SIGPIPE信号。

       MSG_NOSIGNAL (since Linux 2.2)
              Don't generate a SIGPIPE signal if the peer on a stream-
              oriented socket has closed the connection.  The EPIPE
              error is still returned.  This provides similar behavior
              to using sigaction(2) to ignore SIGPIPE, but, whereas
              MSG_NOSIGNAL is a per-call feature, ignoring SIGPIPE sets
              a process attribute that affects all threads in the

所以把send代码进行以下修改:
before:

int count = send(fd, buff, index, 0);
printf("send,to clientfd:%d,count=%d\n", clientfd, count);

after

int count = send(clientfd, buff, index, MSG_NOSIGNAL);
if(count == -1)
{
	perror("send");
	printf("send err,to clientfd:%d,count=%d\n", clientfd,count);
	set_event(clientfd,-1,SET_EVENT_DEL);	
}
else
	printf("send,to clientfd:%d,count=%d\n", clientfd, count);

再用wrk测试一下:
在这里插入图片描述

可以看到,确实有send()报了“broken pipe”的error(上文提到的EPIPE),并且返回值是-1。
而这次没有结束进程。
此时再启动一个net assistant模拟client,还是可以继续跟reactor进程通信的。
所以目前解决了reactor进程结束的问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值