網絡編程不僅是編寫網絡、主機、進程都正常時能良好工做的進程,更重要的是客戶主機崩潰、客戶進程崩潰網絡異常時怎麼處理。編程
accept被信號中斷
accept以及套接字上的I/O可能被信號打斷,並返回EINTR做爲結果,必須處理該返回值而且適當時候再次調用。
for(;;)
{
if(connfd = accept(listenfd, (struct sockaddr*)addr, sizeof(addr)) < 0)
{
if(connfd == EINTR)
{
continue;
}
else
{
printf("accept error\n");
}
}
}
connect被信號中斷
connect被信號打斷,返回EINTR做爲結果,不能對該socket再次調用connect,須要使用select等待鏈接完成。
accept返回前鏈接夭折
estiblished狀態的鏈接在被accept取走以前夭折,對於這種錯誤,不一樣的系統有不一樣的處理,大多數是返回一個錯誤結果給進程,SVR4返回EPROTO(協議錯誤),posix指出必須返回ECONNABORTED(軟件引發的鏈接錯誤),在返回ECONNABORTED錯誤時,從新調用accept便可。
也有的操做系統會直接清除掉這種夭折的鏈接,服務器進程根本不會發現夭折的鏈接。
echo迴響程序處理服務器端異常終止
客戶端進程阻塞於終端輸入時,服務端進程異常終止,三次握手終止鏈接,客戶端把FIN追加到clifd的讀取緩衝區末尾。
客戶從終端輸入字符,經過clifd發送給服務端(因爲服務端已關閉,會回覆一個RST給客戶端)並調用read獲取結果。
此時FIN已在讀取緩衝區,而RST還在網絡傳輸的過程當中,所以read返回0,表明對端已關閉,而不是讀取到RST的復位消息。
爲了不這種場景的RST消息,客戶端須要使用多路複用同時監聽多個輸入:套接口和終端輸入。這樣就能早先一步獲取FIN消息,避免鏈接終止後還向對端發送消息。
SIGPIPE
進程向一個接收到RST的套接字寫入消息時,內核會給進程發送一個SIGPIPE信號。
完整的過程是:進程向一個接收到FIN的套接字寫入消息,接收到RST應答,此時再次寫入,內核會給進程發送一個SIGPIPE信號。
此信號的缺省動做是終止進程,不產生core文件。
無論進程是否捕捉該信號,寫操做都會返回EPIPE錯誤。
SIGPIPE的處理
SIGPIPE缺省是終止進程,而且不產生core文件,這就無從跟蹤和發現問題。
對SIGPIPE的處理能夠是:
1.設置SIG_IGN,無視該信號,並默認write會處理EPIPE錯誤。
2.信號處理函數中處理該錯誤,須要知道的是,信號處理函數沒法判斷是哪一個套接字出了錯誤,若是確實要知道哪一個套接字出了錯誤,仍是須要在write返回後處理EPIPE錯誤。
服務器主機崩潰
當客戶端和服務器之間創建鏈接後,服務器主機崩潰,此時經過網絡發往服務器主機的消息不會獲得任何迴應。
此時可能返回的錯誤有兩種
1.客戶端持續重傳數據分節,一直沒有獲得迴應,此時應返回ETIMEOUT錯誤。
2.若是中間路由器判斷服務器主機不可達,並返回一個ICMP錯誤,則錯誤是EHOSTUNREACH或ENETUNREACH。
經過write的返回值,能夠得知錯誤緣由,可是一般須要等待很長一段時間。
快速檢測服務器主機崩潰
給套接字加上一個超時時間
在不主動發送消息的時候檢測服務器主機崩潰
心跳消息
服務器主機崩潰後重啓
若是服務器主機崩潰後並重啓,在崩潰期間客戶沒有發送消息給服務器,那麼客戶端是不知道服務器曾經崩潰過的(若是不使用套接字選項SO_KEEPALIVE),客戶端給服務器發送消息。
服務器崩潰並重啓後丟失了全部的鏈接信息,對於接收到的消息都以RST響應,致使客戶端收到ECONNRESET錯誤。
若是客戶端檢測服務器的主機崩潰錯誤,那應該設置SO_KEEPALIVE。
服務器主機關機
UNIX系統關機時,由INIT進程給全部進程發送SIGTERM信號(咱們能夠捕捉此信號),而後等待一段時間,而後給全部進程發送SIGKILL信號。進程終止時,全部打開的描述字都將關閉。
對於服務器主機關機,客戶最好使用多路複用及時檢測到套接字的關閉。
網絡數據格式
1.轉換全部格式的數據爲字符串消息
2.明確指定字節序,在服務器和客戶端使用一樣的字節序。