前面我們解決了併發服務端的問題, 但是還是沒有解決掉客服端的bug.
我們以上一節的**為例浮現這個bug.
完整** : fork_sigchld.c
可能你已經忘了客服端的問題了, 這裡在重新說明一下 : 當建立連線後, 服務端主動關閉後, 客服端並沒有立即退出, 而是處於阻塞狀態直到有輸入才會退出.
分析問題的時, 應該先來看一下抓包的情況.
問題基本也能分析出來.
服務端關閉時向客服端傳送fin
, 根據四次揮手的原則, 此時客服端還能夠向服務端傳送資料, 也就解釋了客服端沒有傳送fin
而是阻塞在read
函式等待輸入資料, 但服務端其實傳送fin
後就被關閉了, 等待客服端傳送資料後因為對端已經完全關閉了所以傳送rst
.
客服程序看不到rst
, 因為在呼叫read
之後立即呼叫write
並且收到服務端的fin
後返回0, 程序繼續阻塞在第二次的read
函式.
其實當程序接收到rst
的套接字執行的寫操作時, 核心會向該程序傳送sigpipe
訊號. 該訊號預設行為是為了終止程序, 但是該訊號預設是被忽略的, 所以解決這個問題就需要客服端捕捉該訊號然後退出才行.
有了這個辦法接下來在客服端捕捉sigpipe
訊號即可.
void
sighandler
(int signo)
}int
main()
完整** : client_sigpipe.c
服務端 :
.
/a.out 1
8080
127.0
.0.1
客服端 :
當服務端關閉後客服端阻塞直到傳送資料, 但是客服端write
返回0, 然後繼續阻塞到第二次read
; 當第二次read
後才捕捉ret
訊號呼叫捕捉函式.
最終我們成功捕捉到了ret
訊號, 但實際並沒有完美的解決客服端阻塞的問題, 而且通過訊號捕捉也不是乙個很好的解決方案, 畢竟如果客服端也是多工的話捕捉就出問題的. 難道這個問題就沒有辦法很好的解決了? 別急, 在下一節分析完了就可以完美的解決了.
這裡在羅嗦一下, 涉及到與題意無關的, 但希望大家能借該例子理解一下半開啟連線的知識.
服務端(或者客服端)異常終止了連線, 而對端沒有接收到報文段, 此時對端還維持這原來的連線, 這種狀態就被稱為半開啟. 就算服務端重啟後也並不知道對端的存在, 只有對端傳送資料過來, 自己不認識會回rst
, 對端才知道關閉連線.
注意: 這裡是半開啟, 與後面談到的半關閉 [1]
並不一樣.
前面通訊中關於recv
引數中,flag
選項 [1]
可以設定錯誤時不傳送sigpipe
訊號.
TCP的套接字
摘自 深入理解計算機網路 王達著 機械工業出版社 1.ipv4資料報頭部格式 2.ipv6資料報頭部格式 3.ipv4資料報的封裝與解封裝 4.ipv4資料報的分段與重組 5.arp協議報文格式及arp表 6.arp位址解析原理 7.icmp協議及報文格式 8.ipv6協議族的其它協議 9.tcp的...
TCP套接字程式設計
網路程式設計又稱為套接字程式設計,為了與遠端計算機進行資料傳輸,需要連線到網際網路,而程式設計中的 套接字 就是用來連線該網路的工具。它本身具有連線的含義,還可以表示為兩台計算機之間的網路連線。4.呼叫accept函式受理連線請求 基於tcp的服務端 客戶端 tcp伺服器端預設函式呼叫順序 sock...
TCP套接字程式設計
對於socket不理解的可以檢視 c語言通過socket程式設計實現tcp通訊,linux socket程式設計 socket詳解 先看看程式效果圖 提示如果伺服器,直接通過ctrl z關閉,這樣程式占用的位址不會釋放,需要以下操作 1.ps 檢視程序 2.kill 9 程式pid 強制殺死程序 服...