日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

TCP/UDP编程中的问题汇总

發(fā)布時(shí)間:2025/7/14 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TCP/UDP编程中的问题汇总 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

TCP/UDP編程中的問(wèn)題匯總

?

?

?

TCP和UDP發(fā)送大文件的問(wèn)題。

答:

發(fā)送端:

發(fā)送時(shí),先發(fā)送文件的名稱及大小等信息。

然后,設(shè)置一個(gè)緩沖區(qū)的大小,假設(shè)為4K。

再循環(huán)讀4K的文件內(nèi)容,并發(fā)送,直到發(fā)送完成。

最后,再發(fā)送完成標(biāo)記。

?

接收端:

接收到第一個(gè)包時(shí),得到文件的大小等信息。

計(jì)算出要接收多少個(gè)包。

然后,循環(huán)接收包,并將接收到的數(shù)據(jù)寫入到文件中。

直到,接收到的數(shù)據(jù)長(zhǎng)度等于文件的大小。

?

struct package

{

文件標(biāo)識(shí) //GUID

偏移量 //001-

數(shù)據(jù)段 //Byte[]

};

?

?

如何用UDP實(shí)現(xiàn),返回?cái)?shù)據(jù)。

?

UDP服務(wù)端和客戶端,同時(shí)實(shí)現(xiàn)發(fā)送和接收數(shù)據(jù)。

答:

1,客戶端與服務(wù)端在同一局域網(wǎng),或客戶端有公網(wǎng)IP。

?

?

?

?

2,客戶端與服務(wù)端不在同一局域網(wǎng),且客戶端無(wú)公網(wǎng)IP。

NAT技術(shù)。

?

?

?

UDP報(bào)文丟失的問(wèn)題。

答:

如果C給S發(fā)報(bào)文。則S收到報(bào)文后,給C發(fā)一個(gè)收到報(bào)文的響應(yīng)。C對(duì)此進(jìn)行記錄。

如果C在某段時(shí)間內(nèi)未收到響應(yīng),則重發(fā)此報(bào)文。

?

?

UDP報(bào)文的順序問(wèn)題。

答:

發(fā)送端在報(bào)文中加入發(fā)送序號(hào)。接收端就可以按照發(fā)送序號(hào)進(jìn)行重新排列。

?

UDP缺乏流量控制。

?

1.UDP缺乏流量控制的概念

UDP協(xié)議沒(méi)有TCP協(xié)議所具有的滑動(dòng)窗口概念,接收數(shù)據(jù)的時(shí)候直接將數(shù)據(jù)放到緩沖區(qū)中。如果用戶不有及時(shí)地從緩沖區(qū)中將數(shù)據(jù)復(fù)制出來(lái)

,后面到來(lái)的數(shù)據(jù)會(huì)接著向緩沖區(qū)中放入。當(dāng)緩沖區(qū)滿的時(shí)候,后面到來(lái)的數(shù)據(jù)會(huì)覆蓋之前的數(shù)據(jù)造成數(shù)據(jù)的丟失。

2.緩沖區(qū)溢出對(duì)策

解決UDP接收緩沖區(qū)溢出的現(xiàn)象需要根據(jù)實(shí)際情況確定,一般可以用增大接收數(shù)據(jù)緩沖區(qū)和接收方接收單獨(dú)處理的方法來(lái)解決局部的UDP數(shù)

據(jù)接收緩沖區(qū)溢出問(wèn)題。

?

UDP協(xié)議中的數(shù)據(jù)報(bào)文截?cái)?/h2>

?

?

?

?

UDP一次發(fā)送多少bytes好?

當(dāng)然,這個(gè)沒(méi)有唯一答案,相對(duì)于不同的系統(tǒng),不同的要求,其得到的答案是不一樣的,我這里僅對(duì)像ICQ一類的發(fā)送聊天消息的情況作分析,對(duì)于其他情況,你或許也能得到一點(diǎn)幫助:

首先,我們知道,TCP/IP通常被認(rèn)為是一個(gè)四層協(xié)議系統(tǒng),包括鏈路層,網(wǎng)絡(luò)層,運(yùn)輸層,應(yīng)用層.

UDP屬于運(yùn)輸層,下面我們由下至上一步一步來(lái)看:

以太網(wǎng)(Ethernet)數(shù)據(jù)幀的長(zhǎng)度必須在46-1500字節(jié)之間,這是由以太網(wǎng)的物理特性決定的. 這個(gè)1500字節(jié)被稱為鏈路層的MTU(最大傳輸單元).

但這并不是指鏈路層的長(zhǎng)度被限制在1500字節(jié),其實(shí)這這個(gè)MTU指的是鏈路層的數(shù)據(jù)區(qū). 并不包括鏈路層的首部和尾部的18個(gè)字節(jié).

所以,事實(shí)上,這個(gè)1500字節(jié)就是網(wǎng)絡(luò)層IP數(shù)據(jù)報(bào)的長(zhǎng)度限制.

因?yàn)镮P數(shù)據(jù)報(bào)的首部為20字節(jié),所以IP數(shù)據(jù)報(bào)的數(shù)據(jù)區(qū)長(zhǎng)度最大為1480字節(jié).

而這個(gè)1480字節(jié)就是用來(lái)放TCP傳來(lái)的TCP報(bào)文段或UDP傳來(lái)的UDP數(shù)據(jù)報(bào)的.

又因?yàn)閁DP數(shù)據(jù)報(bào)的首部8字節(jié),所以UDP數(shù)據(jù)報(bào)的數(shù)據(jù)區(qū)最大長(zhǎng)度為1472字節(jié).

這個(gè)1472字節(jié)就是我們可以使用的字節(jié)數(shù)。:)

當(dāng)我們發(fā)送的UDP數(shù)據(jù)大于1472的時(shí)候會(huì)怎樣呢?

這也就是說(shuō)IP數(shù)據(jù)報(bào)大于1500字節(jié),大于MTU.這個(gè)時(shí)候發(fā)送方IP層就需要分片(fragmentation).

把數(shù)據(jù)報(bào)分成若干片,使每一片都小于MTU.而接收方IP層則需要進(jìn)行數(shù)據(jù)報(bào)的重組.

這樣就會(huì)多做許多事情,而更嚴(yán)重的是,由于UDP的特性,當(dāng)某一片數(shù)據(jù)傳送中丟失時(shí),接收方便無(wú)法重組數(shù)據(jù)報(bào).將導(dǎo)致丟棄整個(gè)UDP數(shù)據(jù)報(bào)。

因此,在普通的局域網(wǎng)環(huán)境下,我建議將UDP的數(shù)據(jù)控制在1472字節(jié)以下為好.

進(jìn)行Internet編程時(shí)則不同,因?yàn)镮nternet上的路由器可能會(huì)將MTU設(shè)為不同的值.

如果我們假定MTU為1500來(lái)發(fā)送數(shù)據(jù)的,而途經(jīng)的某個(gè)網(wǎng)絡(luò)的MTU值小于1500字節(jié),那么系統(tǒng)將會(huì)使用一系列的機(jī)制來(lái)調(diào)整MTU值,使數(shù)據(jù)報(bào)能夠順利到達(dá)目的地,這樣就會(huì)做許多不必要的操作.鑒于Internet上的標(biāo)準(zhǔn)MTU值為576字節(jié),所以我建議在進(jìn)行Internet的UDP編程時(shí). 最好將UDP的數(shù)據(jù)長(zhǎng)度控件在548字節(jié)(576-8-20)以內(nèi).

?

理論上,IP數(shù)據(jù)報(bào)的最大長(zhǎng)度是65535字節(jié),這是由IP首部16比特總長(zhǎng)度字段所限制的。去除20字節(jié)的IP首部和8個(gè)字節(jié)的UDP首部,UDP數(shù)據(jù)報(bào)中用戶數(shù)據(jù)的最長(zhǎng)長(zhǎng)度為65507字節(jié)。但是,大多數(shù)實(shí)現(xiàn)所提供的長(zhǎng)度比這個(gè)最大值小。

?

我們將遇到兩個(gè)限制因素。第一,應(yīng)用程序可能會(huì)受到其程序接口的限制。socket API提供了一個(gè)可供應(yīng)用程序調(diào)用的函數(shù),以設(shè)置接收和發(fā)送緩存的長(zhǎng)度。對(duì)于UDP socket,這個(gè)長(zhǎng)度與應(yīng)用程序可以讀寫的最大UDP數(shù)據(jù)報(bào)的長(zhǎng)度直接相關(guān)。現(xiàn)在的大部分系統(tǒng)都默認(rèn)提供了可讀寫大于8192字節(jié)的UDP數(shù)據(jù)報(bào)(使用這個(gè)默認(rèn)值是因?yàn)?192是NFS讀寫用戶數(shù)據(jù)數(shù)的默認(rèn)值)。

?

第二個(gè)限制來(lái)自于TCP/IP的內(nèi)核實(shí)現(xiàn)。可能存在一些實(shí)現(xiàn)特性(或差錯(cuò)),使IP數(shù)據(jù)報(bào)長(zhǎng)度小于65535字節(jié)。

在SunOS 4.1.3下使用環(huán)回接口的最大IP數(shù)據(jù)報(bào)長(zhǎng)度是32767字節(jié)。比它大的值都會(huì)發(fā)生差錯(cuò)。

?

但是從BSD/386到SunOS 4.1.3的情況下,Sun所能接收到最大IP數(shù)據(jù)報(bào)長(zhǎng)度為32786字節(jié)(即32758字節(jié)用戶數(shù)據(jù))。

?

在Solaris 2.2下使用環(huán)回接口,最大可收發(fā)IP數(shù)據(jù)報(bào)長(zhǎng)度為65535字節(jié)。

?

從Solaris 2.2到AIX 3.2.2,發(fā)送的最大IP數(shù)據(jù)報(bào)長(zhǎng)度可以是65535字節(jié)。很顯然,這個(gè)限制與源端和目的端的實(shí)現(xiàn)有關(guān)。

?

主機(jī)必須能夠接收最短為576字節(jié)的IP數(shù)據(jù)報(bào)。在許多UDP應(yīng)用程序的設(shè)計(jì)中,其應(yīng)用程序數(shù)據(jù)被限制成512字節(jié)或更小,因此比這個(gè)限制值小。

?

由于IP能夠發(fā)送或接收特定長(zhǎng)度的數(shù)據(jù)報(bào)并不意味著接收應(yīng)用程序可以讀取該長(zhǎng)度的數(shù)據(jù)。因此,UDP編程接口允許應(yīng)用程序指定每次返回的最大字節(jié)數(shù)。如果接收到的數(shù)據(jù)報(bào)長(zhǎng)度大于應(yīng)用程序所能處理的長(zhǎng)度,那么會(huì)發(fā)生什么情況呢?不幸的是,該問(wèn)題的答案取決于編程接口和實(shí)現(xiàn)。

?

典型的Berkeley版socket API對(duì)數(shù)據(jù)報(bào)進(jìn)行截?cái)?#xff0c;并丟棄任何多余的數(shù)據(jù)。應(yīng)用程序何時(shí)能夠知道,則與版本有關(guān)(4.3BSD Reno及其后的版本可以通知應(yīng)用程序數(shù)據(jù)報(bào)被截?cái)?#xff09;。

?

SVR4下的socket API(包括Solaris 2.x) 并不截?cái)鄶?shù)據(jù)報(bào)。超出部分?jǐn)?shù)據(jù)在后面的讀取中返回。它也不通知應(yīng)用程序從單個(gè)UDP數(shù)據(jù)報(bào)中多次進(jìn)行讀取操作。TLI API不丟棄數(shù)據(jù)。相反,它返回一個(gè)標(biāo)志表明可以獲得更多的數(shù)據(jù),而應(yīng)用程序后面的讀操作將返回?cái)?shù)據(jù)報(bào)的其余部分。在討論TCP時(shí),我們發(fā)現(xiàn)它為應(yīng)用程序提供連續(xù)的字節(jié)流,而沒(méi)有任何信息邊界。TCP以應(yīng)用程序讀操作時(shí)所要求的長(zhǎng)度來(lái)傳送數(shù)據(jù),因此,在這個(gè)接口下,不會(huì)發(fā)生數(shù)據(jù)丟失。

?

?

TCP消息邊界的問(wèn)題

通過(guò)套接字或其助手類來(lái)接收信息時(shí),是從緩存區(qū)里一次性把全部的緣存都讀取出來(lái),只要你設(shè)置的緩存夠大,它就能讀取這么多,這樣就會(huì)導(dǎo)致這樣的情況出現(xiàn)。如果服務(wù)端連續(xù)發(fā)送信息到客戶端,如我連續(xù)發(fā)送字符串"message 1"、"message 2"、"message 3"、"message 4"、"message 5",我預(yù)想的是在客戶端也是能夠收到這樣的五個(gè)完整的字符串,如果用前二篇中講的方法,在同臺(tái)機(jī)子上測(cè)試的話,是正常的,因?yàn)橥_(tái)機(jī)子上網(wǎng)絡(luò)信息傳送出現(xiàn)的異常會(huì)比較少,但如果把客戶端與服務(wù)端部署在不同的機(jī)器上,則會(huì)出現(xiàn)一些異想不到的現(xiàn)象。你會(huì)發(fā)現(xiàn)接收到的字符都被打亂了,會(huì)出現(xiàn)如"3message 4"的字符串,這樣的話,我們就不能把服務(wù)端發(fā)送的信息正常的還原。這個(gè)就是消息的邊界問(wèn)題,要解決這個(gè)問(wèn)題,方法有很多,現(xiàn)抽取其中幾個(gè)來(lái)講一下:

?

1、固定尺寸的消息

?

這是最簡(jiǎn)單但也是最昂貴的解決TCP消息問(wèn)題的方案。就是要設(shè)計(jì)一種協(xié)議,永遠(yuǎn)以固定的長(zhǎng)度傳遞消息,通過(guò)將所有的消息都設(shè)置為固定的尺寸,在從遠(yuǎn)程設(shè)備中接收到完整的消息時(shí),TCP接收程序就能夠了解發(fā)送的情況了。用這各地意味著必須將短消息加長(zhǎng),造成網(wǎng)絡(luò)帶寬資源的浪費(fèi)。

?

2、使用消息尺寸信息

?

這個(gè)方案允許使用可變長(zhǎng)度的消息,惟一的不足就是接收端的遠(yuǎn)程設(shè)置必須了解每一個(gè)變長(zhǎng)消息的確切長(zhǎng)度。具體的方法是,在發(fā)送消息的時(shí)候,一起發(fā)送該消息的長(zhǎng)度。那么在客戶端接收的時(shí)候就能知道該消息的長(zhǎng)度是多少,再來(lái)讀取消息。

?

3、使用消息標(biāo)記

?

該方案使用預(yù)先確定的一個(gè)字符(或多個(gè)字符)來(lái)指定消息的結(jié)束,通過(guò)這種方式來(lái)分隔不同的消息。但用這種方法必須對(duì)所接收到的每一個(gè)字符進(jìn)行檢查以便確定為結(jié)束標(biāo)記,這對(duì)于大型消息來(lái)說(shuō),可能導(dǎo)致系統(tǒng)性能的下降,不過(guò)對(duì)于C#語(yǔ)言來(lái)說(shuō),提供了一些類,能夠用于簡(jiǎn)化這個(gè)過(guò)程,那就是System.IO命名空間流類,下面我們也著重來(lái)講一下這各方法。至于第二種方法,將在下一篇中與在消息中傳送實(shí)體類信息相結(jié)合來(lái)講述。

?

在上一篇中,我們已經(jīng)提到NetworkStream類,利用該類來(lái)傳送和接收消息。在這里,再提一下另外的二個(gè)流類,那就是StreamReader和StreamWriter,這二個(gè)類也可用于TCP協(xié)議發(fā)送和接收文本消息。

?

當(dāng)我們得到Socket連接的一個(gè)NetworkStream對(duì)象時(shí),可以通過(guò)下面的方法得到StreamWriter和StreamReader對(duì)象。

?

1NetworkStream ns = s.GetStream();

2 StreamReader sr = new StreamReader(ns);

3 StreamWriter sw = new StreamWriter(ns);

?

這樣我們就可以通過(guò)StreamWriter來(lái)發(fā)送消息,通過(guò)StreamReader來(lái)接收消息:

?

1//發(fā)送消息

2string welcome = "Welcome to my test sever ";

3

4 sw.WriteLine(welcome);

5 sw.Flush();

?

接收消息:

?

1//接收消息

2string data = "";

3data = sr.ReadLine();

?

這樣是不是比以前的做法更簡(jiǎn)單了,而且同時(shí)也解決了TCP消息邊界問(wèn)題了。

?

但是用這各方法必須得注意以下二點(diǎn):

?

1、這種方法其實(shí)就是利用消息標(biāo)記來(lái)解決邊界問(wèn)題的,這里的標(biāo)記就是換行符,也就是說(shuō),StreamWriter中的WriteLine()和StreamReader中的ReadLine()一定要成對(duì)使用,不然如果發(fā)送的信息中沒(méi)有換行符,則客戶機(jī)中用ReadLine()讀取信息時(shí),將無(wú)法結(jié)束,將堵塞程序的執(zhí)行,一直等待換行符。

?

2、另外還要保證在發(fā)送的消息本身不應(yīng)該帶有換行符,如果消息本身帶有換行符,則這些換行符將被ReadLine()方法錯(cuò)誤地作為標(biāo)記,影響數(shù)據(jù)的完整性。

?

?

TCP長(zhǎng)連接和短連接。

2個(gè)小時(shí)。

?

?

斷點(diǎn)續(xù)傳的問(wèn)題。

如何實(shí)現(xiàn)在傳文件時(shí)的斷點(diǎn)續(xù)傳。

答案:

?

? 其實(shí)在tcp/ip協(xié)議中傳輸文件可以保證傳輸?shù)挠行?#xff0c;但有一個(gè)問(wèn)題文件傳了一部分連接意外斷開(kāi)了怎樣;那這種情況只能在重新連接后繼續(xù)傳輸,由于文件那部分已經(jīng)傳了那部分沒(méi)有完成并不是tcp/ip的范圍,所以需要自己來(lái)制定協(xié)議達(dá)到到這個(gè)目的。實(shí)現(xiàn)這個(gè)續(xù)傳的協(xié)議制定其實(shí)也是非常簡(jiǎn)單,通過(guò)協(xié)議把文件按塊來(lái)劃分,每完成一個(gè)塊就打上一個(gè)標(biāo)記;即使是連接斷了通過(guò)標(biāo)記狀態(tài)就知道還需要傳那些內(nèi)容。下面通過(guò)beetle來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單斷點(diǎn)續(xù)傳的程序(包括服務(wù)端和客戶端)。

? ? ? 在實(shí)現(xiàn)之前先整理一下流程思路,首先提交一個(gè)發(fā)送請(qǐng)求信息包括(文件名,塊大小,塊的數(shù)量等),等對(duì)方確認(rèn)后就進(jìn)行文件塊發(fā)送,對(duì)方接收塊寫入后返回一個(gè)標(biāo)記,然后再繼續(xù)發(fā)直到所有發(fā)送完成。思路明確后就制定協(xié)了:

文件傳輸申請(qǐng)信息

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public?class?Post:MessageBase

{??

????public?string?FileName;

????public?long?Size;

????public?int?PackageSize;

????public?int?Packages;

????public?Post()

????{

????????FileID = Guid.NewGuid().ToString("N");

????}

}

public?class?PostResponse : MessageBase

{

????public?string?Status;

}

FileID這個(gè)值是用來(lái)協(xié)同工作的,兩端根據(jù)這個(gè)ID來(lái)找到具體操作的文件和相關(guān)信息;Response提供了一個(gè)Status屬性,可以用來(lái)提供一個(gè)錯(cuò)誤的描述,如果無(wú)有任何值的情況說(shuō)明對(duì)方允許這個(gè)行為.

文件塊傳輸信息

1

2

3

4

5

6

7

8

9

10

public?class?PostPackage:MessageBase

{

????public?byte[] Data;

????public?int?Index;

}

public?class?PostPackageResponse : MessageBase

{

????public?int?Index;

????public?string?Status;

}

文件塊傳輸也是一個(gè)請(qǐng)求,一個(gè)應(yīng)答;分別帶的信息就是塊數(shù)據(jù)信息和塊的位置,同樣也是根據(jù)Status信息來(lái)標(biāo)記塊的處理是否成功。

? ? ? 結(jié)構(gòu)定義完成了,那就進(jìn)行邏輯處理部分;不過(guò)為了調(diào)用更方便還需要封裝一些東西,如根據(jù)塊大小來(lái)劃分文件塊的數(shù)目,獲取某一文件塊的內(nèi)容和寫入文件某一些的內(nèi)容等功能。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

public?static?int?GetFilePackages(long?filesize)

{

????int?count;

????if?(filesize % PackageSize > 0)

????{

????????count = Convert.ToInt32(filesize / PackageSize) + 1;

????}

????else

????{

????????count = Convert.ToInt32(filesize / PackageSize);

????}

???? ?

????return?count;

}

public?static?byte[] FileRead(string?filename, int?index, int?size)

{

????using?(Smark.Core.ObjectEnter oe = new?Smark.Core.ObjectEnter(filename))

????{

????????byte[] resutl = null;

????????long?length = (long)index * (long)size + size;

????????using?(System.IO.FileStream stream = System.IO.File.OpenRead(filename))

????????{

????????????if?(length > stream.Length)

????????????{

????????????????resutl = new?byte[stream.Length - ((long)index * (long)size)];

????????????}

????????????else

????????????{

????????????????resutl = new?byte[size];

????????????}

????????????stream.Seek((long)index * (long)size, System.IO.SeekOrigin.Begin);

????????????stream.Read(resutl, 0, resutl.Length);

????????}

????????return?resutl;

????}

}

public?static?void?FileWrite(string?filename, int?index, int?size, byte[] data)

{

????using?(Smark.Core.ObjectEnter oe = new?Smark.Core.ObjectEnter(filename))

????{

????????using?(System.IO.FileStream stream = System.IO.File.OpenWrite(filename))

????????{

????????????stream.Seek((long)index * (long)size, System.IO.SeekOrigin.Begin);

????????????stream.Write(data, 0, data.Length);

????????????stream.Flush();

????????}

????}

? ?

}

? ? ? 準(zhǔn)備工作完成了,就開(kāi)始寫接收端的代碼了。之前的文章已經(jīng)介紹了Beetle如果創(chuàng)建一個(gè)服務(wù)和綁定分包機(jī)制,在這里就不多說(shuō)了;看下接收的邏輯是怎樣處理了.

接收傳文件請(qǐng)求

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

public?void?Post(ChannelAdapter adapter, Beetle.FileTransfer.Post e)

{

????string?file = txtFolder.Text + e.FileName;

????PostResponse response = new?PostResponse();

????response.FileID = e.FileID;

????response.ID = e.ID;

????try

????{

????????if?(FileTransferUtils.CreateFile(file, e.Size))

????????{

????????????Logics.FileItem item = new?Logics.FileItem();

????????????item.FileID = e.FileID;

????????????item.FileName = file;

????????????item.Packages = e.Packages;

????????????item.PackageSize = e.PackageSize;

????????????item.Completed = 0;

????????????item.Size = e.Size;

????????????Logics.Access.Update(item);

????????????AddItem(item);

????????}

????????else

????????{

????????????response.Status = "不能創(chuàng)建文件!";

????????}

????}

????catch?(Exception e_)

????{

????????response.Status = e_.Message;

????}

????adapter.Send(response);

????? ?

}

接收請(qǐng)求后根據(jù)信息創(chuàng)建臨時(shí)文件,創(chuàng)建成功就把文件相關(guān)信息保存到數(shù)據(jù)庫(kù)中,如果失敗或處理異常就設(shè)置相關(guān)Status信息返回.

接收文件塊請(qǐng)求

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

public?void?PostPackage(ChannelAdapter adapter, Beetle.FileTransfer.PostPackage e)

{

????PostPackageResponse response = new?PostPackageResponse();

????response.FileID = e.FileID;

????response.ID = e.ID;

????try

????{

????????Logics.FileListItem item = fileListBox1.GetAtFileID(e.FileID);

????????if?(item != null)

????????{

????????????FileTransferUtils.FileWrite(

????????????????item.Item.FileName + ".up", e.Index, item.Item.PackageSize, e.Data);

????????????item.Completed(e.Index);

????????????response.Index = e.Index;

????????????if?(item.Status == Logics.FileItemStatus.Completed)

????????????????FileTransferUtils.Rename(item.Item.FileName);

????????}

????????else

????????{

????????????response.Status = "不存在上傳信息!";

????????}

????}

????catch?(Exception e_)

????{

????????response.Status = e_.Message;

????}

????adapter.Send(response);

}

接收塊請(qǐng)求后處理也很簡(jiǎn)單,根據(jù)FileID獲取相關(guān)信息,然后把數(shù)據(jù)寫入到文件對(duì)應(yīng)的位置中;當(dāng)所有塊都已經(jīng)完成后把臨時(shí)文件名改會(huì)來(lái)就行了。如果處理異常很簡(jiǎn)單通過(guò)設(shè)置到Status成員中告訴請(qǐng)求方。

以下就是請(qǐng)求端的代碼了,其代碼比接收端更加簡(jiǎn)單了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

public?void?PostResponse(ChannelAdapter adapter, Beetle.FileTransfer.PostResponse e)

{

????mResponse = e;

????mResetEvent.Set();

}

public?void?PostPackageResponse(ChannelAdapter adapter, Beetle.FileTransfer.PostPackageResponse e)

{

????Logics.FileListItem item = fileListBox1.GetAtFileID(e.FileID);

????if?(item != null)

????{

????????if?(string.IsNullOrEmpty(e.Status))

????????{

????????????item.Completed(e.Index);

????????????PostPacakge(item);

????????}

????????else

????????????item.Status = Logics.FileItemStatus.Default;

????}

}

private?void?PostPacakge(Logics.FileListItem item)

{

????if?(mChannel != null?&& mChannel.Socket != null?&& item.Status == Logics.FileItemStatus.Working

????????&& item.Item.Completed != item.Item.Packages)

????{

????????PostPackage post = new?PostPackage();

????????post.FileID = item.Item.FileID;

????????post.Index = item.Item.Completed;

????????post.Data = FileTransferUtils.FileRead(item.Item.FileName,

????????????item.Item.Completed, item.Item.PackageSize);

????????mAdapter.Send(post);

????}

}

請(qǐng)求端要做的工作就是發(fā)送文件傳輸請(qǐng)求,等回應(yīng)后就處理PostPacakge進(jìn)行文件塊發(fā)送,接收到當(dāng)前文件塊處理成功后就發(fā)送下一塊直接完成。

? ? ? 到這里斷點(diǎn)續(xù)傳的功能代碼就已經(jīng)完成,兩邊的程序已經(jīng)可以工作。不過(guò)對(duì)于一些使用者來(lái)說(shuō)希望程序更友好的表現(xiàn)工作情況,這個(gè)時(shí)候還得對(duì)UI下一點(diǎn)功夫,如看到當(dāng)前傳輸?shù)臓顟B(tài)和每個(gè)文件進(jìn)度情況等。

? ? ? 以上效果看起來(lái)很不錯(cuò),那接下來(lái)就把它實(shí)現(xiàn)吧,程序使用ListBox來(lái)顯示傳輸文件信息,要達(dá)到以上效果需要簡(jiǎn)單地重寫一下OnDrawItem達(dá)到我們需要的。在講述代碼之前介紹一個(gè)圖標(biāo)網(wǎng)站http://www.iconfinder.com/,畢竟好的圖標(biāo)可以讓程序生色不少。下面看下這個(gè)重寫的代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

protected?override?void?OnDrawItem(DrawItemEventArgs e)

{

????base.OnDrawItem(e);

????StringFormat ListSF;

????Point imgpoint = new?Point(e.Bounds.X + 2, e.Bounds.Y + 1);

????ListSF = StringFormat.GenericDefault;

????ListSF.LineAlignment = StringAlignment.Center;

????ListSF.FormatFlags = StringFormatFlags.LineLimit | StringFormatFlags.NoWrap;

????ListSF.Trimming = StringTrimming.EllipsisCharacter;

????Rectangle labelrect = new?Rectangle(e.Bounds.X + 44, e.Bounds.Y, e.Bounds.Width - 44, e.Bounds.Height);

????if?(Site == null?|| Site.DesignMode == false)

????{

????????if?(e.Index >= 0)

????????{

????????????FileListItem item = (FileListItem)Items[e.Index];

????????????LinearGradientBrush brush;

????????????brush =

??????????????new?LinearGradientBrush(e.Bounds, Color.FromArgb(208, 231, 253),

??????????????Color.FromArgb(10, 94, 177), LinearGradientMode.Horizontal);

????????????double?pent = (double)item.Item.Completed / (double)item.Item.Packages;

????????????using?(brush)

????????????{

????????????????e.Graphics.FillRectangle(brush, e.Bounds.X + 40, e.Bounds.Y + 2, Convert.ToInt32((e.Bounds.Width - 40) * pent), e.Bounds.Height - 4);

????????????}

????????????if?(item.Status == FileItemStatus.Working)

????????????{

????????????????mImgList.Draw(e.Graphics, imgpoint, 1);

????????????}

????????????else?if?(item.Status == FileItemStatus.Completed)

????????????{

????????????????mImgList.Draw(e.Graphics, imgpoint, 2);

????????????}

????????????else

????????????{

????????????????mImgList.Draw(e.Graphics, imgpoint, 0);

????????????}

????????????e.Graphics.DrawString(item.ToString(),new?Font("Ariel", 9), new?SolidBrush(Color.Black),labelrect, ListSF);

????????}

????}

}

重繪代碼就是根據(jù)當(dāng)前文件的進(jìn)度內(nèi)容來(lái)計(jì)算出填沖的寬度,還有根據(jù)當(dāng)前文件狀態(tài)繪制不同的圖標(biāo),是不是比較簡(jiǎn)單:)

整個(gè)功能完成了看下總體的效果怎樣:

下載完整代碼

FileTransfer.rar (649.79 kb)?

如果需要Smark名稱空間的代碼可以到?http://smark.codeplex.com/

?

多線程下載的原理:

各個(gè)線程任務(wù)分配是這樣實(shí)現(xiàn)的。在開(kāi)始下載時(shí),文件平均分成若干塊進(jìn)行下載。如第一個(gè)線程一開(kāi)始的任務(wù)是從文件的0位置開(kāi)始下載一直到72908位置處。 線程1每次下載一塊數(shù)據(jù)后就要調(diào)整任務(wù),如第一次下載了20800字節(jié)的數(shù)據(jù),那么線程1的任務(wù)將改為:20800-72908。如此下去,直到任務(wù)為 72908-72908時(shí)表示線程1完成了當(dāng)前的下載任務(wù)。此時(shí),線程1就分析各個(gè)線程的任務(wù),找出任務(wù)最為繁忙的一個(gè)線程:如線程 3:14816-218724。那么線程1就自動(dòng)去調(diào)整任務(wù),拿50%的任務(wù)來(lái)再次下載。周而復(fù)始直到各個(gè)線程都完成任務(wù)。

不過(guò)這里有一點(diǎn)需要注意:為了避免重復(fù)下載部分?jǐn)?shù)據(jù),在調(diào)整任務(wù)的時(shí)候,起始的文件偏移量必須加上接受緩沖器的字節(jié)數(shù),因?yàn)槿缜懊嫠e的例子來(lái)看。線程1和線程3在平衡負(fù)載的時(shí)候,線程正在下載數(shù)據(jù),如果所剩的數(shù)據(jù)比接受緩沖器的大小還小,線程1和線程3的部分下載數(shù)據(jù)將會(huì)重復(fù)。

?

?

UDP協(xié)議基礎(chǔ)知識(shí)

?

UDP協(xié)議在IP協(xié)議上增加了復(fù)用、分用和差錯(cuò)檢測(cè)功能。UDP的特點(diǎn):

?????? A)無(wú)連接的。相比于TCP協(xié)議,UDP協(xié)議在傳送數(shù)據(jù)前不需要建立連接,當(dāng)然也就沒(méi)有釋放連接。

?????? B)盡最大努力交付的。也就是說(shuō)UDP協(xié)議無(wú)法保證數(shù)據(jù)能夠準(zhǔn)確的交付到目的主機(jī)。也不需要對(duì)接收到的UDP報(bào)文進(jìn)行確認(rèn)。

?????? C)面向報(bào)文的。也就是說(shuō)UDP協(xié)議將應(yīng)用層傳輸下來(lái)的數(shù)據(jù)封裝在一個(gè)UDP包中,不進(jìn)行拆分或合并。因此,運(yùn)輸層在收到對(duì)方的UDP包后,會(huì)去掉首部后,將數(shù)據(jù)原封不動(dòng)的交給應(yīng)用進(jìn)程。

???????D)沒(méi)有擁塞控制。因此UDP協(xié)議的發(fā)送速率不送網(wǎng)絡(luò)的擁塞度影響。

?????? E)UDP支持一對(duì)一、一對(duì)多、多對(duì)一和多對(duì)多的交互通信。

???????F)UDP的頭部占用較小,只占用8個(gè)字節(jié)

UDP報(bào)文格式

?????? ?UDP協(xié)議分為首部字段和數(shù)據(jù)字段,其中首部字段只占用8個(gè)字節(jié),分別是個(gè)占用兩個(gè)字節(jié)的源端口、目的端口、長(zhǎng)度和檢驗(yàn)和。

??????? 長(zhǎng)度:UDP報(bào)文的整個(gè)大小,最小為8個(gè)字節(jié)(僅為首部)。

??????? 檢驗(yàn)和:在進(jìn)行檢驗(yàn)和計(jì)算時(shí),會(huì)添加一個(gè)偽首部一起進(jìn)行運(yùn)算。偽首部(占用12個(gè)字節(jié))為:4個(gè)字節(jié)的源IP地址、4個(gè)字節(jié)的目的IP地址、1個(gè)字節(jié)的0、一個(gè)字節(jié)的數(shù)字17、以及占用2個(gè)字節(jié)UDP長(zhǎng)度。這個(gè)偽首部不是報(bào)文的真正首部,只是引入為了計(jì)算校驗(yàn)和。相對(duì)于IP協(xié)議的只計(jì)算首部,UDP檢驗(yàn)和會(huì)把首部和數(shù)據(jù)一起進(jìn)行校驗(yàn)。接收端進(jìn)行的校驗(yàn)和與UDP報(bào)文中的校驗(yàn)和相與,如果無(wú)差錯(cuò)應(yīng)該全為1。如果有誤,則將報(bào)文丟棄或者發(fā)給應(yīng)用層、并附上差錯(cuò)警告。

?

TCP協(xié)議基礎(chǔ)知識(shí)

?

TCP協(xié)議的特點(diǎn):

??????? A)面向連接的。應(yīng)用程序在使用TCP協(xié)議時(shí),必須進(jìn)行連接;當(dāng)然,數(shù)據(jù)傳輸結(jié)束后,要斷開(kāi)TCP連接。

??????? B)TCP連接是點(diǎn)對(duì)點(diǎn)的

??????? C)TCP連接時(shí)可靠的。也就是說(shuō)傳輸?shù)臄?shù)據(jù)時(shí)無(wú)差錯(cuò)的、不丟失、不重復(fù)、有序到達(dá)的。

??????? D)全雙工的。即TCP連接的兩端都設(shè)有發(fā)送緩存和接收緩存,用來(lái)存放雙向通信的數(shù)據(jù)。

??????? E是面向字節(jié)流的。也就是說(shuō)TCP將應(yīng)用程序交下來(lái)的數(shù)據(jù)看成僅僅是一連串的無(wú)結(jié)構(gòu)的字節(jié)流,其不知道這些字節(jié)流的具體含義。TCP協(xié)議無(wú)法保證發(fā)送的數(shù)據(jù)塊的具體大小,因?yàn)?/strong>TCP協(xié)議的發(fā)送的數(shù)據(jù)大小收到對(duì)方給出的窗口值和當(dāng)前的網(wǎng)絡(luò)擁塞度的影響

TCP的連接端點(diǎn)是套接字。套接字是IP地址拼接上端口號(hào)組成的,即點(diǎn)分方式的十進(jìn)制后面是端口號(hào),中間用逗號(hào)或冒號(hào)隔開(kāi)。如下方式:

?????????????????? 套接字Socket=(IP地址:端口號(hào))

TCP報(bào)文段的首部

TCP協(xié)議的首部有20字節(jié)的固定長(zhǎng)度,以及4N字節(jié)的變長(zhǎng)段,因此TCP報(bào)文段首部最小為20字節(jié)。其格式如下:

??? A)分別占用兩個(gè)字節(jié)的源端口和目的端口。

????B)序號(hào)。占用4個(gè)字節(jié)。序號(hào)是循環(huán)的,當(dāng)增加到最大值后又回到0TCP是面向字節(jié)流的,這樣會(huì)個(gè)發(fā)送的數(shù)據(jù)按順序給每個(gè)字節(jié)編上號(hào)。在建立連接時(shí),會(huì)指出發(fā)送的字節(jié)流的起始序號(hào)。首部中的序號(hào)表示發(fā)送的報(bào)文段的數(shù)據(jù)的第一個(gè)字節(jié)的序號(hào),而報(bào)文的給字節(jié)的序號(hào)是順序的。如第一個(gè)字節(jié)為401,報(bào)文的數(shù)據(jù)長(zhǎng)度為100,則首部的序號(hào)為401,最后一個(gè)字節(jié)的序號(hào)為500,也就是說(shuō)下一個(gè)報(bào)文的首部序號(hào)為501

??? C)確認(rèn)號(hào)。占用4個(gè)字節(jié)。表示期望收到下一個(gè)報(bào)文段的第一個(gè)數(shù)據(jù)字節(jié)的序號(hào),也是下一個(gè)報(bào)文段的首部序號(hào)。如:B收到了A200個(gè)字節(jié)數(shù)據(jù)的TCP報(bào)文段,而這個(gè)TCP報(bào)文段的首部序號(hào)為601,則B希望收到的下一個(gè)報(bào)文段確認(rèn)號(hào)為801也可以說(shuō)如果確認(rèn)號(hào)為N,則前面N-1為止的數(shù)據(jù)已經(jīng)收到。

????D)數(shù)據(jù)偏移。占用4位。其表示數(shù)據(jù)起始位置相對(duì)于報(bào)文段起始的位置的偏移量,也就是報(bào)文段首部的長(zhǎng)度。其單位為32位字,也就是說(shuō)其表示的值應(yīng)該乘上4個(gè)字節(jié)。如:該字段的值為4,則其報(bào)文段首部長(zhǎng)度為16個(gè)字節(jié)。其最大值只能表示15,也就是說(shuō)報(bào)文段的首部最大只能為60個(gè)字節(jié)(即變長(zhǎng)只能為20個(gè)字節(jié))。其最小值為5,因?yàn)槭撞孔钚≈禐?/span>20

???? E)保留。占用6位。其值設(shè)為0

???? F)緊急URG。其占用1位。如果URG設(shè)為1,表示首部中的緊急指針有效。表示其發(fā)送的報(bào)文段數(shù)據(jù)有緊急數(shù)據(jù),其需要馬上發(fā)送出去(也就是取得最高優(yōu)先權(quán)),TCP會(huì)將緊急數(shù)據(jù)插入到該報(bào)文的最前端,后面任然為普通數(shù)據(jù)。

???? G)確認(rèn)ACK。占用1位。當(dāng)ACK=1時(shí),表示首部中確認(rèn)號(hào)字段有效,為0時(shí),確認(rèn)號(hào)字段無(wú)效。TCP規(guī)定,在連接建立后ACK字段必須為1

???? H)推送PSH。占用1位。兩個(gè)應(yīng)用程序通信,有時(shí)應(yīng)用程序希望鍵入一個(gè)命令馬上能夠得到對(duì)方回應(yīng),這是就可以使用這個(gè)字段。將PSH設(shè)為1TCP會(huì)馬上建立一個(gè)報(bào)文將其發(fā)送出去。接收端在收到該報(bào)文后,會(huì)盡快的將其交給應(yīng)用程序,不用得到緩沖區(qū)滿。

????? I)復(fù)位RST。占用1位。當(dāng)RST=1時(shí),表示連接出現(xiàn)嚴(yán)重錯(cuò)誤,需要釋放連接,然后重新進(jìn)行連接。其還用于拒絕打開(kāi)一個(gè)連接或拒絕非法報(bào)文。

????? J)同步SYN。占用1位。用于在連接建立時(shí)同步序號(hào)。當(dāng)SYN=ACK=0時(shí),表示這是一個(gè)連接請(qǐng)求報(bào)文段。當(dāng)SYN=1ACK=1時(shí),表示對(duì)方接收建立連接報(bào)文段。因此SYN=1,表示這是一個(gè)連接請(qǐng)求或連接接受報(bào)文段。

????? K)終止FIN。占用1位。當(dāng)FIN=1時(shí),表示發(fā)送方的數(shù)據(jù)發(fā)送完畢,并要求釋放連接。

????? L)窗口。占用2個(gè)字節(jié)。表示發(fā)送該報(bào)文段的一方的接收窗口,表示允許對(duì)方發(fā)送的數(shù)據(jù)量。窗口值告訴對(duì)方:從報(bào)文段首部中的確認(rèn)好算起,接收方目前允許對(duì)方發(fā)送的數(shù)據(jù)量。如:確認(rèn)為801,窗口值為1000,則表示其還有接收1000個(gè)字節(jié)數(shù)據(jù)(801-1800)的接收緩存空間。

????? M)檢驗(yàn)和。占2個(gè)字節(jié)。其也和UDP一樣需要加上偽首部,但是其中的17會(huì)變?yōu)?/span>6

????? N)緊急指針。占用2個(gè)字節(jié)。當(dāng)URG=1時(shí)有效,其指出了緊急數(shù)據(jù)在報(bào)文端中的末尾位置。緊急數(shù)據(jù)在報(bào)文數(shù)據(jù)段的開(kāi)始。

????? O)選項(xiàng)。可選,最大為40個(gè)字節(jié)。包括MSS、窗口擴(kuò)大、時(shí)間戳、選擇確認(rèn)等。

?

TCP的連接與斷開(kāi)

?

TCP連接的建立采用客戶服務(wù)器方式。TCP連接可分為通信雙方一方發(fā)起連接和雙方同時(shí)發(fā)起連接。

一方發(fā)起連接

????? ? 假設(shè)A方為客服端,B為服務(wù)器端,由AB發(fā)起建立連接請(qǐng)求。

????? ? B的服務(wù)器進(jìn)程創(chuàng)建傳輸控制塊TCB,準(zhǔn)備接受客戶進(jìn)程的連接請(qǐng)求。然后服務(wù)器進(jìn)程處于LISTEN狀態(tài),等待客服端的連接請(qǐng)求。

?????? ?A打的TCP客服端進(jìn)程創(chuàng)建控制塊TCB,然后向B發(fā)送連接請(qǐng)求報(bào)文段。該報(bào)文的首部SYN=1,并且假設(shè)序號(hào)seq=xTCP規(guī)定,該連接請(qǐng)求報(bào)文段不攜帶任何數(shù)據(jù),但需要占用一個(gè)序號(hào)A發(fā)送了連接請(qǐng)求報(bào)文后進(jìn)入SYN-SENT狀態(tài)

??????? B收到A的連接請(qǐng)求報(bào)文后,會(huì)向A返回連接接受報(bào)文。該報(bào)文的首部SYN=1ACK=1seq=y,ack=x+1TCP也規(guī)定,連接接受報(bào)文段也不攜帶任何數(shù)據(jù),但也需要占用一個(gè)序號(hào)B發(fā)送該報(bào)文后立即進(jìn)入SYN-RECD狀態(tài)

??????? A收到B的連接接受報(bào)文后,還需要向B發(fā)送一個(gè)確認(rèn)報(bào)文段。在該報(bào)文中ACK=1seq=x+1,ack=y+1TCP規(guī)定,在該報(bào)文段中可以攜帶數(shù)據(jù),也可不攜帶數(shù)據(jù)。但,不攜帶數(shù)據(jù)時(shí),不會(huì)消耗一個(gè)序號(hào),也就會(huì)說(shuō)下一個(gè)發(fā)送的報(bào)文段的序號(hào)仍為x+1。該報(bào)文段發(fā)送成功后,進(jìn)入ESTAB-LISHED狀態(tài),。

?????? B收到A的確認(rèn)后,也進(jìn)入ESTAB-ISHED狀態(tài)

?同時(shí)發(fā)起連接

?????? 出現(xiàn)這種同時(shí)發(fā)起連接的情況可能性極小,但TCP仍然支持這種方式,這種方式?jīng)]有客戶端和服務(wù)器區(qū)分,一個(gè)既是客戶端又是服務(wù)器。這種方式,雙方同時(shí)發(fā)起連接請(qǐng)求報(bào)文,并進(jìn)入SYN-SENT狀態(tài)。當(dāng)收到對(duì)方的連接請(qǐng)求報(bào)文后,馬上發(fā)送一個(gè)連接接受報(bào)文,并馬上進(jìn)入SYN-REVD狀態(tài)。當(dāng)收到對(duì)方的連接接受報(bào)文后,進(jìn)入ESTABISHED狀態(tài)。

斷開(kāi)連接?

斷開(kāi)連接也可以分為由連接一方發(fā)起斷開(kāi)連接請(qǐng)求和同時(shí)發(fā)起斷開(kāi)連接請(qǐng)求。

一方發(fā)起斷開(kāi)連接

????????AB發(fā)起斷開(kāi)連接請(qǐng)求報(bào)文。該報(bào)文的首部中FIN=1,假設(shè)序列號(hào)seq=u,其為前面發(fā)送的報(bào)文段的數(shù)據(jù)的最后一個(gè)序列號(hào)加一。這是A進(jìn)入FIN-WAI-1狀態(tài)TCP規(guī)定,斷開(kāi)連接請(qǐng)求報(bào)文不攜帶任何數(shù)據(jù),但要消耗一個(gè)序列號(hào)。發(fā)送該報(bào)文之前會(huì)將緩沖區(qū)中的數(shù)據(jù)全部發(fā)送出去,該報(bào)文可以附加數(shù)據(jù)。

?????? B在收到A的斷開(kāi)連接請(qǐng)求報(bào)文后,會(huì)發(fā)回一個(gè)確認(rèn)報(bào)文。該報(bào)文的首部中ACK=1ack=u+1,假設(shè)seq=vB進(jìn)入了CLOSE-WAIT狀態(tài)。這時(shí)B會(huì)通知上層應(yīng)用進(jìn)程,這是AB方向的連接釋放了,表明A沒(méi)有數(shù)據(jù)發(fā)給B了。這是可能會(huì)在該狀態(tài)持續(xù)一段時(shí)間,等待B將沒(méi)發(fā)送完的數(shù)據(jù)發(fā)送給A。這時(shí)A不能夠發(fā)送數(shù)據(jù)給B,A還可以接收數(shù)據(jù)。

????? A在收到B的確認(rèn)報(bào)文后,會(huì)進(jìn)入FIN-WAIT-2狀態(tài),等待BA發(fā)送斷開(kāi)連接請(qǐng)求報(bào)文。

????? 當(dāng)B沒(méi)有數(shù)據(jù)需要發(fā)送給A時(shí),其會(huì)釋放TCP連接。BA發(fā)送斷開(kāi)連接請(qǐng)求報(bào)文。該報(bào)文的首部中FIN=1ACK=1ack=u+1,假設(shè)序列號(hào)為seq=w(因?yàn)榭赡茉诘却倪@段時(shí)間里,BA發(fā)送了一些數(shù)據(jù))。這是B進(jìn)入LAST-ACK狀態(tài)。該報(bào)文也可以附加數(shù)據(jù)。

????? A收到B的斷開(kāi)連接請(qǐng)求報(bào)恩后,也會(huì)發(fā)回個(gè)確認(rèn)報(bào)文。該報(bào)文中ACK=1ack=w+1,seq=u+1。這時(shí)A進(jìn)入TIME-WAIT狀態(tài)

???? B在收到A餓確認(rèn)報(bào)文后,就徹底的斷開(kāi)了連接,并且會(huì)撤去相應(yīng)的傳輸控制塊

? ?

????? 快速斷開(kāi)連接:這種情況出現(xiàn)B發(fā)送給A斷開(kāi)連接確認(rèn)報(bào)文,不僅為ACK而且FIN=1,也就是說(shuō)在該確認(rèn)報(bào)文中還包括了B的斷開(kāi)連接請(qǐng)求。這是A在收到該報(bào)文后,會(huì)給B發(fā)送一個(gè)確認(rèn)報(bào)文,并進(jìn)入TIME-WAIT狀態(tài)。(相對(duì)于正常斷開(kāi)的4次握手,快速斷開(kāi)連接方式將第二次和第三次握手合成了一次)。

同時(shí)斷開(kāi)連接

?????????兩端應(yīng)用層同時(shí)發(fā)出關(guān)閉命令時(shí),兩端均從 ESTABLISHED 變?yōu)?/span> FIN_WAIT_1 。這將導(dǎo)致雙方各發(fā)送一個(gè) FIN ,兩個(gè) FIN 經(jīng)過(guò)網(wǎng)絡(luò)傳送后分別到達(dá)另一端。收到 FIN 后,狀態(tài)由 FIN_WAIT_1 變遷到 CLOSING ,并發(fā)送最后的 ACK 。當(dāng)收到最后的 ACK 時(shí),狀態(tài)變化為 TIME_WAIT 狀態(tài)。

?

?

在同一個(gè)進(jìn)程中,UDP和TCP可以共用同一個(gè)端口嗎?

答:

可以。不同的協(xié)議沒(méi)有沖突。相同的協(xié)議有沖突。

?

?

?

數(shù)據(jù)的加密

SSL

?

轉(zhuǎn)載于:https://www.cnblogs.com/heavyhe/p/4547065.html

總結(jié)

以上是生活随笔為你收集整理的TCP/UDP编程中的问题汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。