最近2周在做ineedle的国舜项目扩展,需要使用socket的tcp连接向对方发送消息,当然需求很简单,只是按照对方要求发送指定格式的消息,程序结构也非常的简单,一对多的client/server模型,ineedle发送给多个服务器消息。我们这边在分析出结果,封装为相应格式消息后发送给对方,只需要在线程循环发送消息即可,便在测试环境中编写简单的socket进行模拟消息发送,一对一发送,能够正常发送消息。可以遇到了一个棘手的问题:在服务器端用ctrl+c来结束服务器接收进程来模拟服务器宕机的情况,结束服务socket进程之后,服务端自然关闭进程,可是client端也竟然出乎意料的关闭掉。
这就奇怪了,我在服务端关闭进程,服务器会关闭tcp连接,向client发送FIN包,client响应ack后,等双向tcp连接关闭后,tcp连接彻底关闭,在client端发送消息会失败,返回错误信息,错误消息会被正常的打印出来,可是很多时候错误信息都没有打印(write函数没有返回),有时候返回了错误信息,但是client端进程仍然无辜死掉,我的client端可是用的while(1)死循环啊,怎么可能。于是乎百度了一番,说法千奇百怪,有说防火墙的问题,关闭防火墙仍然如此。郁闷ing,测试了其它方法都不行,打印出错误错误码,也没有查询到结果。
最后问了下我们亲爱的张总,问题刚给他说完,他便说他以前也遇到这个问题,给我找到了他以前的解决方案。解决方法是使用send函数时候在最后一个参数上加MSG_NOSIGNAL标记即可。于是自己更改发送函数write为send并添加MSG_NOSIGNAL标志,重新编译,运行,中断server,果然这个问题被很潇洒的解决了,感谢张总的英明神武。
Linux下当连接断开,还发送数据的时候,不仅send()的返回值会有反映,而且还会向系统发送一个异常消息,如果不作处理,系统会出BrokePipe,程序会退出,这对于服务器提供稳定的服务将造成巨大的灾难。为此,send()函数的最后一个参数可以设置为MSG_NOSIGNAL,禁止send()函数向系统发送常消息。