今天在Segmentfault上有人提問了一個tcp自鏈接問題,這裏記錄下。所謂tcp自鏈接,就是出現源ip和源端口通目的ip和目的端口徹底相同的狀況,乍看起來難以想象,細細一想情理之中,本文重現下這種鏈接,而且說下解決思路。python
在linux主機下運行下面的python腳本,等待一會便可出現。linux
import socket import time connected=False while (not connected): try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1) sock.connect(('127.0.0.1',55555)) connected=True except socket.error,(value,message): print message if not connected: print "reconnect" print "tcp self connection occurs!" print "try to run follow command : " print "netstat -an|grep 55555" time.sleep(1800)
截圖以下:
nginx
tcp自鏈接出現了!編程
從上面的python腳本中,能夠看到它只是在不斷地嘗試鏈接55555這個端口,而且是沒有socket監聽這個端口,那麼爲什麼最後卻創建鏈接了呢?緣由在於客戶端在鏈接服務端時,若是沒有指定端口號,系統會隨機分配一個。隨機就意味着可能分配一個和目的端口同樣的數字,此時就會出現自鏈接狀況了。由於對於tcp協議來說,鏈接的流程是走的通,三次握手整個階段都合法,鏈接天然能夠創建。segmentfault
自鏈接的壞處顯而易見,當程序去connect一個不處於監聽的端口時,必然期待其鏈接失敗,若是自鏈接出現,就意味着該端口被佔用了,那麼:網絡
真正須要監聽該端口的服務會啓動失敗,拋出端口已被佔用的異常。socket
客戶端沒法正常完成數據通訊,由於這是個自鏈接,並非一個正常的服務。tcp
解決辦法也很簡單,只要保證客戶端隨機的端口不會和服務監聽的端口相同就能夠了。那麼咱們得先了解隨機的範圍,這個範圍對應linux的/etc/sysctl.conf
的net.ipv4.ip_local_port_range
參數,其默認值是32768 61000
。也就是說隨機端口會在這個範圍內出現,試驗中咱們選定了55555
這個端口,因此出現了自鏈接現象。此時只要限定服務監聽在32768
端口如下,就不會出現自鏈接現象了。固然,你能夠修改這個配置,只要注意保證監聽端口再也不配置範圍內就能夠避免自鏈接問題了。spa