导读:
好难受啊, 为什么服务端说挂就挂, 明明只是客户端关闭而已, 服务端怎么能挂呢?
想想, 如果手机上使用一个聊天程序的时候, 手机端关闭了聊天程序, 那么远端服务器程序总不能说挂就挂吧! 所以一定要查明真相.
1. 跟踪代码查找到进程退出的源头
之前服务端源码: https://www.cnblogs.com/songsongman/p/11187844.html
查阅代码发现, 代码主体在 while(1)里面, 所以最可疑的地方在于 accpet,pthread_create, pthread_join 和创建的线程 client_thread 了
明摆着就是 client_thread 中出了问题, 因为 accpet,pthread_create, pthread_join 中都有根据函数返回值做是否出错的判断, 还是认怂好好看看线程做了什么:
- void *client_thread(void *arg)
- {
- int clifd = *(int *)arg;char *s = "hello mysocketclient\n";
- while(1)
- {
- usleep(1000000);
- write(clifd,s,strlen(s));//send(clifd,s,strlen(s),0);
- }
- return (void *)0;
- }
哇! 居然使用 write 的时候没有添加返回值的判断, 在 Ubuntu 终端中输入 man 2 write, 可以看到 write 出错时候会返回 - 1;
2. 简单完善代码容错机制
添加容错代码后以后看看效果如何, 代码如下:
- while(1)
- {
- usleep(1000000);
- ret = write(clifd,s,strlen(s));//send(clifd,s,strlen(s),0);
- if(ret == -1)
- {
- printf("client thread write failed !\n");
- close(clifd);
- pthread_exit(NULL);
- }
- }
执行结果如下:
过程分析,
1. 先执行服务端程序, 然后运行客户端程序, 客户端程序强制退出(通过快捷键 ctrl+c), 服务端 client_thread 中 write 返回 - 1, 线程正常退出.
2. 这时候服务端程序还阻塞在 accpet 等待下一次的客户端连接请求, 运行新的客户端程序, 然后强制退出客户端, 发现服务端进程居然直接退出了!
咋办啊! 感觉代码没有任何问题了, 为啥还会出错, 虽然很明确一定是 write 的时候没能写进客户端导致的进程奔溃, 但是却无从下手.
(注意: 为了解决这个问题, 笔者绞尽脑汁修改, 比如添加
shutdown(clifd, SHUT_RDWR);
又或者添加 getsockopt 来实时获取连接状态
)效果都不佳, 无法解决问题.
3. 添加捕获异常来再次加强容错机制
绞尽脑汁似乎没有什么效果, 抓耳挠腮看看吧, 好好翻翻书, 看看能不能找到灵感.
从网上找到一本和 UNIX 系统编程有关的书籍《UNIX 环境高级编程_第二版中文》, 因为 Android 是基于 Linux 开发的操作系统, Linux 又是从 UNIX 那边衍射出来的,
所以 Linux 系统编程这块参考这本书特别靠谱.
看到一个和信号有关的章节, 确定了要用 signal 来检测异常, 可检测的信号可真多啊!
然后不小心看到这点
好吧, 灵感来了, 开始写代码, 直接添加头文件
include <signal.h>
然后再 main 函数中添加 signal(SIGPIPE, SIG_IGN);
运行服务端, 再运行客户端, 不管客户端怎么退出重启, 服务端都不受影响了.
任务完成!
最后
如果你看到了这里, 觉得文章写得不错就给个赞呗? 如果你觉得那里值得改进的, 请给我留言. 一定会认真查询, 修正不足. 谢谢.
来源: http://www.jianshu.com/p/113901ae46b0