【udp】UDP是一個(gè)無連接的協(xié)議际长,connect的意義何在?

UDP也可以是“已連接”兴泥?

根據(jù)接觸到了 UDP 數(shù)據(jù)報(bào)協(xié)議相關(guān)的知識(shí)工育,在我們的腦海里,已經(jīng)深深印上了“UDP 等于無連接協(xié)議”的特性搓彻。

在沒有開啟服務(wù)端的情況下如绸,我們運(yùn)行一下這個(gè)程序:

image.png
image.png

看到這里你會(huì)不會(huì)覺得很奇怪:
不是說好 UDP 是“無連接”的協(xié)議嗎?
不是說好 UDP 客戶端只會(huì)阻塞在 recvfrom 這樣的調(diào)用上嗎旭贬?
怎么這里冒出一個(gè)“Connection refused”的錯(cuò)誤呢怔接?

從前面的例子中,你會(huì)發(fā)現(xiàn)骑篙,我們可以對(duì) UDP 套接字調(diào)用 connect 函數(shù)蜕提,但是和 TCP connect 調(diào)用引起 TCP 三次握手森书,建立 TCP 有效連接不同靶端,UDP connect 函數(shù)的調(diào)用,并不會(huì)引起和服務(wù)器目標(biāo)端的網(wǎng)絡(luò)交互凛膏,也就是說杨名,并不會(huì)觸發(fā)所謂的”握手“報(bào)文發(fā)送和應(yīng)答。

image.png
image.png

那么對(duì) UDP 套接字進(jìn)行 connect 操作到底有什么意義呢猖毫?

其實(shí)上面的例子已經(jīng)給出了答案台谍,這主要是為了讓應(yīng)用程序能夠接收”異步錯(cuò)誤“的信息。

如果我們回想一下吁断,不調(diào)用 connect 操作的客戶端程序趁蕊,在服務(wù)器端不開啟的情況下,客戶端程序是不會(huì)報(bào)錯(cuò)的仔役,程序只會(huì)阻塞在 recvfrom 上掷伙,等待返回(或者超時(shí))。

在這里又兵,我們通過對(duì) UDP 套接字進(jìn)行 connect 操作任柜,將 UDP 套接字建立了”上下文“卒废,該套接字和服務(wù)器端的地址和端口產(chǎn)生了聯(lián)系,正是這種綁定關(guān)系給了操作系統(tǒng)內(nèi)核必要的信息宙地,能夠?qū)⒉僮飨到y(tǒng)內(nèi)核收到的信息和對(duì)應(yīng)的套接字進(jìn)行關(guān)聯(lián)摔认。

我們可以展開討論一下。

事實(shí)上宅粥,當(dāng)我們調(diào)用 sendto 或者 send 操作函數(shù)時(shí)参袱,應(yīng)用程序報(bào)文被發(fā)送,我們的應(yīng)用程序返回秽梅,操作系統(tǒng)內(nèi)核接管了該報(bào)文蓖柔,之后操作系統(tǒng)開始嘗試往對(duì)應(yīng)的地址和端口發(fā)送,因?yàn)閷?duì)應(yīng)的地址和端口不可達(dá)风纠,一個(gè) ICMP 報(bào)文會(huì)返回給操作系統(tǒng)內(nèi)核况鸣,該 ICMP 報(bào)文含有目的地址和端口等信息。

如果我們不進(jìn)行 connect 操作竹观,建立(UDP 套接字——目的地址 + 端口)之間的映射關(guān)系镐捧,操作系統(tǒng)內(nèi)核就沒有辦法把 ICMP 不可達(dá)的信息和 UDP 套接字進(jìn)行關(guān)聯(lián),也就沒有辦法將 ICMP 信息通知給應(yīng)用程序臭增。

這就涉及到了網(wǎng)絡(luò)協(xié)議設(shè)計(jì)中的數(shù)據(jù)平面和控制平面了懂酱,對(duì)于控制平面的消息,可以是帶內(nèi)傳輸誊抛,也可以是帶外傳輸列牺。
實(shí)際上,ICMP拗窃,根據(jù)名稱就可以看出它是一種專門的控制協(xié)議瞎领,控制和指示IP層發(fā)生的事件。
ECONNREFUSED正是ICMP返回的随夸,然而并不是所有的UDP socket都可以享用ICMP帶來的錯(cuò)誤提示九默,畢竟帶外控制消息和協(xié)議本身的關(guān)聯(lián)太松散了。
UDP socket必須顯式的connect對(duì)端才可以宾毒。

如果我們進(jìn)行了 connect 操作驼修,幫助操作系統(tǒng)內(nèi)核從容建立了(UDP 套接字——目的地址 + 端口)之間的映射關(guān)系,該映射的作用正是為了和UDP帶外的ICMP控制通道捆綁在一起诈铛,使得UDP socket的接口含義更加豐滿乙各。

當(dāng)收到一個(gè) ICMP 不可達(dá)報(bào)文時(shí),操作系統(tǒng)內(nèi)核可以從映射表中找出是哪個(gè) UDP 套接字擁有該目的地址和端口幢竹,別忘了套接字在操作系統(tǒng)內(nèi)部是全局唯一的耳峦,當(dāng)我們?cè)谠撎捉幼稚显俅握{(diào)用 recvfrom 或 recv 方法時(shí),就可以收到操作系統(tǒng)內(nèi)核返回的”Connection Refused“的信息妨退。

一般來說妇萄,服務(wù)器端不會(huì)主動(dòng)發(fā)起 connect 操作蜕企,因?yàn)橐坏┤绱耍?wù)器端就只能響應(yīng)一個(gè)客戶端了冠句。
當(dāng)然轻掩,有時(shí)候也不排除這樣的情形,一旦一個(gè)客戶端和服務(wù)器端發(fā)送 UDP 報(bào)文之后懦底,該服務(wù)器端就要服務(wù)于這個(gè)唯一的客戶端唇牧。

一般來說,客戶端通過 connect 綁定服務(wù)端的地址和端口聚唐,對(duì) UDP 而言丐重,可以有一定程度的性能提升。
這是為什么呢杆查?

因?yàn)槿绻皇褂?connect 方式扮惦,每次發(fā)送報(bào)文都會(huì)需要這樣的過程:
連接套接字→發(fā)送報(bào)文→斷開套接字→連接套接字→發(fā)送報(bào)文→斷開套接字 →………

而如果使用 connect 方式,就會(huì)變成下面這樣:
連接套接字→發(fā)送報(bào)文→發(fā)送報(bào)文→……→最后斷開套接字

我們知道亲桦,連接套接字是需要一定開銷的崖蜜,比如需要查找路由表信息。
所以客峭,UDP 客戶端程序通過 connect 可以獲得一定的性能提升豫领。

我對(duì) UDP 套接字調(diào)用 connect 方法進(jìn)行了深入的分析。
之所以對(duì) UDP 使用 connect舔琅,綁定本地地址和端口等恐,是為了讓我們的程序可以快速獲取異步錯(cuò)誤信息的通知,同時(shí)也可以獲得一定性能上的提升备蚓。

不進(jìn)行connect操作课蔬,UDP套接字與服務(wù)端的地址和端口就沒有產(chǎn)生關(guān)系,那recvfrom是怎么收到對(duì)應(yīng)的報(bào)文呢星著?
UDP的connect操作购笆,會(huì)引發(fā)內(nèi)核的ICMP報(bào)文發(fā)送?如果不是虚循,ICMP是在什么時(shí)機(jī)下發(fā)送的?

1.是通過sendto函數(shù)來綁定服務(wù)端地址的样傍,之后再通過recvfrom引用到之前的socket横缔,這樣收到的報(bào)文就是指定的服務(wù)地址和端口了;
2.不是connect導(dǎo)致ICMP報(bào)文衫哥,而是對(duì)應(yīng)的地址和端口不可達(dá)時(shí)茎刚,一個(gè) ICMP 報(bào)文會(huì)返回。connect只是將這個(gè)信息傳遞變得可能了撤逢。

為什么UDP的sendto方法會(huì)有一個(gè)"連接"過程的性能損耗膛锭,直接按照目標(biāo)地址發(fā)過去不就可以了嗎粮坞?
操作系統(tǒng)會(huì)先用ICMP協(xié)議探一探目標(biāo)地址是否存在,然后再用UDP協(xié)議發(fā)送具體的數(shù)據(jù)初狰,不知道理解的對(duì)不莫杈?

我不覺得會(huì)發(fā)ICMP來探一探。ICMP是用的時(shí)候才觸發(fā)的奢入。
這里我想表達(dá)的是操作系統(tǒng)協(xié)議棧在每次sendto的時(shí)候都會(huì)需要一個(gè)地址初始化的過程筝闹,如果這個(gè)過程省略掉了,是可以得到一點(diǎn)點(diǎn)性能的提升的腥光。當(dāng)然关顷,其實(shí)這個(gè)是沒有那么大的。

udp 連接套接字 這個(gè)是什么過程武福? 斷開套接字這又是什么過程呢议双?

沒有斷開,這里都是一個(gè)系統(tǒng)調(diào)用捉片,告訴了一些系統(tǒng)內(nèi)核信息而已聋伦。

通常在服務(wù)器端不開啟的情況下,UDP客戶端程序是不會(huì)報(bào)錯(cuò)的界睁,程序只會(huì)阻塞在 recvfrom 上觉增,等待返回(或者超時(shí))。
UDP的connect并不是真正的conncect操作翻斟,它只是給UDP 套接字建立了“上下文”逾礁。

在客戶端的代碼中,在send之前進(jìn)行了connect访惜。為什么send函數(shù)返回是成功嘹履,而recv就返回失敗呢?send的時(shí)候不應(yīng)該也能知道icmp報(bào)文返回錯(cuò)誤而返回錯(cuò)誤么债热?

從函數(shù)設(shè)計(jì)的角度來說砾嫉,在UDP通信中, sendto的目的是將報(bào)文通過網(wǎng)絡(luò)傳送給對(duì)端,并不考慮是否能發(fā)送成功窒篱,僅僅考慮的是把報(bào)文通過緩沖區(qū)發(fā)送出去焕刮;
而recvfrom則是一個(gè)阻塞調(diào)用,它是需要知道是否成功的墙杯,包括超時(shí)配并,包括ICMP報(bào)文返回錯(cuò)誤。

不調(diào)用connect時(shí)高镐, 難道recvfrom不是收到后再填充from的地址的嗎溉旋,還可以指定從某個(gè)服務(wù)端收數(shù)據(jù)?

這是對(duì)UDP而言的嫉髓,通過sendto函數(shù)客戶端指定了發(fā)送的服務(wù)端地址观腊,再通過recvfrom就可以從之前指定的服務(wù)端地址來接收數(shù)據(jù)了邑闲。
這里,沒有說可以任意從某個(gè)服務(wù)端收數(shù)據(jù)的梧油,而是從之前指定的服務(wù)端收數(shù)據(jù)的苫耸。

UDP 連接和斷開套接字的過程是怎樣的?

UDP 連接套接字不是發(fā)起連接請(qǐng)求的過程婶溯,而是記錄目的地址和端口到套接字的映射關(guān)系鲸阔。
斷開套接字則相反,將刪除原來記錄的映射關(guān)系迄委。

在 UDP 中不進(jìn)行 connect褐筛,為什么客戶端會(huì)收到信息?
有人說叙身,如果按照我在文章中的說法渔扎,UDP 只有 connect 才建立 socket 和 IP 地址的映射,那么如果不進(jìn)行 connect信轿,收到信息后內(nèi)核又如何把數(shù)據(jù)交給對(duì)應(yīng)的 socket晃痴?

這個(gè)問題非常有意思。我剛剛看到這個(gè)問題的時(shí)候财忽,心里也在想倘核,是啊,我是不是說錯(cuò)了即彪?

其實(shí)呢紧唱,這對(duì)應(yīng)了兩個(gè)不同的 API 場(chǎng)景:

第一個(gè)場(chǎng)景就是我這里討論的 connect 場(chǎng)景,在這個(gè)場(chǎng)景里隶校,我們討論的是 ICMP 報(bào)文和 socket 之間的定位漏益。
我們知道,ICMP 報(bào)文發(fā)送的是一個(gè)不可達(dá)的信息深胳,不可達(dá)的信息是通過目的地址和端口來區(qū)分的绰疤,如果沒有 connect 操作,目的地址和端口就沒有辦法和 socket 套接字進(jìn)行對(duì)應(yīng)舞终,所以轻庆,即使收到了 ICMP 報(bào)文,內(nèi)核也沒有辦法通知到對(duì)應(yīng)的應(yīng)用程序权埠,告訴它連接地址不可達(dá)榨了。

image.png

那么為什么在不 connect 的情況下,我們的客戶端又可以收到服務(wù)器回顯的信息了攘蔽?

這就涉及到了第二個(gè)場(chǎng)景,也就是報(bào)文發(fā)送的場(chǎng)景呐粘。
注意服務(wù)器端程序满俗,先通過 recvfrom 函數(shù)調(diào)用獲取了客戶端的地址和端口信息转捕,這當(dāng)然是可以的,因?yàn)?UDP 報(bào)文里面包含了這部分信息唆垃。
然后我們看到服務(wù)器端又通過調(diào)用 sendto 函數(shù)五芝,把客戶端的地址和端口信息告訴了內(nèi)核協(xié)議棧,可以肯定的是辕万,之后發(fā)送的 UDP 報(bào)文就帶上了客戶端的地址和端口信息枢步,通過客戶端的地址和端口信息,可以找到對(duì)應(yīng)的套接字和應(yīng)用程序渐尿,完成數(shù)據(jù)的收發(fā)醉途。

參考

UDP編程有必要調(diào)用connect嗎?
https://zhuanlan.zhihu.com/p/380109394

UDP socket也可以使用connect系統(tǒng)調(diào)用
https://www.cnblogs.com/jingzhishen/p/5545787.html

關(guān) udp socket 連接問題分析
http://www.reibang.com/p/6ab38d2eefc2

UDP也可以是“已連接”砖茸?
https://time.geekbang.org/column/article/129807

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隘擎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子凉夯,更是在濱河造成了極大的恐慌货葬,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劲够,死亡現(xiàn)場(chǎng)離奇詭異震桶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)征绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門蹲姐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人炒瘸,你說我怎么就攤上這事淤堵。” “怎么了顷扩?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵拐邪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我隘截,道長(zhǎng)扎阶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任婶芭,我火速辦了婚禮东臀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘犀农。我一直安慰自己惰赋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赁濒,像睡著了一般轨奄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拒炎,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天挪拟,我揣著相機(jī)與錄音,去河邊找鬼击你。 笑死玉组,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丁侄。 我是一名探鬼主播惯雳,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼绒障!你這毒婦竟也來了吨凑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤户辱,失蹤者是張志新(化名)和其女友劉穎鸵钝,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庐镐,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恩商,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了必逆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怠堪。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖名眉,靈堂內(nèi)的尸體忽然破棺而出粟矿,到底是詐尸還是另有隱情,我是刑警寧澤损拢,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布陌粹,位于F島的核電站,受9級(jí)特大地震影響福压,放射性物質(zhì)發(fā)生泄漏掏秩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一荆姆、第九天 我趴在偏房一處隱蔽的房頂上張望蒙幻。 院中可真熱鬧,春花似錦胆筒、人聲如沸邮破。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽决乎。三九已至队询,卻和暖如春派桩,著一層夾襖步出監(jiān)牢的瞬間构诚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工铆惑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留范嘱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓员魏,卻偏偏與公主長(zhǎng)得像丑蛤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撕阎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 從一個(gè)例子開始 我們先從一個(gè)客戶端例子開始受裹,在這個(gè)例子中,客戶端在 UDP 套接字上調(diào)用 connect 函數(shù)虏束,之...
    taj3991閱讀 70評(píng)論 0 0
  • 在前面的基礎(chǔ)篇中镇匀,我們已經(jīng)接觸到了 UDP 數(shù)據(jù)報(bào)協(xié)議相關(guān)的知識(shí)照藻,在我們的腦海里,已經(jīng)深深印上了“UDP 等于無連...
    日落_3d9f閱讀 376評(píng)論 0 1
  • 一汗侵、 udp問題抓包分析 公司內(nèi)部的一個(gè) 中間件報(bào) UDP 連接異常的日志幸缕,問題很明顯,對(duì)端的服務(wù)掛了晰韵,自然重啟下...
    Bogon閱讀 4,053評(píng)論 0 1
  • 1发乔、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量2)雪猪、lso...
    北辰青閱讀 9,410評(píng)論 0 11
  • Python提供了兩個(gè)基本的scoket模塊分別是:1.Socket : 它提供了標(biāo)準(zhǔn)的 BSD Sockets ...
    月亮是我踢彎得閱讀 4,753評(píng)論 0 1