套接字半關閉與關閉


套接字半關閉與關閉 (可參考TCP/IP網絡編程)
套接字的半關閉狀態: 可以傳輸但不可接收或可接收但不可傳輸,即只關閉流的一半. shutdown()函數的三種斷開連接方式: SHUT_RD: 斷開輸入流 SHUT_WR: 斷開輸出流 SHUT_RDWR: 同時斷開I/O區別: 如果傳入SHUT_RD 那么無法接收數據,即使數據到緩沖區了也會抹去並無法調用相關讀取函數. 如果傳入SHUT_WR 那么無法輸出數據了, 但如果輸出緩沖中還有未傳輸的數據會首先傳輸完畢. [這是與SHUT_RD的區別]. close()才不管緩沖區還有沒有內容直接全抹掉. 打算關閉套接字連接時close()shutdown()都會向客戶端發送EOF符號表示傳輸結束. 而調用close()函數會同時關閉I/O流,並且再也無法接收對方的數據了. 使用shutdown()進行半關閉就比較優雅了, 我可以發送完EOF后等待客戶端發送的最后一次數據(SHUT_WD). 比如下面的服務端代碼: while (1) { read_cnt = fread((void*)buf, 1, BUF_SIZE,fp); if(read_cnt < BUF_SIZE) { break; //我輸出完畢之后推出循環 } } shutdown(client_fd,SHUT_WR); //告訴客戶端我不再發數據給你了 read(client_fd, buf, BUF_SIZE); //阻塞在這等客戶端最后一次發數據過來. printf("msg from client:%s\n", buf); //打印客戶端最后一次數據 fclose(fp); close(client_fd); //正式關閉客戶端套接字 close(server_fd); closesocketshutdown(使用SHUT_WR當作參數時),會向通信對方發出一個fin包, 而此時套接字的狀態會由ESTABLISHED變成FIN_WAIT_1,然后對方發送一個ACK包作為回應, 套接字又變成FIN_WAIT_2,如果對方也關閉了連接則對方會發出FIN我方會回應一個ACK並將套接字置為TIME_WAIT。因此可以看出closesocket,shutdown所進行的TCP行為是一樣的, 所不同的是函數部分,shutdown會確保windows建立的數據傳輸隊列中的數據不被丟失, 而closesocket會冒然的拋棄所有的數據,因此如果你願意closesocket完全可以取代shutdown, 然而在數據交互十分復雜的網絡協議程序中,最好還是shutdown穩妥一些! @1. (ESTABLISHED) -- shutdown -> 服務端(FIN_WAIT_1) --fin-> 客戶端 --ack-> 服務端(FIN_WAIT_2) @2. 客戶端 --fin--> 服務端 --ack--> 客戶端(TIME_WAIT); @3. 客戶端套接字處於TIME_WAIT 階段即處於等待回收狀態, windows默認4分鍾后自動回收, 既然是資源那有稀缺性, 比如nginx默認可操作1024個文件描述符(套接字), 如果這些TIME_WAIT待回收的或CLOSE_WAIT(調用close()產生待回收)的套接字占用太多而無法及時回收的話, 那么nginx剩下可用於建立ESTABLISHED的套接字資源就不足了, 那么就無法繼續接受請求, 於是報"Too Many Open Files異常"或卡主(nginx還必須維護這些TIME_WAIT套接字), 再比如mysql配置max-connections=2048, 一旦沒有可用的連接(套接字),mysql就會報too many connections, 因此及時的回收或重新利用這些TIME_WAIT 就顯得很關鍵了. HTTP協議1.1版規定default行為是Keep-Alive,也就是會重用TCP連接(套接字)傳輸多個 request/response,一個主要原因就是發現了這個問題. 即告訴套接字別發完一個就像等待被回收了, 繼續站崗循環使用吧. 繼續看下面的案例怎么通過修改內核配置盡快回收套接字. 
vim /etc/sysctl.conf

編輯文件,加入以下內容: net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 然后執行 /sbin/sysctl -p 讓參數生效。 net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉; net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將time-wait sockets重新用於新的TCP連接,默認為0,表示關閉; net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。 net.ipv4.tcp_fin_timeout    修改系統默認的 TIMEOUT 時間

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM