自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

動(dòng)手學(xué)習(xí)TCP系列之?dāng)?shù)據(jù)傳輸

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
前面的文章介紹了TCP狀態(tài)變遷,以及TCP狀態(tài)變遷圖中的一些特殊狀態(tài)。本文主要看看TCP數(shù)據(jù)傳輸過(guò)程中需要了解的一些重要點(diǎn):MSS(Maximum Segment Size)、Seq號(hào)和Ack號(hào)的計(jì)算、TCP半連接

前面的文章介紹了TCP狀態(tài)變遷,以及TCP狀態(tài)變遷圖中的一些特殊狀態(tài)。

本文主要看看TCP數(shù)據(jù)傳輸過(guò)程中需要了解的一些重要點(diǎn):

MSS(Maximum Segment Size)

Seq號(hào)和Ack號(hào)的計(jì)算

TCP半連接

TCP數(shù)據(jù)傳輸實(shí)驗(yàn)

在開(kāi)始介紹上面列出的內(nèi)容之前,先看看實(shí)驗(yàn)程序的運(yùn)行。

本文的例子代碼是基于"動(dòng)手學(xué)習(xí)TCP:客戶端狀態(tài)變遷"文章中的例子。

首先,修改了"BuildTcpPacket"這個(gè)函數(shù),增加了兩個(gè)功能:

正常情況下TCP首部是20個(gè)字節(jié),但是TCP首部支持一些特殊"Options"(MSS就是其中一個(gè));所以,***個(gè)改動(dòng)就是支持創(chuàng)建帶特殊選項(xiàng)的TCP包

第二個(gè)改動(dòng)是可以通過(guò)參數(shù)設(shè)置為T(mén)CP包增加Payload,這樣就可以通過(guò)TCP包傳輸數(shù)據(jù)了。

public static Packet BuildTcpPacket(EndPointInfo endPointInfo, TcpControlBits tcpControlBits, List tcpOptionList = null, bool withPayload = false, string payloadData = "")
{
EthernetLayer ethernetLayer =
new EthernetLayer
{
Source = new MacAddress(endPointInfo.SourceMac),
Destination = new MacAddress(endPointInfo.DestinationMac),
EtherType = EthernetType.None, // Will be filled automatically.
};
IpV4Layer ipV4Layer =
new IpV4Layer
{
Source = new IpV4Address(endPointInfo.SourceIp),
CurrentDestination = new IpV4Address(endPointInfo.DestinationIp),
Fragmentation = IpV4Fragmentation.None,
HeaderChecksum = null, // Will be filled automatically.
Identification = 123,
Options = IpV4Options.None,
Protocol = null, // Will be filled automatically.
Ttl = 10,
TypeOfService = 0,
};
TcpLayer tcpLayer =
new TcpLayer
{
SourcePort = endPointInfo.SourcePort,
DestinationPort = endPointInfo.DestinationPort,
Checksum = null, // Will be filled automatically.
SequenceNumber = seqNum,
AcknowledgmentNumber = ackNum,
ControlBits = tcpControlBits,
Window = windowSize,
UrgentPointer = 0,
Options = (tcpOptionList == null) ? TcpOptions.None : new TcpOptions(tcpOptionList),
};
PacketBuilder builder;
if (withPayload)
{
PayloadLayer payloadLayer = new PayloadLayer
{
Data = new Datagram(System.Text.Encoding.ASCII.GetBytes(payloadData)),
};
builder = new PacketBuilder(ethernetLayer, ipV4Layer, tcpLayer, payloadLayer);
return builder.Build(DateTime.Now);
}
builder = new PacketBuilder(ethernetLayer, ipV4Layer, tcpLayer);
return builder.Build(DateTime.Now);
}

代碼其余的改動(dòng)發(fā)生在"PacketHandler"函數(shù)中:

private static void PacketHandler(PacketCommunicator communicator, EndPointInfo endPointInfo, bool clientToSendFin = true)

增加了對(duì)于"ESTABLISHED"狀態(tài)下收到數(shù)據(jù)包的處理,主要作用就是發(fā)送一個(gè)[ACK]包對(duì)收到的數(shù)據(jù)包進(jìn)行確認(rèn)。

case TcpControlBits.Acknowledgment:
if (tcpStatus == TCPStatus.FIN_WAIT_1)
{
tcpStatus = TCPStatus.FIN_WAIT_2;
Utils.PacketInfoPrinter(packet, tcpStatus);
}
else if (tcpStatus == TCPStatus.LAST_ACK)
{
tcpStatus = TCPStatus.CLOSED;
Utils.PacketInfoPrinter(packet, tcpStatus);
running = false;
}
else if (tcpStatus == TCPStatus.ESTABLISHED)
{
//print the data received from server
Console.WriteLine(packet.Ethernet.IpV4.Tcp.Payload.ToString());
communicator.SendPacket(Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment));
}
break;
case (TcpControlBits.Acknowledgment | TcpControlBits.Push):
if (tcpStatus == TCPStatus.ESTABLISHED)
{
//print the data received from server
Console.WriteLine(packet.Ethernet.IpV4.Tcp.Payload.ToString());
communicator.SendPacket(Utils.BuildTcpResponsePacket(packet, TcpControlBits.Acknowledgment));
}
break;

運(yùn)行效果

代碼修改好之后,運(yùn)行代碼。

通過(guò)console端可以看到,在連接為"ESTABLISHED"狀態(tài)下,客戶端收到的來(lái)自服務(wù)端的字節(jié)數(shù)。

 

#p#

通過(guò)Wireshark抓包可以看到,在連接建立請(qǐng)求包[SYN]中增加了MSS的設(shè)置,并且以后的數(shù)據(jù)傳出中,TCP數(shù)據(jù)包的payload長(zhǎng)度***就是MSS的值。

 

下面就開(kāi)始介紹上面實(shí)驗(yàn)中涉及的TCP數(shù)據(jù)傳輸?shù)闹R(shí)點(diǎn)。

TCP分段和IP分片

在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)包是有大小限制,這里就需要知道TCP分段和IP分片的概念了。

跟這兩個(gè)概念緊密相關(guān)的就是MSS(Maximum Segment Size)和MTU(Maximum Transmission Unit)這兩個(gè)指標(biāo)了,這兩個(gè)指標(biāo)的值大小直接決定了TCP分段和IP分片。

下面分別看看MSS和MTU。

MTU

首先來(lái)看看MTU。

以太網(wǎng)和802.3對(duì)數(shù)據(jù)幀的長(zhǎng)度都有一個(gè)限制,***值分別是1500和1492個(gè)字節(jié)。鏈路層的這個(gè)指標(biāo)稱作MTU(注意MTU是鏈路層的概念),不同類型的網(wǎng)絡(luò)大多數(shù)都有一個(gè)上限。

如果網(wǎng)絡(luò)層(IP層)有一個(gè)數(shù)據(jù)報(bào)需要傳輸,且數(shù)據(jù)的長(zhǎng)度比鏈路層的 MTU還大,那么網(wǎng)絡(luò)層(IP層)就要進(jìn)行分片(fragmentation),把數(shù)據(jù)報(bào)分成若干片,保證每一個(gè)分片都小于MTU;目的端的網(wǎng)絡(luò)層(IP層)會(huì)對(duì)收到的分片進(jìn)行重新組裝。

也就是說(shuō),分片和重新組裝過(guò)程發(fā)生在網(wǎng)絡(luò)層(IP層),所以對(duì)運(yùn)輸層(TCP/UDP)是透明的。

下面看看通過(guò)ping命令演示IP分片,ping命令屬于ICMP(Internet Control Messages Protocol)協(xié)議:

 

Wireshark的結(jié)果為下,這5000個(gè)字節(jié)的數(shù)據(jù)被分別放在了四個(gè)IP分片中,每個(gè)分片(***一個(gè)分片除外)中的數(shù)據(jù)長(zhǎng)度等于1480(1500 – 20[IP header]):

 

IP分片的問(wèn)題:IP分片有一個(gè)很大的問(wèn)題,由于IP層本身沒(méi)有超時(shí)重傳機(jī)制,即使只丟失一片數(shù)據(jù)也要重新傳整個(gè)數(shù)據(jù)報(bào)。也就是說(shuō),對(duì)于上面截圖中的4個(gè)Frame,任何一個(gè)丟失了,另外3個(gè)都需要進(jìn)行重傳。

使用UDP和ICMP的時(shí)候很容易導(dǎo)致IP分片,因?yàn)閁DP和ICMP是不考慮MTU和分片的,而是把這些工作都丟給了網(wǎng)絡(luò)層(IP層);但是,為了減少IP分片對(duì)TCP的影響,在TCP中提出了MSS來(lái)試圖避免IP分片。

MSS

MSS就是TCP數(shù)據(jù)包每次能夠傳輸?shù)?**數(shù)據(jù)分段。

為了達(dá)到***的傳輸效能TCP協(xié)議在建立連接的時(shí)候通常要協(xié)商雙方的MSS值,這個(gè)值TCP協(xié)議在實(shí)現(xiàn)的時(shí)候往往用MTU值代替(需要減去IP數(shù)據(jù)包首部的大小20Bytes和TCP數(shù)據(jù)段的首部20Bytes),所以往往MSS為1460。通訊雙方會(huì)根據(jù)雙方提供的MSS值得最小值確定為這次連接的***MSS值。

回到本文開(kāi)始的例子,在建立TCP連接的時(shí)候,客戶端指定了MSS為800,服務(wù)端指定的MSS為1460。經(jīng)過(guò)協(xié)商后,雙方采用了較小的MSS,所以以后的數(shù)據(jù)包長(zhǎng)度最到為800字節(jié)。TCP就是通過(guò)這種方式來(lái)避免IP分片的。

再看一個(gè)MSS的例子,通過(guò)Wireshark抓取了一段HTTP請(qǐng)求,通過(guò)GET方法請(qǐng)求jquery的一組數(shù)據(jù)包。

通過(guò)下面可以看到,當(dāng)應(yīng)用層有一個(gè)超過(guò)MSS的數(shù)據(jù)需要發(fā)送的時(shí)候,TCP會(huì)把應(yīng)用層的數(shù)據(jù)分成多個(gè)TCP分段然后發(fā)送出去。每一個(gè)分段包都包含TCP首部,然后傳遞給網(wǎng)絡(luò)層進(jìn)一步增加IP首部。

 

區(qū)別

通過(guò)上面可以看到TCP分段和IP分片有下面的主要區(qū)別:

TCP分段發(fā)生在傳輸層,分段的依據(jù)是MSS;IP分片發(fā)生在網(wǎng)絡(luò)層,分片的依據(jù)是MTU

TCP分段是在傳輸層完成,并在傳輸層進(jìn)行重組;IP分片由網(wǎng)絡(luò)層完成,也在網(wǎng)絡(luò)層進(jìn)行重組

再看Seq和Ack號(hào)

TCP傳輸?shù)目煽啃允峭ㄟ^(guò)Seq和Ack號(hào)來(lái)進(jìn)行保證的,所以可以看出Seq和Ack號(hào)的重要性。

文章開(kāi)始的實(shí)驗(yàn)中,另一個(gè)需要注意的地方就是Seq和Ack號(hào)的變化。

在前面TCP連接的相關(guān)文章中已經(jīng)介紹了連接建立和終止時(shí)候Seq和Ack號(hào)的變化,可以總結(jié)得到下面公式:

確認(rèn)包的Ack = 待確認(rèn)包(特殊標(biāo)志包)的Seq + 1

從Wireshark的截圖中可以看到在數(shù)據(jù)傳輸中Seq和Ack號(hào)的變化。

 

對(duì)于數(shù)據(jù)包的確認(rèn),可以使用下面的方式進(jìn)行計(jì)算:

確認(rèn)包的Ack = 待確認(rèn)數(shù)據(jù)包的Seq + 待確認(rèn)數(shù)據(jù)包的數(shù)據(jù)長(zhǎng)度(Len)

關(guān)于TCP半連接

在介紹TCP終止連接的時(shí)候,提到了由于TCP是全雙工的,所以需要經(jīng)過(guò)四次揮手才能關(guān)閉TCP連接。

TCP中有一個(gè)半連接的概念,就是TCP連接的一端在結(jié)束它的發(fā)送后,還能接收來(lái)自另一端數(shù)據(jù)。

還是回到文章開(kāi)始的例子,服務(wù)端發(fā)出了終止TCP連接的請(qǐng)求[FIN, ACK],客戶端進(jìn)行了確認(rèn),到此服務(wù)端到客戶端方向的TCP連接就關(guān)閉了。

但是,隨后客戶端向服務(wù)端發(fā)送了一段長(zhǎng)度為480字節(jié)的數(shù)據(jù),然后才關(guān)閉客戶端到服務(wù)端方向的TCP連接。

 

總結(jié)

本文主要介紹了TCP數(shù)據(jù)傳輸中的幾個(gè)重要的概念。

MSS(Maximum Segment Size)

Seq號(hào)和Ack號(hào)

TCP半連接

通過(guò)這篇文章,一定能很好的認(rèn)識(shí)TCP分段和IP分片的區(qū)別,以及MSS和MTU的關(guān)系。

責(zé)任編輯:何妍 來(lái)源: 博客園
相關(guān)推薦

2015-10-08 14:03:01

TCP網(wǎng)絡(luò)協(xié)議

2015-10-13 15:09:31

2009-07-07 16:46:33

數(shù)據(jù)傳輸銅纜結(jié)構(gòu)

2015-10-09 13:15:03

TCP網(wǎng)絡(luò)協(xié)議

2020-06-12 07:50:15

大數(shù)據(jù)

2010-04-07 14:54:38

2015-10-15 09:38:48

TCP網(wǎng)絡(luò)協(xié)議定時(shí)器

2015-10-12 08:33:06

TCP網(wǎng)絡(luò)協(xié)議服務(wù)端

2015-10-10 09:51:51

TCP網(wǎng)絡(luò)協(xié)議客戶端

2010-07-13 15:55:12

FTP數(shù)據(jù)傳輸模式

2023-04-12 16:20:00

同步數(shù)據(jù)異步數(shù)據(jù)傳輸

2013-11-26 15:51:45

Android編程藍(lán)牙數(shù)據(jù)傳輸

2009-12-08 11:17:41

WCF雙向通信

2021-12-14 11:01:44

TCPUDP網(wǎng)絡(luò)協(xié)議

2021-06-09 11:28:06

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

2019-09-06 09:11:36

以太網(wǎng)數(shù)據(jù)二層交換

2017-05-04 12:48:18

WOT網(wǎng)易NDC

2024-08-05 09:31:00

MySQLDTS數(shù)據(jù)

2022-03-30 15:06:25

數(shù)據(jù)傳輸Harmony源碼分析

2011-03-02 11:23:48

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)