導讀:html
好難受啊,爲何服務端說掛就掛,明明只是客戶端關閉而已,服務端怎麼能掛呢?linux
想一想,若是手機上使用一個聊天程序的時候,手機端關閉了聊天程序,那麼遠端服務器程序總不能說掛就掛吧!因此必定要查明真相。android
1. 跟蹤代碼查找到進程退出的源頭編程
以前服務端源碼:http://www.javashuo.com/article/p-uaclxhvz-kv.htmlubuntu
查閱代碼發現,代碼主體在while(1)裏面,因此最可疑的地方在於accpet,pthread_create, pthread_join和建立的線程client_thread了服務器
明擺着就是client_thread中出了問題,由於accpet,pthread_create, pthread_join中都有根據函數返回值作是否出錯的判斷,仍是認慫好好看看線程作了什麼:socket
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.簡單完善代碼容錯機制spa
添加容錯代碼後之後看看效果如何,代碼以下:操作系統
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來檢測異常,可檢測的信號可真多啊!
圖3.1 參考UNIX環境高級編程第二版中文第10章表1
而後不當心看到這點
好吧,靈感來了,開始寫代碼,直接添加頭文件
#include <signal.h>
而後再main函數中添加signal(SIGPIPE, SIG_IGN);
運行服務端,再運行客戶端,無論客戶端怎麼退出重啓,服務端都不受影響了。
任務完成!