TCP的"Self-Connection"是一種比較少見的特殊現象,不少人可能從事網絡相關的工做若干年也沒有遇到過,甚至沒有據說過,不過Google一下仍是很容易得到相關信息的。服務器
要產生一條"Self-Connection"的鏈接須要具有如下條件:網絡
客戶端和服務器運行在同一個系統中(同一臺機器上),這是最基本的要求,沒有這一點就無從談起"Self-Connection";socket
服務器監聽的端口號在/proc/sys/net/ipv4/ip_local_port_range所指定的範圍內;
tcp
當客戶端嘗試鏈接的時候,服務器並無正常啓動;spa
客戶端在鏈接不成功的狀況下會不斷的重試,而且在此期間服務器一直都沒有開始正常的監聽流程;.net
好了,當全部上述條件都知足以後,你將會在系統中看到一條TCP鏈接,它的源(IP+PORT)和目的(IP+PORT)是徹底相同的兩組值,而且鏈接狀態爲ESTABLISHED,以下所示:code
tcp 0 0 127.0.0.1:36666 127.0.0.1:36666 ESTABLISHED 1489/a.out
產生這種狀況的緣由就是客戶端在鏈接服務器的時候,內核會從/proc/sys/net/ipv4/ip_local_port_range所指定的端口範圍內選擇一個合適的值做爲它的源端口號,因爲這時服務器並不存在,所以鏈接失敗,下一次重連時內核又會選擇一個新的源端口號,而因爲此時服務器仍然沒有正常啓動,所以他本來要監聽的端口號處於空閒狀態,就有機會被選爲客戶端的源端口號,當這種狀況發生時,協議棧會將它做爲"TCP同時打開"這種特殊狀況來處理,而沒有作特殊干預,因而,一條"Self-Connection"的鏈接就創建起來了。blog
更多關於TCP端口號選擇的內容能夠參見這篇文章。進程
這種狀況發生時,咱們能夠經過客戶端的socket描述符發送數據,而後再從這個socket中將數據接收回來,從而造成一個閉環。這是由於協議棧下層是依據IP+PORT來查找socket的,因而就又找到它啦。ip
而且當"Self-Connection"發生後,不管服務器是監聽在127.0.0.1仍是0.0.0.0,也不管服務器是否設置了SO_REUSEADDR,當它嘗試啓動時,都會得到「bind failed, errno: 98, Address already in use」的錯誤,這時只有將客戶端進程停掉,讓服務器先行啓動才能恢復正常。
大好春光,你在作什麼呢?:)