如果您不願意更改可用臨時端口的數量(如David所建議的那樣),或者您需要的連接數超過理論最大值,還有其他兩種方法可以減少正在使用的端口數。但是,它們在不同程度上違反了TCP標準,因此應謹慎使用它們。
第一個是打開SO_LINGER
零秒超時,迫使TCP
堆棧發送一個RST數據包並刷新連接狀態。然而,有一個微妙之處:你應該在套接字文件描述符上調用shutdown
,然後再發送close
,這樣就有機會在RST
數據包之前發送一個FIN
數據包。因此,代碼看起來類似:
shutdown(fd, SHUT_RDWR);
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 0;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_LINGER,
(char *) &linger, sizeof(linger));
close(fd);
服務器應該只看到一個過早的連接復位,如果FIN
包獲取與RST
包重新排序。
請參閱TCP option SO_LINGER (zero) - when it's required瞭解更多詳情。 (實驗上,它似乎並不無論你在哪裏設置setsockopt
)
二是使用SO_REUSEADDR
和明確bind
(即使你的客戶端),這將允許你的Linux你什麼時候使用這個臨時端口在他們完成等待之前跑步。請注意,您必須使用bind
與INADDR_ANY
和端口0
,否則SO_REUSEADDR
不受尊重。你的代碼看起來是這樣的:
int opts = 1;
// todo: test for error
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &opts, sizeof(int));
struct sockaddr_in listen_addr;
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = 0;
listen_addr.sin_addr.s_addr = INADDR_ANY;
// todo: test for error
bind(fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr));
// todo: test for addr
// saddr is the struct sockaddr_in you're connecting to
connect(fd, (struct sockaddr *) &saddr, sizeof(saddr));
此選項是不太好的,因爲你仍然飽和,內部內核數據結構按netstat -an | grep -e tcp -e udp | wc -l
TCP連接。但是,在這種情況發生之前,您不會開始重用端口。
我在一個大的Redis集羣中有類似的問題。你的用例是什麼? – Riccardo 2013-11-30 13:39:40