socket編程中主動關閉VS被動關閉
tcp中server,client都可能是主動關閉方或者被動關閉方,現闡述下兩者之間的關系:
客戶端(client) 服務器(server)
close() Fin x -> 讀通道關閉(close_wait)
寫通道關閉 <- Ack x+1
讀通道關閉(time_wait) <- Fin y close()
ack y+1 -> 寫通道關閉
2x msl closed
closed
1、 客戶端是調用函數close(),這時,客戶端會發送一個FIN給服務器。
2、 服務器收到FIN,關閉套接字讀通道,並將自己狀態設置為CLOSE_WAIT(表示被動關閉),
並返回一個ACK給客戶端。
3、 客戶端收到ACK,關閉套接字寫通道
接下來,服務器會調用close():
1、 服務器close(),發送一個FIN到客戶端。
2、 客戶端收到FIN,關閉讀通道,並將自己狀態設置成TIME_WAIT,發送一個ACK給服務器。
3、 服務器收到ACK,關閉寫通道,並將自己狀態設置為CLOSE。
4、 客戶端等待兩個最大數據傳輸時間,然后將自己狀態設置成CLOSED。
有了上面的背景知識,對於我們系統線上一個case分析就很簡單了!
首先是主動關閉日志很多,后來是被動關閉的日志
由於server端發現了大量閑置的沒有Io的socket連接,有監聽器在監聽是否存在閑置的socket連接,就釋放並關閉這些連接,time_wait就出現了,這個時候應用方客戶端重啟應用,釋放了資源包括一些客戶端連接,這個時候close_wait出現了,正好是以上日志所反映的
同時time_wait狀態的連接是不會釋放內核資源,所以服務端不要輕易close!
socket中的read返回0
在socket中服務器與客戶端進行通信,當其中一方調用close(即這一方會發送一個fin)關閉套接字之后,另一方read()會返回一個0。
我之前編寫的一個服務器與客戶端通信(一個服務器只連接一個客戶端):服務器開兩個進程,一個用於接收客戶端發送的數據,另一個進程用於
向客戶端發送數據。客戶端開兩個進程也是一個用於發送數據一個用於接收數據。由於創建了兩個進程,那么套接字的引用計數都為2,只有當客戶
端關閉兩次套接字,在服務器的read()才會返回0
另外,如果在虛擬機上運行,打開兩個shell,一個運行客戶端,一個運行服務器,當關閉運行客戶端的shell,則服務器的read()會返回0
python socket模塊4種異常
-
與一般I/O和通信問題有關的socket.error;
-
與查詢地址信息有關的socket.gaierror;
-
與其他地址錯誤有關的socket.herror;
-
與在一個socket上調用settimeout()后,處理超時有關的socket.timeout.