chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>電子百科>通信技術(shù)>數(shù)據(jù)通信>

基于TCP流協(xié)議的數(shù)據(jù)包通訊 - 全文

2017年11月27日 14:29 網(wǎng)絡(luò)整理 作者: 用戶評(píng)論(0

  一、TCP定義

  TCP(Transmission Control Protocol 傳輸控制協(xié)議)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,由IETF的RFC 793定義。在簡(jiǎn)化的計(jì)算機(jī)網(wǎng)絡(luò)OSI模型中,它完成第四層傳輸層所指定的功能,用戶數(shù)據(jù)報(bào)協(xié)議(UDP)是同一層另一個(gè)重要的傳輸協(xié)議。在因特網(wǎng)協(xié)議族(Internet protocol suite)中,TCP層是位于IP層之上,應(yīng)用層之下的中間層。不同主機(jī)的應(yīng)用層之間經(jīng)常需要可靠的、像管道一樣的連接,但是IP層不提供這樣的流機(jī)制,而是提供不可靠的包交換。

基于TCP流協(xié)議的數(shù)據(jù)包通訊

  二、TCP可靠性實(shí)現(xiàn)

  TCP提供一種面向連接的、可靠的字節(jié)流服務(wù)。面向連接意味著兩個(gè)使用TCP的應(yīng)用(通常是一個(gè)客戶和一個(gè)服務(wù)器)在彼此交換數(shù)據(jù)包之前必須先建立一個(gè)TCP連接。這一過(guò)程與打電話很相似,先撥號(hào)振鈴,等待對(duì)方摘機(jī)說(shuō)“喂”,然后才說(shuō)明是誰(shuí)。在一個(gè)TCP連接中,僅有兩方進(jìn)行彼此通信。廣播和多播不能用于TCP。

  1.應(yīng)用數(shù)據(jù)被分割成TCP認(rèn)為最適合發(fā)送的數(shù)據(jù)塊。這和UDP完全不同,應(yīng)用程序產(chǎn)生的數(shù)據(jù)報(bào)長(zhǎng)度將保持不變。由TCP傳遞給I P的信息單位稱為報(bào)文段或段

  2.當(dāng)TCP發(fā)出一個(gè)段后,它啟動(dòng)一個(gè)定時(shí)器,等待目的端確認(rèn)收到這個(gè)報(bào)文段。如果不能及時(shí)收到一個(gè)確認(rèn),將重發(fā)這個(gè)報(bào)文段。

  3.當(dāng)TCP收到發(fā)自TCP連接另一端的數(shù)據(jù),它將發(fā)送一個(gè)確認(rèn)。這個(gè)確認(rèn)不是立即發(fā)送,通常將推遲幾分之一秒。

  4.TCP將保持它首部和數(shù)據(jù)的檢驗(yàn)和。這是一個(gè)端到端的檢驗(yàn)和,目的是檢測(cè)數(shù)據(jù)在傳輸過(guò)程中的任何變化。如果收到段的檢驗(yàn)和有差錯(cuò),TCP將丟棄這個(gè)報(bào)文段和不確認(rèn)收到此報(bào)文段(希望發(fā)端超時(shí)并重發(fā))。

  5.既然TCP報(bào)文段作為IP數(shù)據(jù)報(bào)來(lái)傳輸,而IP數(shù)據(jù)報(bào)的到達(dá)可能會(huì)失序,因此TCP報(bào)文段的到達(dá)也可能會(huì)失序。如果必要,TCP將對(duì)收到的數(shù)據(jù)進(jìn)行重新排序,將收到的數(shù)據(jù)以正確的順序交給應(yīng)用層。

  6.既然I P數(shù)據(jù)報(bào)會(huì)發(fā)生重復(fù),TCP的接收端必須丟棄重復(fù)的數(shù)據(jù)。

  7.TCP還能提供流量控制。TCP連接的每一方都有固定大小的緩沖空間。TCP的接收端只允許另一端發(fā)送接收端緩沖區(qū)所能接納的數(shù)據(jù)。這將防止較快主機(jī)致使較慢主機(jī)的緩沖區(qū)溢出。

  三、TCP連接的建立

  利用TCP傳輸數(shù)據(jù)前,需要建立tcp連接,tcp連接的建立有3個(gè)主要過(guò)程,叫做3次握手,具體過(guò)程如下圖所示:

基于TCP流協(xié)議的數(shù)據(jù)包通訊

  過(guò)程:

  1. 首先客戶端發(fā)送一個(gè)SYN包給服務(wù)器(SYN=1,Seq為主機(jī)選擇的這個(gè)連接的初始序號(hào)),然后等待應(yīng)答。

  2. 服務(wù)器端收到SYN包,回應(yīng)給客戶端一個(gè)ACK =x+1、SYN=1的TCP數(shù)據(jù)段(ACK表示確認(rèn)序號(hào)有效,即收到上一個(gè)包,這里加1并不是ACK的值加1,ACK是一個(gè)標(biāo)志位,這里會(huì)變成1,而x+1則是希望收到的下一個(gè)包的序列號(hào),這個(gè)值放在包的確認(rèn)序列號(hào)字段中,而只有ACK=1時(shí),確認(rèn)序列號(hào)才有效)。

  3. 客戶必須再次回應(yīng)服務(wù)器端一個(gè)ACK確認(rèn)數(shù)據(jù)段(這里的Seq為x+1)。

  經(jīng)過(guò)上面3個(gè)過(guò)程就建立了一個(gè)tcp連接,接著就可以發(fā)送數(shù)據(jù)了,因?yàn)榻⑦B接使用了一個(gè)序列號(hào)x,所以發(fā)送數(shù)據(jù)的第一個(gè)字節(jié)序號(hào)為x+1。

  注意:這里tcp為應(yīng)用層提供全雙工服務(wù),意味數(shù)據(jù)能在兩個(gè)方向上獨(dú)立地進(jìn)行傳輸,因此連接的每一段都有各自的傳輸數(shù)據(jù)序號(hào)(對(duì)應(yīng)于上圖中的x和y,這兩個(gè)值是沒有必然聯(lián)系的)。

  四、TCP協(xié)議流的理解

  TCP是流協(xié)議,不像UDP那樣sendto發(fā)一次消息,另一端必然會(huì)收到完整消息,或者沒有收到任何消息。當(dāng)用TCP send發(fā)一次消息的時(shí)候,可能另一端在某時(shí)刻可能只收到一部分消息,下一時(shí)刻才能收到另一部分。那如果一個(gè)消息很小,是否可以保證另一端在某時(shí)刻能收到這條完整消息?

  調(diào)用send后,TCP將數(shù)據(jù)拷貝到緩沖區(qū)。緩沖區(qū)內(nèi)可能不止一條用戶消息。TCP按照一定算法,將緩沖區(qū)的數(shù)據(jù)打包到1-n個(gè)TCP報(bào)文中,交給IP層發(fā)送。TCP報(bào)文是TCP協(xié)議的最小發(fā)送單位,大小應(yīng)該是可變的,并且丟失的話會(huì)重發(fā)。并不能保證一個(gè)TCP報(bào)文中必然包含一條用戶消息的全部,所以即使消息很小,另一端也有可能在某時(shí)刻只收到部分

  IP層將TCP報(bào)文裝進(jìn)IP包,然后再交給鏈路層發(fā)送以太幀

  理論上IP包的大小應(yīng)該會(huì)選擇比MTU小。一旦IP包比MTU大,意味著網(wǎng)絡(luò)上的路由要幫你緩存多個(gè)以太幀,拼出IP包后才知道如何路由到下一個(gè)節(jié)點(diǎn)。向下一節(jié)點(diǎn)路由的時(shí)候還要再拆分成多個(gè)以太幀發(fā)送。所以TCP報(bào)文應(yīng)該會(huì)比選擇比MTU小。

基于TCP流協(xié)議的數(shù)據(jù)包通訊

  五、基于TCP流協(xié)議的數(shù)據(jù)包通訊

  TCP通訊是流協(xié)議,它不像UDP那樣基于包為邊界的通訊方式,TCP流式協(xié)議,舉個(gè)簡(jiǎn)單例子,一端用send 分別發(fā)送 100,123,120字節(jié)的數(shù)據(jù),另一端用recv可以一下子接收到 100+123+120=343字節(jié)的數(shù)據(jù),或者先接收 3個(gè)字節(jié)的數(shù)據(jù),再接收余下的340字節(jié),不管另一端怎么接收,最終是要接收到343字節(jié)的數(shù)據(jù)。而且TCP保證數(shù)據(jù)的完整性和順序,也就是兩端是數(shù)據(jù)同步的,出現(xiàn)任何一點(diǎn)的數(shù)據(jù)不一致,都會(huì)造成TCP連接的失效。

  UDP則跟TCP大不一樣,他是基于包邊界的。所謂的包邊界,就是一端分別發(fā)送 100, 123, 120字節(jié)的數(shù)據(jù),另一端接收到也應(yīng)該分別是 100,123,120字節(jié)數(shù)據(jù)的三個(gè)包,不會(huì)出現(xiàn)一端發(fā)送100字節(jié)的一個(gè)數(shù)據(jù)包,另一端只接收到小于100字節(jié)的數(shù)據(jù)包,或者收到大于100字節(jié)的數(shù)據(jù)包。UDP同時(shí)也不保證穩(wěn)定和順序,如發(fā)送端發(fā)送100,123,120三個(gè)包,接收端可能接收到3個(gè)包,也可能只接收到2個(gè)包,也可能一個(gè)包也收不到,收到的順序不一定是100,123,120,可能是100,120,123,或者123,100,120等。這些TCP和UDP的屬性,大家稍微查查資料就該很清楚。

  UDP的這種特殊通訊方式其實(shí)跟網(wǎng)絡(luò)底層鏈路層的通訊方式很接近。鏈路層的數(shù)據(jù)是一個(gè)數(shù)據(jù)包一個(gè)數(shù)據(jù)包的傳輸,并不保證數(shù)據(jù)能否達(dá)到對(duì)方,或者按照順序到達(dá)對(duì)方。UDP只是簡(jiǎn)單把鏈路層和IP層的數(shù)據(jù)加了一層封裝,加了端口用于識(shí)別同一個(gè)機(jī)器的不同進(jìn)程,UDP數(shù)據(jù)包的收發(fā)方式,只是組合成UDP包之后,簡(jiǎn)單的發(fā)送到底層網(wǎng)絡(luò)了事,至于底層網(wǎng)卡有沒有發(fā)成功或者接收成功,它是一概不聞不問(wèn)的。他的底層處理方式比起 TCP協(xié)議來(lái)說(shuō)簡(jiǎn)單太多了。

  既然UDP這么好,編程又簡(jiǎn)單,可現(xiàn)在網(wǎng)絡(luò)中大部分都在使用TCP,一個(gè)非常重要的原因就是TCP提供的是可靠傳輸,TCP有一套復(fù)雜的底層算法來(lái)保證數(shù)據(jù)的完整和可靠,有這個(gè)理由就已經(jīng)足夠讓TCP在大部分場(chǎng)所比UDP好使了。因?yàn)榇蟛糠謺r(shí)候,我們?cè)陂_發(fā)網(wǎng)絡(luò)通信程序,都希望能隨意的接收和發(fā)送任意大小和完整的數(shù)據(jù),如果使用UDP,還得自己寫算法來(lái)保證數(shù)據(jù)的順序和完整,整個(gè)處理過(guò)程就等于實(shí)現(xiàn)一個(gè)小型的TCP協(xié)議。

  一些特殊場(chǎng)所,比如P2P,各種使用P2P的下載軟件如迅雷等,這些軟件和傳統(tǒng)的服務(wù)端客戶端模式不大一樣,每個(gè)運(yùn)行軟件的機(jī)器既是客戶端也是服務(wù)端,而用戶的每個(gè)機(jī)器可能處于不同的網(wǎng)絡(luò)環(huán)境中,最典型的就是大部分機(jī)器處于NAT中,這樣的環(huán)境下,采用UDP是最佳選擇,因?yàn)門CP的NAT穿透能力差。

  當(dāng)然這些軟件使用UDP,他們也必須實(shí)現(xiàn)一套算法來(lái)保證UDP傳輸?shù)耐暾晚樞?。我們?cè)陂_發(fā)TCP程序時(shí)候,最先想到的就是 請(qǐng)求-應(yīng)答模式:就是客戶端發(fā)起一個(gè)請(qǐng)求,然后服務(wù)端接收到請(qǐng)求,進(jìn)行處理,接著向客戶端應(yīng)答這個(gè)請(qǐng)求。最典型和常用的就是 HTTP協(xié)議,我們?yōu)g覽的所有網(wǎng)頁(yè),以及各種玲瑯滿目的網(wǎng)站,這些都是HTTP的功勞,HTTP協(xié)議是建立在TCP上的應(yīng)用層協(xié)議,采用就是 請(qǐng)求-應(yīng)答方式。

  瀏覽器首先發(fā)起一個(gè)網(wǎng)頁(yè)請(qǐng)求的TCP連接,web服務(wù)器通過(guò)這個(gè)TCP連接應(yīng)答這個(gè)網(wǎng)頁(yè),并把網(wǎng)頁(yè)內(nèi)容傳輸給瀏覽器。然后瀏覽器可能關(guān)閉這個(gè)TCP連接,或者也可能利用這個(gè)TCP連接發(fā)起另外一個(gè)網(wǎng)頁(yè)請(qǐng)求。這個(gè)請(qǐng)求-應(yīng)答模式,也是我在使用TCP開發(fā)私有協(xié)議時(shí)候,使用的最多的模式,多得來(lái)以至于都忘記其他模式需求的存在了。

  windows遠(yuǎn)程桌面:

  使用遠(yuǎn)程桌面可以遠(yuǎn)程控制另一臺(tái)windows機(jī)器,可以在遠(yuǎn)程桌面里做任何本地桌面上的操作,比如刪除,復(fù)制文件,可以把本地文件復(fù)制到遠(yuǎn)程機(jī)器里,在復(fù)制的同時(shí)還能執(zhí)行其他操作,遠(yuǎn)程機(jī)器的桌面變化實(shí)時(shí)更新到本地,等等。

  但是仔細(xì)研究會(huì)發(fā)現(xiàn),遠(yuǎn)程桌面只使用了一條 TCP連接,連接到被控制機(jī)器的 3389 端口。也就是在一條TCP通訊連接里,傳輸各種請(qǐng)求數(shù)據(jù)和接收各種應(yīng)答數(shù)據(jù)。遠(yuǎn)程桌面使用的是 RDP協(xié)議,我們這里不討論RDP的細(xì)節(jié),只討論如何在一條TCP連接中,如何做到遠(yuǎn)程桌面的各種操作。如果我們還是按照請(qǐng)求-應(yīng)答的模式來(lái)解釋遠(yuǎn)程桌面的通訊協(xié)議,顯然會(huì)有很多無(wú)法處理的問(wèn)題。

  比如舉個(gè)簡(jiǎn)單例子:

  我們?cè)谶h(yuǎn)程桌面客戶端點(diǎn)擊鼠標(biāo)操作,這個(gè)操作會(huì)通過(guò)3389的TCP連接發(fā)送到被控制端,如果按照請(qǐng)求-應(yīng)答模式來(lái)工作,則必須在被控制端接收到這個(gè)鼠標(biāo)操作,執(zhí)行這個(gè)動(dòng)作,然后回答給客戶端已經(jīng)執(zhí)行了這個(gè)操作。如果這期間,被控制機(jī)器的桌面界面內(nèi)容發(fā)生變化,則無(wú)法通知給客戶端,因?yàn)橐磺型ㄓ嵍际前凑湛蛻舳税l(fā)起請(qǐng)求,然后服務(wù)端應(yīng)答的方式通訊的。即使我們使用請(qǐng)求-應(yīng)答的方式,通過(guò)輪詢定時(shí)查詢被控制機(jī)器的界面內(nèi)容變化情況,也無(wú)法做到實(shí)時(shí),而且輪詢慢了會(huì)嚴(yán)重影響視覺效果,輪詢快了會(huì)嚴(yán)重浪費(fèi)資源。

  于是,我們改換一種解決問(wèn)題的辦法,從 UDP 通訊的特點(diǎn):(按照包模式通訊)入手去解決上邊的問(wèn)題。假定我們?cè)谶h(yuǎn)程桌面的TCP通訊中,一切通訊的數(shù)據(jù)都定義成一個(gè)一個(gè)的單獨(dú)的數(shù)據(jù)包在同一條TCP連接中傳輸,數(shù)據(jù)包的接收和發(fā)送分開進(jìn)行,就是在同一個(gè)TCP連接中,一個(gè)線程專門接收數(shù)據(jù)包,一個(gè)線程專門發(fā)送數(shù)據(jù)包。這是可以的,因?yàn)楝F(xiàn)在的網(wǎng)卡都是工作在全雙工狀態(tài)下。所謂全雙工,就是接收和發(fā)送使用各自的通道,能獨(dú)立進(jìn)行數(shù)據(jù)傳輸。

  大致偽代碼如下:

  int tcp_socket = 客戶端連接到服務(wù)端的socket或者服務(wù)端接收到客戶端連接的socket。

  receive_thread() //負(fù)責(zé)接收數(shù)據(jù)包的線程

  {

  tcp_packet = recv_packet (tcp_socket );

  ////TCP 是流協(xié)議,因此,我們必須至少定義一個(gè)表示包大小的頭+包內(nèi)容,才能保證TCP數(shù)據(jù)傳輸?shù)耐健?/p>

  //處理 tcp_packet 包,為了不阻塞讀線程,一般是把tcp_packet交給別的線程處理。

  }

  send_thread()//負(fù)責(zé)發(fā)送數(shù)據(jù)包的線程

  {

  while(loop){

  從發(fā)送隊(duì)列取出一個(gè)包 tcp_packet,(發(fā)送隊(duì)列,是別的線程生成的需要發(fā)送的數(shù)據(jù)包。)

  send_packet( tcp_socket, tcp_packet ); //發(fā)送這個(gè)數(shù)據(jù)包。

  }

  }

  再回到上邊的問(wèn)題,

  遠(yuǎn)程桌面控制端(客戶端)和被控制端(服務(wù)端),分別開啟兩個(gè)線程,一個(gè)負(fù)責(zé)接收數(shù)據(jù)包,一個(gè)負(fù)責(zé)發(fā)送數(shù)據(jù)包。當(dāng)我們?cè)谶h(yuǎn)程桌面客戶端點(diǎn)擊鼠標(biāo)等操作,生成一個(gè)鼠標(biāo)的數(shù)據(jù)包投遞到發(fā)送線程,發(fā)送線程再把它傳輸?shù)奖豢刂贫?,被控制端接收到這個(gè)數(shù)據(jù)包,然后執(zhí)行,他如果要回復(fù)這個(gè)鼠標(biāo)的執(zhí)行結(jié)果,則再生成一個(gè)結(jié)果包投遞到發(fā)送線程,發(fā)送線程再把這個(gè)包傳輸給客戶端。

  同時(shí)如果被控制端的界面發(fā)生改變,則生成一個(gè)界面內(nèi)容改變的數(shù)據(jù)包,投遞到發(fā)送線程,發(fā)送線程再傳輸給客戶端??蛻舳说慕邮站€程接收到界面內(nèi)容改變的數(shù)據(jù)包,顯示新的被控制端的界面內(nèi)容??蛻舳私邮盏绞髽?biāo)執(zhí)行結(jié)果的包,知道鼠標(biāo)操作是失敗還是成功。

  按照包的方式通訊,就能在遠(yuǎn)程桌面中傳遞各種復(fù)雜的動(dòng)作,每個(gè)動(dòng)作都封裝成一個(gè)一個(gè)的數(shù)據(jù)包進(jìn)行傳輸。接收包和發(fā)送包分開獨(dú)立進(jìn)行,互相不干擾,每個(gè)包是否需要應(yīng)答包,根據(jù)每個(gè)包的需求決定,不是必須的。這又回到了 UDP通訊方式。那為何不干脆使用UDP代替呢? 還是上邊提到的原因,TCP保證穩(wěn)定和順序,這點(diǎn)在遠(yuǎn)程桌面等這類要求數(shù)據(jù)必須準(zhǔn)確的地方,是十分必要的。

  TCP如何保證傳輸?shù)氖菃为?dú)數(shù)據(jù)包?

  每個(gè)數(shù)據(jù)包定義成 ”包大小+包內(nèi)容“,比如4個(gè)字節(jié)表示包的大小,然后是包數(shù)據(jù)。

  發(fā)送的時(shí)候,“包大小+包內(nèi)容”組合到一起發(fā)送,接收的時(shí)候,先接收固定的4個(gè)字節(jié),獲取到包的size,

  然后再接收size字節(jié)的數(shù)據(jù),這樣一個(gè)包就接收完成。大致偽代碼如下:

  send_packet(tcp_socket, packet, packet_size) //發(fā)送數(shù)據(jù)包

  {

  int32 size = pakcet_size; ///應(yīng)該采用網(wǎng)絡(luò)序

  send(tcp_socket, &size, 4.。);

  send(tcp_socket, packet, packet_size);

  }

  recv_packet(tcp_socket)

  {

  int32 size;

  recv(tcp_socket, &size, 4,。。.);

  char* packet = malloc(size);

  recv( tcp_socket, packet, size, 。。.);

  return packet;

  }

非常好我支持^.^

(1) 100%

不好我反對(duì)

(0) 0%

( 發(fā)表人:姚遠(yuǎn)香 )

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?