问题描述:
Linux下应用软件崩溃,报SIGPIPE错误。跟踪代码发现服务端关闭socket连接后,客户端继续向服务端发送报文导致。(ps:对于老手,定位问题应该更快,通过SIGPIPE就能判断错误位置,可以参考linux下错误提示errrno,可以看手册man,也可以参考博主https://blog.csdn.net/u010629326/article/details/76021420)。
问题分析:
SIGPIPE错误的原因就是服务端Socket关闭,客户端继续向服务端发送报文导致的错误。
问题解决:
由上面原因总结出两种方法:
1、设置系统忽略SIGPIPIE消息,从结果解决SIGPIPE错误导致程序崩溃问题;
在socket建立时设置下列属性,socket将不会产生SIGPIPE信号。
int optval=1;
#ifdef __linux__
setsockopt(m_Sockfd, SOL_SOCKET, MSG_NOSIGNAL, &optval, sizeof(optval));
#else
setsockopt(m_Sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
#endif
在main函数设置如下属性,SIGPIPE信号还是会产生,只是应用程序不将处理这个信号,也就不会闪退。
#ifdef UNIX_ENV
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction(SIGALRM, &sa, 0);
sigaction(SIGPIPE, &sa, 0);
#endif
2、客户端在发送报文前判断连接状态,并决定是否重新建立连接,这样从根源解决这个问题。
客户端在发送前非阻塞读取数据,如果发现recv()返回0时,代表服务端已经关闭socket,此时需要重新建立连接。为了方便调试,linux下返回错误提示的变量errno可以输出出来查看,此变量在socket建立时初始值为0,非组态connect连上后值为errno值发生变化一般为EINPROGRESS。
当调用connect、listen、accept、recv、write等socket接口时,返回小于0的值时表示出现错误,可以通过查看errno值定位问题。目前看来其他返回值不会修改errno的值。