1. 程式人生 > >udp中的connect()&bind()

udp中的connect()&bind()

connect()&bind()的作用

udp

udp connect()

 #include <sys/types.h>         
 #include <sys/socket.h>
 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

udp connect()描述

  1. connect系統呼叫將sockfd關聯的套接字連線到addr指定的地址,如果sockfd是SOCK_DGRAM型別的,那麼這個地址就是唯一資料報傳送和接收地址
  2. 有連結的協議一般只能成功connect()一次,而無連線的協議可以多次connect()來改變sockfd與addr的聯絡

返回值

  1. 0,返回成功
  2. EACCES ,EPERM 使用者試圖連結到一個廣播地址,但是相應的socket broadcast flag沒有設定,或者是因為有本地防火牆
  3. EADDRINUSE 地址已經被使用
  4. EAFNOSUPPORT 傳參的地址中的address family 與sa_family不匹配
  5. EBADF 檔案描述符sockfd非法
  6. EINTR connect被signal中斷

udp connect()特殊的一些地方

經試驗發現,若傳送端(客戶端)不呼叫connect(),則傳送非同步錯誤時,程序很難知道傳送了什麼。若是呼叫connect(),其實際作用也與tcp中有較大不同。

  1. 呼叫connect()不會發包,核心只是檢查是否有立即可知的錯誤,記錄對端的ip&port,於是立即返回。但是這樣一個socket就只能與一個ip進行互動(此處包括廣播ip)
  2. connect()後,非同步錯誤會被返回,在write()到一個不可達的程序時,對方將傳送icmp,我方udp收到這個報文,並在下次準備read()這個套接字時,返回connection refused
  3. 一般而言,無連線的udp在傳送資料時,核心中也是會做連結操作的,等資料傳送完畢然後斷開連線。這樣其實效率較低,若是傳送程序明確知道自己將於某個程序長時間通訊,可以呼叫connect()來提高效率。【Partridge和Pink 1993】指出,臨時連結的UDP套接字會耗費每個UDP傳輸1/3的開銷

廣播/多播(組播)

什麼是多播

組播通過把224.0.0.0-239.255.255.255的D類地址作為目的地址,有一臺源主機發出目的地址是以上範圍組播地址的報文,在網路中,如果有其他主機對於這個組的報文有興趣的,可以申請加入這個組,並可以接受這個組,而其他不是這個組的成員是無法接受到這個組的報文的。

區域網內多播時發生了什麼

若區域網中有一個接收程序啟動,並通過setsockopt()加入到某多播組。ipv4層內部會儲存以上資訊,並告知資料鏈路層接收特定目的地址乙太網幀(通過組播ip到乙太網地址的對映)。但是介面卡做的是不完備過濾,即介面卡也可能會接收目的地址為其他地址的乙太網幀。但是ip層是完備的,它會比較目的ip。

有了以上內容,我們就知道若是某個組播成員(假設是A機)程序關閉了接收,或者他根本就沒加入過組播。那麼當傳送程序再次發生組播時,A機實際上會忽略這個組播資料,既然忽略了,也不會發送icmp了。若是這個A機上有多個程序都加入了這個多播組,那單個套接字成員關係上的抹除,不影響A機繼續作為該多播組的成員,直到最後一個套接字也離開該多播組。這種情況下呼叫connect,應該是connect到一個組播地址。

如何加入到組播

int setsockopt(int sockfd,int level,int optname,void* optval,socklen_t optlen)

optname dataType function
IP_ADD_MEMBERSHIP struct ip_mreq enter a group
IP_ADD_SOURCE_MEMBERSHIP struct ip_mreq_source enter a SSM
IP_BLOCK_SOURCE struct ip_mreq_source block a source

以源特定組播為例

  1. 假設組播IP是GROUP

  2. 按慣例,建立socket,填充好port,sin_family.

  3. inet_aton(GROUP,&serv.sin_addr);
    inet_aton(GROUP,&mreq.imr_multiaddr);
    inet_aton(yourInterfaceIP,&(mreq.imr_interface));
    inet_aton(sourceIP,&(mreq.imr_sourceaddr));
    setsockopt(sockfd,SOL_IP,IP_ADD_SOURCE_MEMBERSHIP,&mreq,sizeof(mreq))
  4. 第一條語句的意思是接收程序的地址要設定成組播IP,第二至第四條語句的意思是要填充一個 struct ip_mreq_source結構。這個結構三個成員,分別是組播地址,本機一個介面的IP,以及多播發送方的IP

  5. setsockopt第三個引數指明這是加入源特定組播,第四個是上面說的結構體指標,第五個是它的長度

  6. 當optname是IP_ADD_MEMBERSHIP時,填充struct ip_mreq,這個結構體沒有imr_sourceaddr成員

connect到多播ip的一個事實

UNP1上說可以connect到一個多播ip,我在把cli傳送程序做了這樣的設定。但是令人奇怪的是,我的傳送程式再也收不到來自接收ser的任何資訊。後來仔細翻UNP,發現上面說“目的地為為這個已連線UDP套接字的本地協議地址,發源地卻不是該套接字早先connect到的協議地址的資料報,不會投遞到該套接字,這樣就限制了已連線套接字能且僅能與一個對端交換資料”。這個事實印證了這個說法。udp呼叫connect()需要付出這樣的代價。

bind()以及REUSE_ADDR、REUSE_PORT功能

見下,非常詳細

有待解決

此次試驗在一臺機子上進行,多播試驗,傳送端未做特殊設定,接收端設定IP_ADD_MEMBERSHIP。一開始觀察到傳送程序未bind()時,接收可以收到資料,但是卻顯示源地址是0.0.0.0。後傳送端加上bind(),接收端依舊顯示源地址是0.0.0.0。

後改變接收端設定,變為IP_ADD_SOURCE_MEMBERSHIP,並填上多播的源地址192.168.1.136。此時再測試,發現接收端依舊顯示源地址是0.0.0.0。後發現當第二次啟動傳送端程式傳送多播時,接收端顯示源地址是192.168.1.136。於是我修改傳送端程式,讓他不再recv 接收端的回覆,而是隻傳送資料。我發現第一次發生資料時,接收端總是不能得到傳送端的源地址,但是第二次傳送資料後,接收端就能知道源地址了。

TCP

三路握手

  1. tcp的穩定連線靠的是三路握手,而三路握手由connect(),accept()完成
  2. 伺服器必須準備好接受外來的連線,這通常通過呼叫socket,bind,listen來完成
  3. 客戶通過呼叫connect發起主動連線,這導致客戶傳送一個syn分節,它告訴伺服器客戶將傳送的資料的初始序列號。
  4. 伺服器則必須確認這個SYN,併發送ACK,同時自己也要傳送一個SYN,這個SYn含有伺服器傳送資料的初始序列號,當這個ACK/SYN到達客戶端時,connect()返回
  5. 客戶傳送對伺服器發來的SYN的ACK,伺服器收到這個ack後即從accept返回
  6. 三路握手完成

TCP連線終止

  1. TCP終止一個連結需要4個分節,因為終止是雙邊的,每一邊兩個分節,也就是說TCP可以存在半關閉狀態
  2. 某程序先呼叫close(),他是主動關閉方,它將傳送一個fin分節,這僅僅表示這個程序告訴對方他的資料已經發送完畢,不代表這個程序不能繼續收資料
  3. 若另外一邊也認為他的資料傳送完畢,則也會呼叫close()傳送fin分節
  4. 每個fin分節都需要被ACK

TIME_WAIT

  1. TIME_WAIT是主動執行關閉的那端的最後一個網路狀態。停留在這個狀態的時間是2MSL
  2. 這個狀態存在有兩個必要的理由,可靠的實現全雙工連線的終止,讓老的分組在網路中消逝
  3. 對於第一個理由,假設主動發起關閉的那端在收到被動關閉端來的fin後,傳送對這個fin的ACK,然而這個ACK丟失了。則被動關閉方會重傳一個FIN,這時,若是沒有TIME_WAIT狀態,主動關閉方在發完最後一個ACK後就不再維護狀態資訊,則此時被動關閉方重發的FIN到達,則主動關閉方將對這個FIN分節迴應一個RST,這將被被動關閉方解釋為一個錯誤。
  4. 對於第二個理由,若是一個連結終止後,但是網路上還有這個連結沒有到達的分組,此時若是快速的啟動一個新的連結,他的ip和port都和舊的一樣,那萬一這個舊的分組在此時到達,則會被新的連線誤收。所以為了讓舊的分組消逝,有必要等待一個較長的時間。

bind()

如果SO_REUSEADDR選項沒有被設定,處於TIME_WAIT階段的socket任然被認為是繫結在原來那個地址和埠上的。直到該socket被完全關閉之前(結束TIME_WAIT階段),任何其他企圖將一個新socket繫結該該地址埠對的操作都無法成功。這一等待的過程可能和延遲等待的時間一樣長。所以我們並不能馬上將一個新的socket繫結到一個剛剛被關閉的socket對應的地址埠對上。在大多數情況下這種操作都會失敗。

然而,如果我們在新的socket上設定了SO_REUSEADDR選項,如果此時有另一個socket繫結在當前的地址埠對且處於TIME_WAIT階段,那麼這個已存在的繫結關係將會被忽略。事實上處於TIME_WAIT階段的socket已經是半關閉的狀態,將一個新的socket繫結在這個地址埠對上不會有任何問題。這樣的話原來繫結在這個埠上的socket一般不會對新的socket產生影響。但需要注意的是,在某些時候,將一個新的socket繫結在一個處於TIME_WAIT階段但仍在工作的socket所對應的地址埠對會產生一些我們並不想要的,無法預料的負面影響。但這個問題超過了本文的討論範圍。而且幸運的是這些負面影響在實踐中很少見到。

相關推薦

UDP使用bindconnect的作用

1:UDP中可以使用connect系統呼叫2:UDP中connect操作與TCP中connect操作有著本質區別。TCP中呼叫connect會引起三次握手,client與server建立連結.UDP中呼叫connect核心僅僅把對端ip&port記錄下來.3:UDP中可以多次呼叫connect,TCP

udpconnect()&bind()

connect()&bind()的作用 udp udp connect() #include <sys/types.h> #include <sys/socket.h> int conne

UDPconnect函式

  1、UDP中可以使用connect系統呼叫。   2、UDP中connect操作與TCP中connect操作有著本質區別。‘   TCP中呼叫connect會引起三次握手,client與serv

UDPConnect

標準的udp客戶端開了套介面後,一般使用sendto和recvfrom函式來發資料,實際上,udp傳送資料有兩種方法供大家選用的: 方法一:  socket----->sendto()或recvfrom()  方法二:  socket----->connect(

【踩坑】angularJS 1.X版本 ng-bind 指令多空格展示

ext 數據庫查詢 sci 接收 可能 color 最終 數據 目的 做項目的時候遇到的問題 1、問題描述   用戶在表單某個值輸入多個空格,例如:A B,保存至服務器   在列表查詢頁面中使用bg-bind的指令單向綁定,結果展示位A B,連續的空格被替換

Jquerybind(),live(),delegate(),on()綁定事件方式 前言

文章 let com 多說 空格 code html event 進行 前言   因為項目中經常會有利用jquery操作dom元素的增刪操作,所以會涉及到dom元素的綁定事件方式,簡單的歸納一下bind,live,delegate,on的區別,以便以後查閱,也希望該文章日後

oracleconnect by語句的優化

oop sca cnblogs con edi 分享 for unique 定義 很多應用中都會有類似組織機構的表,組織機構的表又通常是典型的層次結構(沒有循環節點)。於是通過組織控制數據權限的時候,許多人都喜歡通過connect by獲得組織信息,然後再過濾目標數據。 在

JavaScriptbind方法及其常見應用

bind 支持 peer doc func 被調用 程序 引用 AC 一、bind()方法的實現   在JavaScript中,方法往往涉及到上下文,也就是this,因此往往不能直接引用。就拿最常見的console.log("info…")來說,避免書寫冗長的console

jquerybind()、live()的區別與使用(事件處理)

綁定 HA 我們 doc dso 目標 code span ive 原文:jquery中的bind()、live()的區別與使用(事件處理)使用jquery有一段時間了,剛開始看別人的源代碼的時候對事件的綁定方法有疑惑。比如: var btn=$("#button")

JSbind(),apply(),call()

語法 fun.bind(thisArg[, arg1[, arg2[, ...]]]) 引數 thisArg 當繫結函式被呼叫時,該引數會作為原函式執行時的 this 指向。當使用new 操作符呼叫繫結函式時,該引數無效。 arg1, arg2, … 當繫結函式被呼叫時,這些引

javascriptbind()

bind()方法在ECMAScript5中新定義的,這個方法會建立一個函式的例項,其this值會被繫結到傳給bind()函式的值,該函式可傳入兩個引數第一個引數作為this,第二個及以後的引數則作為函式的引數呼叫。具體作用如下: 1、建立繫結函式 就是當我們呼叫某些函式的時候是要在特定環境下

UDPconnect

規範 get icmp icm 約會 已連接udp套接字 自動 時間 記錄 UDP的connect沒有三次握手過程,內核只是檢測是否存在立即可知的錯誤(如一個顯然不可達的目的地), 記錄對端的的IP地址和端口號,然後立即返回調用進程。 未連接UDP套接字(unconne

深入理解jsbind

/** * bind 函式在js中的應用 */ this.name = "test"; let testObj = { name:'zhangsan', introduce:function(){ return this.name; } } let test = { name:"lisi

【網路程式設計】TCP網路程式設計connect()、listen()和accept()三者之間的關係

舉個簡單的例子(以下程式碼只是示範性的,用於說明不同套接字的作用,實際的函式會需要更多的引數): /* 建立用於監聽和接受客戶端連線請求的套接字 */ server_sock = socket(); /* 繫結監聽的IP地址和埠 */ bind(server_sock); /* 開始監聽 */ li

ES6(React)bind(this)詳解

初心-楊瑞超個人部落格誠邀您加入qq群(IT-程式猿-技術交流群):757345416 探討問題: 在使用React中 如果使用ES6的Class extends寫法 如果onClick繫結一個方法,需要bind(this),而使用React.createClass方法

querybind(),live(),delegate(),on()有什麼區別?

這裡是修真院前端小課堂,每篇分享文從 【背景介紹】【知識剖析】【常見問題】【解決方案】【編碼實戰】【擴充套件思考】【更多討論】【參考文獻】 八個方面深度解析前端知識/技能,本篇分享的是: 【query中的bind(),live(),delegate(),on()有什麼區別? 】

規避 React 元件bind(this)

React 元件中處理 onClick 類似事件繫結的時候,是需要顯式給處理器繫結上下文(context)的,這一度使程式碼變得冗餘和難看。 請看如下的示例: class App extends Component { constructor() { super(); this.stat

18-UDPconnect函式

1. 面向連線的UDP   在上一篇中遺留了一個問題:sendto函式產生的非同步錯誤一般是不會返回給udp套接字的(主要是因為udp是無連線的原因),如果這個錯誤要返回給udp套接字,那麼就需要呼叫connect函式。 是的,你沒看錯,udp也可以呼叫connect函式達

深入解析Vue.jsv-bind v-model的使用和區別

v-model 指令在表單控制元件元素上建立雙向資料繫結,所謂雙向繫結,指的就是我們在js中的vue例項中的data與其渲染的dom元素上的內容保持一致,兩者無論誰被改變,另一方也會相應的更新為相同的資料 最基礎的就是實現一個聯動的效果 <body> <

jsbind方法的實現方法

js中目前我遇見的改變作用域的5中方法:call, apply, eval, with, bind。 var obj = { color: 'green' } function demo (