tcp socket在调用send接口时,出现了程序出现:Program received signal SIGPIPE, Broken pipe的异常。
说明程序收到了SIGPIPE的信号。一般网上的处理手段是signal(SIGPIPE, SIG_IGN);忽略这个信号,但实际测试过程中貌似没太生效,这块没具体研究。
还是直接分析下原因,为何
sendret = send(sockfd, sendmsg, strlen(sendmsg), 0);
这样一段代码会引起程序收到SIGPIPE信号呢?
直接看下send对应的代码吧:
kernel:tcp_sendmsg函数
err = -EPIPE;
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
goto out_err;
... ...
out_err:
err = sk_stream_error(sk, flags, err);
release_sock(sk);
return err;
int sk_stream_error(struct sock *sk, int flags, int err)
{
if (err == -EPIPE)
err = sock_error(sk) ? : -EPIPE;
if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
send_sig(SIGPIPE, current, 0);
return err;
}
可以看出:当send操作的socketfd被关闭的时候,会抛出sigpipe的异常。
而看上述代码,flags如果带有MSG_NOSIGNAL标志的话,就不会抛出异常,所以在应用层调用send时,可以如下:
sendret = send(sockfd, sendmsg, strlen(sendmsg), MSG_NOSIGNAL);
这样就不会抛出异常。
两个疑问:
1)除了操作send的flag,还有其它手段吗?通过select或者epoll监听sockfd的事件,判断sockfd可写后再发送可以吗?但是会不会出现当epoll发现可写时,但是真正send时socket的状态又被改变的场景?
2)signal(SIGPIPE, SIG_IGN);的方式为何不生效呢?
|