標籤:

Linux下connect函數埠連到自己, 這種問題怎麼解決?

我在做項目的時候遇到一個問題
有兩個程序, 一個A作為客戶端, 一個B作為服務段. A主動連接B, B只監聽.
可是, 有時候B沒有運行, A也可以列印出信息"連接成功"

while( connect( socket, m_sin, sizeof( m_sin ) &< 0 );
在A根本沒有啟動的情況下, 這個循環會跳出.

然後在終端輸入lsof -i:33008 (33008是B程序負責監聽的埠)
會顯示 localhost:33008-&>localhost:33008 ( ESTABLISHED )
系統顯示這個埠連接到了自己, 為什麼會出現這種情況.

而且A程序裡面給33008發送信息後, 收到信息就是33008這個埠, 信息會發給A自己.

這種問題怎麼解決啊?


首先,要認命,目前在linux網路協議棧開發者眼中,TCP自連接行為不被認為是TCP協議實現的bug。。。。
為什麼會出現自連接?
當對一個TCP socket調用connect函數時,如果這個socket沒有bind指定的埠號,操作系統會為它選擇一個當前未被使用的埠號,這個埠號被稱為ephemeral port, 範圍可以在/proc/sys/net/ipv4/ip_local_port_range里查看。假設30000這個埠被選為ephemeral port,
當connect函數被調用時,tcp向目標地址發起三次握手過程,發送SYN分節到對端,由於源埠和目標埠相同都是30000,30000埠是被打開的,這樣30000埠能收到SYN分節,返回的是SYN+ACK,而不會返回RST,最後源地址再返回ACK,三次握手流程完畢,完成了一個TCP自連接。
如何避免自連接?
可以加上一段判斷保護代碼,對描述符分別調用getsockname和getpeername,然後檢查返回的地址結構是否相等,如果相等,說明是自連接,close描述符取消該連接。


先bind埠0,這樣系統會給你分配一個埠。
然後getsockname,如果bind上的地址和要connect的地址相同,說明要連接的埠根本沒有被監聽。


Linux給沒有bind過的socket自動分配一個埠號,默認是32768-61000。
你或者把監聽的埠號改到這個範圍以外,比如30008;或者改自動分配的範圍:

echo "40001 61000" &> /proc/sys/net/ipv4/ip_local_port_range

就不會出這個問題了。


推薦閱讀:

C++ 中的命名空間和類有什麼區別?
單元測試到底是什麼?應該怎麼做?
怎麼理解API和MFC的關係?
C++ 中為什麼要有. -> ::這幾種成員訪問操作符?
面試 C++ 程序員,什麼樣的問題是好問題?

TAG:Linux | C | TCPIP |