客戶端的socket是否需要bind?

luckyone906發表於2017-06-06




bind() 函式的定義與作用——

    將一本地地址與一套介面捆綁。本函式適用於未連線的資料包或流類套介面,在connect()listen()呼叫前使用。

    當用socket()建立套介面後,它便存在於一個名字空間(地址族)中,但並未賦名。bind()函式通過給一個未命名套介面分配一個本地名字來為套介面建立本地捆綁(主機地址/埠號)。

服務端——    

  服務端程式bind埠:基本是必須要做的事情,比如一個伺服器啟動時(比如freebsd),它會一個一個的捆綁眾所周知的埠來提供服務,同樣,如果bind了一個埠就表示我這個伺服器會在這個埠提供一些“特殊服務”
  服務端程式bind IP地址:目的是限制了服務端程式建立的socket只接受那些目的地為此IP地址的客戶連結;

   但是經常看見一些server端的程式碼是這麼寫的(沒有明確寫明bind 的IP):


1

servaddr.sin_addr.s_addr
= htonl(INADDR_ANY);


之後執行bind函式

1

bind(Sockfd,
(
struct

sockaddr *)servaddr,
sizeof(struct

servaddr));


這種設定是因為該server可能有多個網路卡(多個IP),但不確定client會從哪個網路卡連線進來。這麼設定可以使bind IP這個過程推遲,直到client端與server建立連線後,server才確定bind 哪個IP.


客戶端——


1

int

connect ( SOCKET s,
const

struct

sockaddr * name,
int

namelen );


     TCP socket客戶端通過呼叫Connect函式來連線server端,Connect()函式的第二個引數就是server端的地址資訊,因為這種情況下只需知道server端 的地址,而客戶通過哪個埠與伺服器建立連線並不重要,socket執行體為你的程式自動選擇一個未被佔用的埠,並通知你的程式資料什麼時候開啟埠,因此無須呼叫bind()。(當然也有特殊情況,linux系統中rlogin命令應當呼叫bind函式繫結一個未用的保留埠號,還有當客戶端需要用指定的網路裝置介面和埠號進行通訊等等)

1

int

sendto ( socket s ,
const

void

* msg,
int

len, unsigned
int

flags,
const

struct

sockaddr * to ,
int

tolen ) ;


    UDP socket客戶端呼叫sendto()函式同樣也只需要填寫server端的地址資訊(倒數第二個引數),系統依然是自動分配了埠給該socket。


客戶端bind了地址可能帶來的問題:

 如果在client端的程式裡,bind()了某個埠(比如 3456)。首先,得考慮這個埠是否被其他的程式佔用了(增加了實現的難度和麻煩)。第二,如果client端是hard code了bind這麼一個埠(3456),那麼在這臺電腦上,就只能執行一個客戶端,因為同一個埠只能給一個socket使用。 


總結:

  bind地址的意義在於,可以提前確定埠號——比如:用於瀏覽網頁服務的80埠,用於FTP服務的21埠等。server有這個需求,但是client基本沒這個需求。


其他:

  使用bind函式時,通過將my_addr.sin_port置為0,函式會自動為你選擇一個未佔用的埠來使用。
  Bind()函式在成功被呼叫時返回0;出現錯誤時返回"-1"並將errno置為相應的錯誤號。

  需要注意的是,在呼叫bind函式時一般不要將埠號置為小於1024的值,因為1到1024是保留埠號,你可以選擇大於1024中的任何一個沒有被佔用的埠號。

相關文章