TCP-简述

TCP是一种ARQ协议,即使当数据没能成功发送给对方的时候,就重试。

Another is to simply “try sending again” until the information is finally received. This approach, called Automatic Repeat Request (ARQ), forms the basis for many communications protocols, including TCP.

链路中的情况十分复杂,除了基本的比特位错误以外,还有其他错误包括:分组的乱序,分组的重复,分组的丢失。所以一个在不可靠的IP协议之上的协议必须能够处理这些问题。

对于分组丢失的最直接的方法就是重新发送,于是就引入了两个问题:

  1. 要知道对方是否已经接受了整个分组
  2. 对方刚接收的分组是否为之前已经发送过的,即发送方是否发送了重发的分组

发送方用于通知发送方它已经正确接收的方法叫作:确认(acknowledgment)简称为ACK。最简单的方法就是:发送方发送一个分组(packet),接收方返回一个ACK,一直这样下去。于是又引入了几个问题:

  1. 发送方等待来自接收方的ACK要等多久? (如果一直不来,那它就发不下去了)
  2. 如果ACK丢失怎么办?
  3. 如果分组被接收了,但是有些错误怎么办?

第一个问题,可以说,发送方最多可以期待多久来自接收方的ACK?这里我将会在14章介绍

第二个问题,如果ACK丢失怎么办?对于这种情况,发送方根本无法区分到底是分组丢失还是ACK丢失,所以重新发送即可。

第三个问题,我们可以使用经典的校验和(checksum)或者说CRC检测来对数据判断是否有错。当接收到的数据有错误的时候,就不发送ACK,最终会导致发送方重新发送数据。

即使是现在这种最简单的协议,我们还不知道如何处理重复的数据。即已经被接受数据,但是可能因为ACK丢失而导致发送方重新发送的数据。为了解决这个问题,我们就引入了序列号(sequence number),每一个分组都有自己的序列号,接收方使用序列号来判断数据是否已经被正确接收。

就目前描述的协议来说,还是不够有效的,因为此时的协议是停等的(stop and wait)。意思是:每发一个分组,就要等待属于它的ACK,效率低下。所以,我们希望在一段时间以内发送方可以发多一点数据到链路中。于是一个新的问题又被引入:

  1. 往链路中塞多少分组才合适?
  2. 等待ACKs的timer要等多久?
  3. 而且,对于已经发送但是还未被ACKed的数据,需要保存在缓存中,不能直接丢弃。

所以对于发送者来说,它需要有方法知道哪些数据被发送了,哪些被ack了。因为发送方发数据的速度更快了,不可避免的会导致到达接收方数据的乱序,所以接收方持有缓存来保存这些乱序数据,而不是暴力的直接丢弃,效率低下。还有其他问题:如果接收方的处理速度慢于发送方怎么办?如果接收方放不下了就直接将数据丢弃掉,那么同样的情况也会发生在路由器中,所以也需要引入机制来使得发送方和接收方之间可以交互,控制速度。

滑动窗口和windowing packets

首先我们引入窗口的概念(window),窗口只是一组被发送但是还未被确认的数据的集合。

滑动窗口

这就是一个简单的窗口,最多可以持有三个分组,当数据被ack之后,窗口就可以往右前进(sliding)一个。这就是所谓滑动窗口。

就是这样简单的窗口一下子就解决了不少问题“

对于发送方来说,它可以知道哪些数据已经被接收了(小于窗口左边界的数据都是被接收的),哪些在等待ack(窗口内部的都是在等待ack),哪些还未被发送(大于窗口有边界都是等待被发送)。

对于接收方来说,小于左边界的是被ACKed的数据,窗口内部的是可以被接收方填充的缓冲区。

可变窗口

为了解决发送方发的太快而导致接收方来不及处理的问题,我们通过流量控制(flow control)的方法来解决这个问题。在TCP中,主要是通过改变窗口大小来控制流量的,即在TCP中窗口的大小并不是固定的。

为了实现这种方法,在TCP中使用了一种叫作window advertisment 或者叫 window update。TCP接收方通过这个值来改变它的窗口大小。通常来说,window update的和前面所说的ACK报文有些区别,但是在实际中,window update和ACK通常会一起发送

这种方法对于接收方和发送方来说是挺好的,但是对于网络中的路由器就不好了,所以又需要引入一种新的机制来使得中间的路由器放不下数据而丢弃,这个过程叫做拥塞控制(congestion control)。

PS:流量控制针对的是双方,而拥塞控制针对的是链路中的路由器。

Retransmission Timeout

需要对超时的时间做一个估计,这里涉及到多种方法。

Introduction to TCP

TCP的服务模型:

虽然TCP和UDP位于同一层网络模型中(传输层),但是TCP和UDP完全不同。TCP是称为面向链接的,即需要使用TCP链接的应用必须经过握手才可以。

The term connection-oriented means that the two applications using TCP must establish a TCP connection by contacting each other before they can exchange data.

TCP提供的是字节流,它不知道内部数据是什么,也不会在两个分组之间插入分界(boundary)。所以当发送方分三次发了10,20,50字节数据的时候。对方可能20,20,20,20分四次读取,取决于应用选择了要读多少字节。它并不知道这些代表着什么,当然也可能一次就读取完毕。所以网上所谓粘包的说法真是太呆了。

TCP并不会解释它所传送的数据是什么,对于数据如何解释交给应用层协议来做。

TCP中的可靠性:

TCP使用目前所提到方法来保证可靠性(序列号,确认机制,超时重传,滑动窗口等)。因为TCP读取的是来自应用数据的字节流,而IP接收的数据固定大小的报文段,因此TCP必须将字节流包装为IP可以承载的数据,这过程叫作packetization,这些分组包含着序列号,序列号代表着字节在应用数据流中的偏移(offset)。

This is called packetization. These packets contain sequence numbers, which in TCP actually represent
the byte offsets of the first byte in each packet in the overall data stream rather than packet numbers.

此外,这就使得发送的数据可以变大小的,单次发送的数据只要小于IP可以承载的即可,所以这也意味着小的数据可以被合并,这个过程叫作(repacketization)。TCP发送给IP的数据不会分片(恰好等于一个IP可以承载的数据大小),而UDP数据发送给就是来自应用的数据多大就是多大,因此会导致数据的分片。

TCP内部有一个校验和(checksum),它是由伪首部计算而得(pseudo-header),伪首部包括:应用数据,IP报文的字段,TCP报文的字段。如果校验和计算后发现有错,就直接将报文丢弃。

TCP maintains a mandatory checksum on its header, any associated application data, and fields from the IP header

但是有资料显示,对于大数据传输来说,校验和并不是那么的准确。—-这里看625页所引用的资料,[SP00]

当TCP发送一组报文段(segment,而不是packets)的时候,会使用一个(single)计时器,而不是对每一个segment都启用一个计时器。每当一个ACK到达的时候,就会重新设置定时器,否则如果定时器超时了,那么就直接重传。

累计确认,并不是成功接受一个数据就返回一个ACK,通常也会有一点延迟。TCP使用的ACK是累计的(cumulative),也就是说ACK N表示着到到N之前的所有数据都已经被正确接收了,这提供了很好的稳定性。因为,如果ACK < N丢失了,但是ACK N正确接收了,就可以知道N之前的都是正确接收的。

This provides some robustness against ACK loss—if an ACK is lost, it is very likely that a subsequent ACK is sufficient to ACK the previous segments

因为TCP底层使用的是IP协议,对于数据的顺序并没有什么保证。然而TCP永远不会给应用程序发送乱序的数据,所以如果接收到了乱序的数据,TCP必须让序列号较大的数据等待着序列号小的数据填充了这个”洞(hole)“之后才可以给应用程序。

TCP header and encapsulation

一个典型的TCP 分组结构如下:

报文结构

如果不包含选项,那么就是20字节的IP头,20字节的TCP头,剩下的都是数据。如果包含着选项(options),那么TCP报文头最多可以达到60字节。

下图是一个TCP头的结构:

TCP 报文的各个字段

报文头中包含着目标以及源端口号,再加上IP报文中的目标以及源IP地址,就能够唯一的鉴别一个连接,这个通常叫做四元组(four-tuple)。

Each TCP header contains the source and destination port number. These two values, along with the source and destination IP addresses in the IP header, uniquely identify each connection.

序列号(sequence number)是用来标识数据的,它通常表示这改字节在TCP字节流中的位置(相对的,因为初始序列号并不是从0开始),这是一个无符号数,到达$2^{32}-1$之后回卷到0。

确认号(acknowledgment number)指示的是下一个希望让发送方发送的序列号,所以确认号等于最后一个被正确接收的字节+1。比如,从N开始发送M字节的数据,那么返回的ACK=N+M+1。序列号字段只有在ACK位 =1的才有效,基本的TCP报文段都是这样的,除了初始建立(initial)和关闭(closing)的。

当一个需要建立一个链接,报文的SYN = 1,这时候的序列号并不是简单的0或者1,通常是一个随机数,叫作ISN(initial sequence number),这通常和安全性相关的。

The sequence number of the first byte of data sent on this direction of the connection is the ISN plus 1 because the SYN bit field consumes one sequence number

这里我的理解是,TCP只对有附带数据的分组会重传,所以就让SYN占据一个字节,这样就能使得丢失的SYN触发重传。

TCP可以描述为,累计确认的滑动窗口协议,ACK number表示的是在接收端最大被正确接收的序列号+1。面对乱序的数据,TCP会采用选择确认的机制,相对应的TCP发送方也会实现选择重传(selective repeat)。

报文头是以32bit的字(word)为单位的,4bit最多可以表示0xf。所以4*15=60字节,因此TCP报文头的最大长度就是60字节。

8个比特位的意思:

CWR–Congestion Window Reduced (the sender reduced its sending rate),

ECE—ECN Echo (the sender received an earlier congestion notification)

URG—Urgent (the Urgent Pointer field is valid—rarely used)

ACK—Acknowledgment (the Acknowledgment Number field is valid always on after a connection is established);

PSH—Push (the receiver should pass this data to the application as soon as possible—not reliably implemented or used)

RST—Reset the connection (connection abort, usually because of an error)

SYN—Synchronize sequence numbers to initiate a connection

FIN—The sender of the segment is finished sending data to its peer

窗口大小(window size)字段用于流量控制,窗口大小表明对方的缓冲区还有还有多少空闲的地方,16bit最多可以存放65535字节的数据,由此来限制TCP的吞吐量(如果缓冲区为0,那么就会导致发送方无法再继续发送数据),但是窗口大小是可以通过option中的字段扩展的

校验和(checksum)是计算伪首部的校验和的,所采用的算法和其他协议中的校验和计算方式类似。

紧急指针(urgent pointer)只有在URG = 1的时候才有用,它和序列号加在一起组成了最后一个紧急数据(urgent data)的序列号。

This “pointer” is a positive offset that must be added to the Sequence Number field of the segment to yield the sequence number of the last byte of urgent data.

选项(options)中最常用的是Maximum Segment Size,称为MSS,通常在第一个报文(SYN 报文)的时候中使用。另外一个常用的选项就是SACK了。

TCP中的数据段是可选的,也就是说可以发送不带任何数据的TCP报文。pure ACK和window update都是这类报文。

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇