目录
前言
本文对网上关于TCP/IP/UDP相关内容进行收集整理,引用部分参考文献内容作为章节补充,以对相关概念作较为清晰、且完整的表述。
本文对TCP/IP理论基础进行整理,同时提供一个简单的基于FPGA实现的TCP架构、相关状态转移图。该方案仅是一种初步设想,并非完整方案,时钟复位系统也需要独立设计,仅提供初步的设计构思基础、作为参考。
1、概念梳理(以太网帧/TCP协议/IP协议/UDP协议)
1.1 IP/UDP/TCP协议报文
IP首部校验和:占16位,只检验数据报的首部、不检验数据部分(仅对IP首部20字节进行校验)。采用二进制反码求和,即将16位数据相加后,再将进位与低16位相加,直到进位为0,最后将16位取反。
TCP首部校验和:占16位,TCP校验和是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。
TCP校验和:覆盖TCP伪首部和TCP数据,而IP首部中的校验和只覆盖IP的首部,不覆盖IP数据报中的任何数据。TCP的校验和是必需的,而UDP的校验和是可选的。TCP和UDP计算校验和时,都要加上一个12字节的伪首部。
TCP伪首部:TCP校验和、IP校验和的计算方法是基本一致的,除了计算的范围不同.
首先,把伪首部、TCP报头、TCP数据分为16位的字,如果总长度为奇数个字节,则在最后增添一个位都为0的字节。
把TCP报头中的校验和字段置为0(否则就陷入鸡生蛋还是蛋生鸡的问题)。
其次,用反码相加法累加所有的16位字(进位也要累加)。
最后,对计算结果取反,作为TCP的校验和。
UDP伪首部:
UDP的校验和:包含 伪首部+数据 一起都检验。
UDP检验和的计算方法是:
- 按每16位求和得出一个32位的数;
- 如果这个32位的数,高16位不为0,则高16位加低16位再得到一个32位的数;
- 重复第2步直到高16位为0,将低16位取反,得到校验和。
源端口/目的端口 | 是0-65535任何数字,在收到请求时系统会为客户端动态分配,0-1023为知名端口号. |
报文序号 | 用来标识从TCP源端向TCP目标端发送的数据字节流,它表示在这个报文段中的数据编号,用sequence表示. |
确认序号 | 只有ACK标志为1时,确认号字段才有效,它包含目标端所期望收到源端的下一个数据编号,用acknowledge表示. |
报文长度 | 因为选项长度不确定,取值范围是5-15(20-60byte). |
URG | 紧急标志位,紧急指针有效,1表示有效. |
ACK | 确认序号有效,1表示有效. |
PSH | 推送标志位,1表示接收方应该尽快将这个报文段交给应用层,但只是整个数据的一部分并不是所有,类似收到短信提醒一样. |
RST | 1表示重新连接. |
SYN | 1表示发起一个新的连接. |
FIN | 1表示释放一个连接,finish. |
窗口尺寸(单位byte) | 此字段用来进行流量控制,这个值是本机期望下一次接收的最大长度,带伪头部的TCP报头校验和:这个是伪头部(12+20+选项长度+数据长度)16位校验值. |
紧急指针 | 它是一个偏移量(也就是先发的包长度),和报文序号字段中的值相加表示紧急数据最后一个字节的序号选项:可能包括"窗口扩大因子"、"时间戳"等选项. |
CRC | 从MAC到数据所有内容进行的CRC32校验结果,不论是传输层、网络层计算包长度时都不包含crc32这4个字节的长度,这是物理链路封包校验用的. |
1.2 TCP 首部各字段的意义和作用
(本节引用自参考文献3)
源端口和目的端口 Port
各占 2 个 字节,共 4 个字节。
用来告知主机该报文段是来自哪里以及传送给哪个应用程序(应用程序绑定了端口)的。
进行 TCP 通讯时,客户端通常使用系统自动选择的临时端口号,而服务器则使用知名服务端口号。
序号 Sequence Number
占 4 个字节。
TCP 是面向字节流的,在一个 TCP 连接中传输的字节流中的每个字节都按照顺序编号。
例如 100 kb 的 HTML 文档数据,一共 102400 (100 * 1024) 个字节,那么每一个字节就都有了编号,整个文档的编号的范围是 0 ~ 102399。
序号字段值指的是本报文段所发送的数据的第一个字节的序号。
那么 100 的 HTML 文档分割成四个等分之后,
第一个 TCP 报文段包含的是第一个 25kb 的数据,0 ~ 25599 字节, 该报文的序号的值就是:0
第二个 TCP 报文段包含的是第二个 25kb 的数据,25600 ~ 51199 字节,该报文的序号的值就是:25600
......
根据 8 位 = 1 字节,那么 4 个字节可以表示的数值范围:[0, 2^32],一共 2^32 (4294967296) 个序号。
序号增加到最大值的时候,下一个序号又回到了 0.
也就是说 TCP 协议可对 4GB 的数据进行编号,在一般情况下可保证当序号重复使用时,旧序号的数据早已经通过网络到达终点或者丢失了。
确认号 Acknowledgemt Number
占 4 个字节。
表示期望收到对方下一个报文段的序号值。
TCP 的可靠性,是建立在「每一个数据报文都需要确认收到」的基础之上的。
就是说,通讯的任何一方在收到对方的一个报文之后,都要发送一个相对应的「确认报文」,来表达确认收到。
那么,确认报文,就会包含确认号。
例如,通讯的一方收到了第一个 25kb 的报文,该报文的 序号值=0,那么就需要回复一个确认报文,其中的确认号 = 25600.
数据偏移 Offset
占 0.5 个字节 (4 位)。
这个字段实际上是指出了 TCP 报文段的首部长度 ,它指出了 TCP报文段的数据起始处 距离 TCP报文的起始处 有多远。(注意 数据起始处 和 报文起始处 的意思)
一个数据偏移量 = 4 byte,由于 4 位二进制数能表示的最大十进制数字是 15,因此数据偏移的最大值是 60 byte,这也侧面限制了 TCP 首部的最大长度。
保留 Reserved
占 0.75 个字节 (6 位)。
保留为今后使用,但目前应置为 0。
标志位 TCP Flags
标志位,一共有 6 个,分别占 1 位,共 6 位 。
每一位的值只有 0 和 1,分别表达不同意思。
紧急 URG (Urgent)
当 URG = 1 的时候,表示紧急指针(Urgent Pointer)有效。
它告诉系统此报文段中有紧急数据,应尽快传送,而不要按原来的排队顺序来传送。
URG 要与首部中的 紧急指针 字段配合使用。
确认 ACK (Acknowlegemt)
当 ACK = 1 的时候,确认号(Acknowledgemt Number)有效。
一般称携带 ACK 标志的 TCP 报文段为「确认报文段」。
TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 设置为 1。
推送 PSH (Push)
当 PSH = 1 的时候,表示该报文段高优先级,接收方 TCP 应该尽快推送给接收应用程序,而不用等到整个 TCP 缓存都填满了后再交付。
复位 RST (Reset)
当 RST = 1 的时候,表示 TCP 连接中出现严重错误,需要释放并重新建立连接。
一般称携带 RST 标志的 TCP 报文段为「复位报文段」。
同步 SYN (SYNchronization)
当 SYN = 1 的时候,表明这是一个请求连接报文段。
一般称携带 SYN 标志的 TCP 报文段为「同步报文段」。
在 TCP 三次握手中的第一个报文就是同步报文段,在连接建立时用来同步序号。
对方若同意建立连接,则应在响应的报文段中使 SYN = 1 和 ACK = 1。
终止 FIN (Finis)
当 FIN = 1 时,表示此报文段的发送方的数据已经发送完毕,并要求释放 TCP 连接。
一般称携带 FIN 的报文段为「结束报文段」。
在 TCP 四次挥手释放连接的时候,就会用到该标志。
窗口大小 Window Size
占 2 字节。
该字段明确指出了现在允许对方发送的数据量,它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
窗口大小的值是指,从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。
例如,假如确认号是 701 ,窗口字段是 1000。这就表明,从 701 号算起,发送此报文段的一方还有接收 1000 (字节序号是 701 ~ 1700) 个字节的数据的接收缓存空间。
校验和 TCP Checksum
占 2 个字节。
由发送端填充,接收端对 TCP 报文段执行 CRC 算法,以检验 TCP 报文段在传输过程中是否损坏,如果损坏这丢弃。
检验范围包括首部和数据两部分,这也是 TCP 可靠传输的一个重要保障。
紧急指针 Urgent Pointer
占 2 个字节。
仅在 URG = 1 时才有意义,它指出本报文段中的紧急数据的字节数。
当 URG = 1 时,发送方 TCP 就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。
因此,紧急指针指出了紧急数据的末尾在报文段中的位置。
1.3 TCP协议建立/关闭连接
本节引用自参考文献1.
1.3.1 建立连接
- 第一次握手:客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如是100),那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1),序列号seq=100。
- 第二次握手:服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端的起始序列号100存起来,并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
- 第三次握手:客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文;同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接。
1.3.2 断开连接
四次挥手的目的是关闭一个连接。
比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。
- 第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
- 第二次挥手:服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
- 第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
- 第四次挥手:客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。
1.4 确认应答机制
首先,需要理解确认应答机制;其次,需要理解:“确认应答机制” 与 “ACK有延迟确认机制”之间的关系。
1.4.1 确认应答机制
每一个ACK都带有对应的确认序列号,意思是告诉发送者,我们已经收到了哪些数据,下一吃发送数据应该从哪里开始。 如上图,主机A给主机B发送了1-1000的数据,ACK应答,携带了1001序列号。告诉主机A,我已经接受到了1-1000数据,下一次你从1001开始发送数据。
1.4.2 ACK延迟确认机制
TCP协议中,接收方成功接收到数据后,会回复一个ACK数据包,表示已经确认接收到ACK确认号前面的所有数据。ACK字段长度为32位,能表示0~2^32-1之间的值。
发送方在一定时间内没有收到服务端的ACK确认包后,就会重新发送TCP数据包。发送方收到了ACK,表明接收方已经接收到数据,保证了数据的可靠达到。
接收方在接收到数据后,不是立即会给发送方发送ACK的。这可能由以下原因导致:
1、收到数据包的序号前面还有需要接收的数据包。因为发送方发送数据时,并不是需要等上次发送数据被Ack就可以继续发送TCP包,而这些TCP数据包达到的顺序是不保证的,这样接收方可能先接收到后发送的TCP包(注意提交给应用层时是保证顺序的)。
2、为了降低网络流量,ACK有延迟确认机制。
3、ACK的值到达最大值后,又会从0开始。
接收方在收到数据后,并不会立即回复ACK,而是延迟一定时间。一般ACK延迟发送的时间为200ms,但这个200ms并非收到数据后需要延迟的时间。系统有一个固定的定时器每隔200ms会来检查是否需要发送ACK包。这样做有两个目的。
1、这样做的目的是ACK是可以合并的,也就是指如果连续收到两个TCP包,并不一定需要ACK两次,只要回复最终的ACK就可以了,可以降低网络流量。
2、如果接收方有数据要发送,那么就会在发送数据的TCP数据包里,带上ACK信息。这样做,可以避免大量的ACK以一个单独的TCP包发送,减少了网络流量。
一、ACK定义
TCP协议中,接收方成功接收到数据后,会回复一个ACK数据包,表示已经确认接收到ACK确认号前面的所有数据。
ACK字段长度为32位,能表示0~2^32-1之间的值。
二、ACK作用
发送方在一定时间内没有收到服务端的ACK确认包后,就会重新发送TCP数据包。发送方收到了ACK,表明接收方已经接收到数据,保证了数据的可靠达到。
三、ACK机制
接收方在接收到数据后,不是立即会给发送方发送ACK的。这可能由以下原因导致:
1、收到数据包的序号前面还有需要接收的数据包。因为发送方发送数据时,并不是需要等上次发送数据被Ack就可以继续发送TCP包,而这些TCP数据包达到的顺序是不保证的,这样接收方可能先接收到后发送的TCP包(注意提交给应用层时是保证顺序的)。
2、为了降低网络流量,ACK有延迟确认机制。
3、ACK的值到达最大值后,又会从0开始。
四、ACK延迟确认机制
接收方在收到数据后,并不会立即回复ACK,而是延迟一定时间。一般ACK延迟发送的时间为200ms,但这个200ms并非收到数据后需要延迟的时间。系统有一个固定的定时器每隔200ms会来检查是否需要发送ACK包。这样做有两个目的。
1、这样做的目的是ACK是可以合并的,也就是指如果连续收到两个TCP包,并不一定需要ACK两次,只要回复最终的ACK就可以了,可以降低网络流量。
2、如果接收方有数据要发送,那么就会在发送数据的TCP数据包里,带上ACK信息。这样做,可以避免大量的ACK以一个单独的TCP包发送,减少了网络流量。
1.5 超时重传机制
首先,需要理解超时重传机制;其次,需要理解 “ 超时重传机制 ” 与 “ACK有延迟确认机制”之间的关系。
那么发送方发送完毕后等待的时间是多少呢?如果这个等待的时间过长,那么会影响TCP传输的整体效率,如果等待时间过短,又会导致频繁的发送重复的包。如何权衡?
由于TCP传输时保证能够在任何环境下都有一个高性能的通信,因此这个最大超时时间(也就是等待的时间)是动态计算的。
注意:超时以500ms(0.5秒)为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍。重发一次后,仍未响应,那么等待2*500ms的时间后,再次重传。等待4*500ms的时间继续重传。以一个指数的形式增长。
累计到一定的重传次数,TCP就认为网络或者对端出现异常,强制关闭连接。
1.5.1 超时重传机制
由于TCP存在一个确认应答机制,所以每次发送端发送一个数据之后,都应该收到一个ACK应答,如果没有收到,发送端就需要重新发送数据。发送端没有接收到ACK应答有可能是发送时网络拥堵没有发送出去,但也有可能对端发送来的ACK在中途丢失了,这样的话就会导致发送端重新发送重复的数据到接收端。这时TCP协议报中的序列号就起到了至关重要的作用,接收端在接收到数据之后,通过核对序列号可以起到一个去重的效果。
主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B; 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发;
因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉. 这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果.
2、TCP/IP数据传输方案
本节仅是提供一种设计构思,没有具体实现。可以参考文献11,使用Xilinx 三速以太网MAC IP核来实现TCP/IP通信。
核心思想:
通过CTRL_LOGIC模块来控制发送接收模块的工作状态。
CTRL_LOGIC模块控制收发模块实现:“ 建立TCP连接 ” 、 “ 数据双向传输 ” 、“ ACK延迟确认 ” 、 “ 超时重传 ” 、“ 发送/接收模块数据校验 ”,通过上述这几种功能来保证FPGA通过TCP/IP与PC传输之间的可靠性!
2.1 TCP架构
2.2 TX发送模块状态控制
START状态:实现ip_head/tcp_head的组装;
TCP_DATA_CHECK:实现数据校验计算;
IP/TCP_CHECK:实现IP/TCP首部校验和计算;
SEDN_55:发送前导码
SEDN_MAC:发送MAC地址
SEND_IP_HEAD:发送IP首部
SEND_TCP_HEAD:发送TCP首部
SEND_DATA:发送数据
SEND_OPTION:发送option
SEND_CRC:发送CRC校验
2.3 CTRL_LOGIC模块状态控制
通过该模块实现对收发模块的控制,从而实现TCP的可靠传输。
参考博文
作者 | 博客 |
1、爱前端不爱恋爱 | TCP/IP三次握手四次挥手 |
2、ythunder | TCP/IP报文头部结构整理 |
3、JC_Huang | 理解 TCP(二):报文结构 |
4、M、k | TCP数据包协议格式详解 |
5、hushhw | 计算机网络笔记 |
6、zhangskd | TCP校验和的原理和实现 |
7、stone_Yu | UDP校验和计算 |
8、alifpga | TCP报文送达确认ACK |
9、三个臭皮匠半个我 | 简谈TCP——确认应答、超时重传 |
10、Lucky& | TCP协议如何保证可靠传输 |
11、没落骑士 | 浅析Xilinx 三速以太网MAC IP核(仿真篇) |