曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 3496|回复: 0
打印 上一主题 下一主题

TCP 数据的处理:流,段 和 序列号

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2013-1-16 20:38:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
使用离散的消息块是相当简单的,许多协议都直接使用它们。但其天生存有局限性,比如为了能够正常的会话,它会迫使应用程序去创建这些离散的数据块。然而,许多应用程序在一定程度上需要连续的发送消息,也就是说还让应用程序分神去创建这这些大量的消息块是不适宜的。另外,一些应用程序需要发送大把的数据,对于较低的协议层来说,它们不可能接受一次性将大量的数据当作整块来发送。

如使用像 UDP 这样的协议,应用程序将不得不人为地将它们的数据分割成许多消息块,而它们之间并没有什么内在的意义。这样就会使得应用程序需要做许多额外的工作,比如不得不对这些消息中的数据进行跟踪,如果发现丢失了,还得给补上;此外,应用程序还得在接收到这些消息时负责按正确的顺序将它们重组好,因为 IP 协议发送这些消息块时很可能不是按照一定的顺序的。当然了,应用程序确实可以完整这些工作,但是这些功能 TCP 协议自身就可以实现,因此再用应用程序来完成这些事情,那就显得毫无意义。

TCP 设计者使 TCP 协议可以接收来自应用程序任意大小,任意结构类型的数据,而不要求数据必须是一个个的消息块。更具体的说,TCP 对来自应用程序的数据是以”流“(stream) 的形式来看待的。因此,对 TCP 的描述也是从”面向数据流“(stream-oriented)的。每一个应用程序将数据以一个稳定以字节流来传输,而不必将它们先搞成数据块,也无需担心这个流到底有多长。形象的说,就像从井里用水泵打水一般,水从井里到泵口,是一种流的形式;而出泵口后,至于你是用大桶还是小桶来装水,那就不是应用程序所关心的问题了。

将数据打包成”段“(segments)
从应用程序送来的数据经 TCP 处理后,会使用网络层的 IP 协议将其发送。IP 是一种面向消息(message-oriented)的协议,而非面向数据流(stream-oriented)。因此,来自应用程序的数据流就会在 TCP 里被封装成一个个的消息块,这些消息块我们称之为 ”TCP 段“(TCP segments)

”TCP 段“ 被送往 IP 后,会进一步被封装以 IP 数据包头,然后再将其传送到目的设备。在接收端,数据经过 IP 层时,会被解包成 ”TCP 段“,然后再送到 TCP ,再接着 TCP 会将这些数据还原成字节流返回给应用程序。工作原理如下图所示:

上图中,一旦 TCP 连接建立起来,一个应用层协议就可以给 TCP 发送一个稳定的字节流,对于该流,不要求符合任何一个特定结构。TCP 会对将这些字节打包成”段“,而”段“的大小则由一些不同的参数来决定。接着,这些”段“会被送往 IP 层,在此还会进一步封装成 IP 数据包,然后再传送出去。在接收端,执行与发送端相反的解包 过程。

TCP 数据标识符:序列号(Sequence Numbers)
由于 TCP 是一种可靠协议,它需要保持对所有来自应用程序数据的跟踪,这样才能确保接收端可以完整无缺的收到数据。此外,它还必须确保数据按照它所发送数据被顺序接收,且必须重发任何意外丢失的数据。

TCP 对数据的跟踪涉及到一个重要概念,即“序列号”(Sequence Numbers) 。由于 TCP 是面向数据流的协议,因此“序列号”必须能够体现到每一个数据字节!这看起来貌似很奇怪,但实际上确实如此。序列号可以确保以“段”形式发送的数据可以重新还原为传递给应用层的数据流。

下面使用一个实例来说明序列号的情形,这里使用嗅探工具来捕捉一个访问 www.groad.net 时所需要的 HTTP 协议,而 HTTP 协议则是基于 TCP 的。

在三次握手开始时,客户端向服务端发送 SYN ,此时可以看到:

上图中,所发送的序列号是 4131116864 ,底下的应答号(Ack Number 为 0)。该序列号由客户端随机产生。

接着,服务器应答客户端(SYN + ACK) :

由上图可见,服务器应答号为 4131116864 + 1 = 4131116865 ;服务器则自己随机产生了一个序列号 3152946212 。

接着,客户端回应服务器(ACK):

由上图可见,客户端将之前服务器发来的序列号 3152946212 加 1 后作为应答号,并将服务器发来的应答号作为自己的序列号。

经过上面的几个步骤,3 次握手完成。接下来,客户端要用 GET 方法来请求服务器上的数据了:

我们再观察这条记录中的序列号和应答号:

发现它们和第 3 次握手中的一样。需要注意的是,[Next Sequence Number] 中所条的序列号并不是本次发送的任何一次数据,而是嗅探软件自己计算好下一次要发送的序列号值,因此这里使用一个中括号 [ ] 提示。那么 ,[Next Sequence Number] 这个值(4131117137)是怎么算出来的?回过头来看一下上面客户端使用 GET 请求的图,那次发送的数据尺寸为 330 。用这个值减去以太网包头 14 个字节,IP 包头 20 个字节,TCP 包头 20 个字节,以及 FCS ()4 个字节,共 58 个字节后得到 272 。把 4131116865 加上 272 后就得到 4131117137 了。

接下来服务器应答客户端的请求:

从上面可以看到,服务器发送过来的序列号为 3152946213 ,即上一步客户端发来的应答号;而它所发送的应答号就为 4131117137 。也就是说,服务器告诉客户端:“我已经收到了你发来的 272 个数据”。

再接下来,服务器真正的发送 HTTP 数据,包括 HTTP 头部,HTTP 网页内容:




就是这样,客户端和服务器之间就是一发送一应答确保数据发送接收的完整性。在某次得到的 TCP 数据中,将本次的序列号减去上一个序列号,那么就得到本次接收到的数据长度,从而就可以还提取出接收过来的数据,最后还原回应用层所需要接收的数据流。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 20:01 , Processed in 0.065900 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表