套接字埠復用 SO REUSEADDR

2021-08-20 21:19:22 字數 4034 閱讀 3094

下面建立的套接字都是tcp套接字

1.程序建立監聽套接字socket1,邦定乙個指定埠,並接受了若干連線。那麼程序建立另外乙個套介面socket2,並試圖邦定同乙個埠時候,bind錯誤返回「address already in use」(即使使用了so_reuseaddr).

2.程序建立監聽套接字,邦定乙個指定埠,並接受了若干連線,為每個連線建立子程序為連線服務。殺死監聽套接字所在程序,然後重新啟動。重新啟動的程序呼叫bind重新建立監聽套接字。這次邦定只有在bind前指定了so_reuseaddr時才能成功。(因為直接殺程序,沒有顯式關閉套接字來釋放埠,會等待一段時間後才可以重新use這個關口,解決辦法就是用so_reuseaddr)。

3.程序建立套接字socket1,邦定乙個指定埠,使用這個套接字去connect另外乙個監聽套接字。連線建立。然後程序建立乙個監聽套接字socket2,邦定同乙個埠。這次邦定只有在下面兩個條件都滿足的情況下才成功返回:為socket2邦定前指定so_reuseaddr,且為socket1邦定前也指定了so_reuseaddr。

4.程序建立套接字socket1,邦定乙個指定埠,去連線某個監聽套介面。殺死程序,保證socket1一端執行主動關閉。那麼重啟程序後,除非上乙個連線中socket1退出了time_wait狀態,否則重啟的程序在呼叫bind時候錯誤返回。

同乙個機器上乙個埠port1,tcp socket1 繫結port1,然後tcp socket2繫結port1會失敗;

同乙個機器上乙個埠port1,tcp socket1 繫結port1,然後udp socket2繫結port1會成功;

同乙個機器上乙個埠port1,udp socket1 繫結port1,然後udp socket2繫結port1會失敗;

同乙個機器上乙個埠port1,tcp socket1 繫結port1,然後tcp socket2繫結port1會成功的條件是:

兩個套接字繫結前都呼叫:

int opt = 1;  

// sockfd為需要埠復用的套接字  

setsockopt(sockfd, sol_socket, so_reuseaddr, (const voidvoid *)&opt, sizeof(opt));

但是假如socket1不僅bind了,還listen,並且accept成功了,這個時候socket2再次繫結到這個埠就會失敗!!但是假如socket2是udp的socket,那麼socket2的bind還是會成功的!!!

埠復用允許在乙個應用程式可以把 n 個套接字綁在乙個埠上而不出錯。同時,這 n 個套接字傳送資訊都正常,沒有問題。但是,這些套接字並不是所有都能讀取資訊,只有最後乙個套接字會正常接收資料。

埠復用最常用的用途應該是防止伺服器重啟時之前繫結的埠還未釋放或者程式突然退出而系統沒有釋放埠。這種情況下如果設定了埠復用,則新啟動的伺服器程序可以直接繫結埠。如果沒有設定埠復用,繫結會失敗,提示addr已經在使用中——那只好等等再重試了,麻煩!

復用真正是什麼意義呢?這個我們可以看看tcp/ip裡面tcp建立和斷開鏈結的方法。

我們知道,在tcp斷開鏈結的時候我們需要四次握手來斷開,而且當兩端都關閉了read/write通道以後我們還是要等待乙個time_wait時間。

這就是so_reuseaddr的作用所在.

其實這個選項就是告訴os如果乙個埠處於time_wait狀態, 那麼我們就不用等待直接進入使用模式, 不需要繼續等待這個時間結束.

那這樣我們肯定要問,那為什麼我們需要有這個time_wait時間啊?

看看tcp/ip協議組我們就知道,這樣做是為了讓在網路中殘餘的tcp包消失, 也就是說, 如果我們沒有等到這個時間就讓os把這個埠釋放給其他的程序使用,別的程序很有可能就會收到上乙個會話的殘餘tcp包,這樣就會出現一系列的不可預知的錯誤.

一、保證tcp協議的全雙工連線能夠可靠關閉

二、保證這次連線的重複資料段從網路中消失

那麼什麼時候我們可以用這個選項以加快我們程序的速度減小等待時間呢?

這裡有一些例子:

so_reuseaddr可以用在以下四種情況下。

(摘自《unix網路程式設計》卷一,即unpv1)

1、當有乙個有相同本地位址和埠的socket1處於time_wait狀態時,而你啟

動的程式的socket2要占用該位址和埠,你的程式就要用到該選項。

2、so_reuseaddr允許同一port上啟動同一伺服器的多個例項(多個程序)。但

每個例項繫結的ip位址是不能相同的。在有多塊網絡卡或用ip alias技術的機器可

以測試這種情況。

3、so_reuseaddr允許單個程序繫結相同的埠到多個socket上,但每個soc

ket繫結的ip位址不同。這和2很相似,區別請看unpv1。

4、so_reuseaddr允許完全相同的位址和埠的重複繫結。但這只用於udp的

多播,不用於tcp。

也就是說,不是所有的情況我們都可以使用這個選項的,請參閱這篇**的案例:

1、一般來說,乙個埠釋放後會等待兩分鐘之後才能再被使用,so_reuseaddr是讓埠釋放後立即就可以被再次使用。

so_reuseaddr用於對tcp套接字處於time_wait狀態下的socket,才可以重複繫結使用。server程式總是應該在呼叫bind()之前設定so_reuseaddr套接字選項。tcp,先呼叫close()的一方會進入time_wait狀態

2、so_reuseaddr和so_reuseport

so_reuseaddr提供如下四個功能:

so_reuseaddr允許啟動乙個監聽伺服器並**其眾所周知埠,即使以前建立的將此埠用做他們的本地埠的連線仍存在。這通常是重啟監聽伺服器時出現,若不設定此選項,則bind時將出錯。

so_reuseaddr允許在同一埠上啟動同一伺服器的多個例項,只要每個例項**乙個不同的本地ip位址即可。對於tcp,我們根本不可能啟動**相同ip位址和相同埠號的多個伺服器。

so_reuseaddr允許單個程序**同一埠到多個套介面上,只要每個**指定不同的本地ip位址即可。這一般不用於tcp伺服器。

so_reuseaddr允許完全重複的**:當乙個ip位址和埠繫結到某個套介面上時,還允許此ip位址和埠**到另乙個套介面上。一般來說,這個特性僅在支援多播的系統上才有,而且只對udp套介面而言(tcp不支援多播)。

so_reuseport選項有如下語義:

此選項允許完全重複**,但僅在想**相同ip位址和埠的套介面都指定了此套介面選項才行。

如果被**的ip位址是乙個多播位址,則so_reuseaddr和so_reuseport等效。

使用這兩個套介面選項的建議:

在所有tcp伺服器中,在呼叫bind之前設定so_reuseaddr套介面選項;

當編寫乙個同一時刻在同一主機上可執行多次的多播應用程式時,設定so_reuseaddr選項,並將本組的多播位址作為本地ip位址**。

if (setsockopt(fd, sol_socket, so_reuseaddr,

(const void *)&noptval , sizeof(int)) < 0) ...

q:編寫 tcp/sock_stream 服務程式時,so_reuseaddr到底什麼意思?

a:這個套接字選項通知核心,如果埠忙,但tcp狀態位於 time_wait ,可以重用埠。如果埠忙,而tcp狀態位於其他狀態,重用埠時依舊得到乙個錯誤資訊,指明"位址已經使用中"。如果你的服務程式停止後想立即重啟,而新套接字依舊使用同一埠,此時so_reuseaddr 選項非常有用。必須意識到,此時任何非期望資料到達,都可能導致服務程式反應混亂,不過這只是一種可能,事實上很不可能。

乙個套接字由相關五元組構成,協議、本地位址、本地埠、遠端位址、遠端埠。so_reuseaddr 僅僅表示可以重用本地本地位址、本地埠,整個相關五元組還是唯一確定的。所以,重啟後的服務程式有可能收到非期望資料。必須慎重使用so_reuseaddr 選項。

TCP套接字埠復用SO REUSEADDR

下面建立的套接字都是tcp套接字 1.程序建立監聽套接字socket1,邦定乙個指定埠,並接受了若干連線。那麼程序建立另外乙個套介面socket2,並試圖邦定同乙個埠時候,bind錯誤返回 address already in use 即使使用了so reuseaddr 2.程序建立監聽套接字,邦定...

套接字(socket) 埠

套接字 socket socket可以看成在兩個程式進行通訊連線中的乙個端點,乙個程式將一段資訊寫入socket中,該socket將這段資訊傳送給另外乙個socket中,使這段資訊能傳送到其他程式中。套接字,是支援tcp ip的網路通訊的基本操作單元,可以看做是不同主機之間的程序進行雙向通訊的端點,...

套接字 實現埠重用

假如埠被socket使用過,並且利用socket.close 來關閉連線,但此時埠還沒有釋放,要經過乙個time wait的過程之後才能使用,這是tnn的相當煩銀的,為了實現埠的馬上覆用,可以選擇setsockopt 函式來達到目的。以下是網上找到的一篇文章的一小段相關例子,試用之後,相當有效果,特...