以下为一些常见的TCP/IP问题总结:
OSI与TCP/IP各层的结构与功能
互联网主要分为五层:
- 物理层:通过线路(可以是有形的线也可以是无线链路)传送原始的比特(bit)流,只完成一个节点到另一个节点的传送(单跳)
- 数据链路层:通过物理网络传送帧,只完成一个节点到另一个节点的传送(单跳)(hop-by-hop, node-to-node)
- 网络层:把包里面的目的地址拿出来,进行路由选择(routing),决定要往哪个方向传输,负责从源(source)通过路由选择到目的地(destination)的过程,达到从源主机传输数据到目标主机的目的(host-to-host)
- 传输层:也称为端到端传输,网络层只把数据送到主机,但不会送到进程。传输层负责负责进程与主机(host)间的传输,主机到主机(host-to-host)的传输交由网络层负责。在七层模型中,传输层还可以细分为会话层和展示层:
- 会话层:通过数据流建立会话关系
- 展示层:数据压缩、解压,加密、解密,数据类型、格式变换等一切与数据展示有关的操作
- 应用层:专门针对某些应用提供服务
网络层有如下协议:
传输层主要有TCP(传输控制协议)与UDP(用户数据报协议)两种协议。
应用层有如下协议:
TCP与UDP的区别
TCP即传输控制协议,UDP即用户数据报协议,他们的区别主要有以下几点:
- TCP协议是面向连接的,发送数据之前需要建立连接;UDP协议是无连接的,发送数据之前不需要建立连接
- TCP协议提供可靠的传输服务;UDP协议提供不可靠的传输服务
- TCP发送数据大小会受发送窗口、接收窗口及MSS(最大报文段)限制,因此会分为多段发送;UDP发送数据大小即为数据本身大小
- TCP拥有众多反馈机制与附加机制;UDP没有反馈机制
- TCP传输速度较慢;UDP传输速度较快
总的来说,TCP协议提供面向连接的,可靠的传输服务,但速度较慢,适合文件下载等传输任务;UDP协议提供无连接的,不可靠的传输服务,但速度较快,适合媒体流等看重传输速度的传输任务。
TCP报文结构
TCP段结构如下:
其中:
- Source port:源端口,16位,说明发送端的端口号
- Destination port:目的端口,16位,说明接收端的端口号
- Sequence number:序列号,32位,说明这个数据的序号,从而接收端接收后可以进行排序,避免接收错序
- Acknowledgement number:确认号,ACK,32位,表示说明这是对哪个数据的确认,表明期待接收编号为x的数据段,小于x的数据段已经成功接收并交给了上层
- TCP header length:TCP头部长度,4位,由于TCP头部中带有option,而option的长度不固定,因此需要标识头部的长度
- 0(灰色那段):padding,6位,无实际作用
- 标志位:6位,作用分别如下:
- URG:说明数据部分是否有紧急数据,可能导致乱序问题,因此并不会在实际中被使用
- ACK:说明确认号是否有效
- PSH:告诉接收方将缓冲区的数据尽快交给上层,可能会导致数据丢失,因此不会在实际中被使用
- RST:重置连接,将连接强制中断
- SYN:同步标识,建立连接时使用
- FIN:结束标识,关闭连接时使用
- Window size:窗口大小,16位,发送端告诉接收端自己的发送窗口的缓冲区大小
- Checksum:校验和,16位
- Urgent pointer:紧急数据指针,16位,说明数据段中哪一段数据是紧急数据
- Options:0或32位,选项部分
- Data:数据部分
TCP的三次握手与四次挥手过程
TCP三次握手
其示意图如下:
三次握手是指TCP建立连接的过程,顾名思义,主要分为3个步骤:
- 客户机发起请求
- SYN为1:说明发起新的连接
- SEQ为x:说明这个段的序列号是多少,服务器收到后会调整接收的滑动窗口为x+1(表明下一次要接收的段的序列号为x+1),一般随机选取x
- 指定窗口大小的值:客户机说明自己的接收窗口目前还可容纳多少数据
- 服务器响应请求
- ACK为1:表示确认接收请求
- ACK号为x+1:表示接受了序列号位x及以下的数据,期待序列号为x+1的数据
- SYN为1:说明服务器同意新的连接建立(只是同意,还没有没有分配端口资源)
- SEQ为y:说明这个段的序列号是多少,客户机收到后会调整接收的滑动窗口为y+1(表明下一次要接收的段的序列号为y+1),与x没有关系
- 指定窗口大小的值:服务器说明自己的接收窗口目前还可容纳多少数据
- 服务器响应请求
- ACK为1:表示确认接收请求
- ACK号为y+1:表示接受了序列号位y及以下的数据,期待序列号为y+1的数据
- SEQ为x+1:说明这个段的序列号是多少,服务器收到后会调整接收的滑动窗口为x+2(表明下一次要接收的段的序列号为x+2)
看完三次握手我们不禁有疑问,为什么需要三次握手呢?一次握手,两次握手为什么不行呢?
原因如下:
- 一次握手:客户机根本不知道连接的有效性
- 有可能这次握手请求根本没有到达服务器或者直接被服务器拒绝
- 两次握手:服务器无法确认该请求的合法性,如果是两次握手服务器将立即分配端口资源造成资源浪费,可能使得其它客户机无法连接
- 发送方请求连接的包在信道里面停留了很长时间,使得连接都释放掉了这个包才到
- 会遭遇SYN泛洪攻击:一台恶意的主机伪造自己的IP向服务器请求连接
TCP四次挥手
其示意图如下:
TCP四次挥手是指TCP释放连接的过程,顾名思义,主要分为4个步骤:
- 释放连接的发起方发起释放连接请求
- FIN为1:结束位为1,说明发起方的发送过程已经结束,不会再向对方发送实际数据
- SEQ为x:序列号为x
- 释放连接的接收方回复释放连接请求
- ACK为1:表示确认接收请求
- ACK号为x+1:表示接受了序列号位x及以下的数据,期待序列号为x+1的数据
- 释放连接的接收方同意释放连接请求
- FIN为1:结束位为1,说明发起方的发送过程已经结束,不会再向对方发送实际数据
- SEQ为y:序列号为y
- 释放连接的发起方回复释放连接请求
- ACK为1:表示确认接收请求
- ACK号为y+1:表示接受了序列号位x及以下的数据,期待序列号为y+1的数据
发起方在第四次握手发出ACK后会等待一段时间后再正式释放连接,这段时间被称为TIME_WAIT。会有TIME_WAIT的原因主要是保证接收方能够收到对于FIN的ACK,如果ACK在返回的过程中丢失会导致接收方超时,这时会再发一个FIN给到发起方,因此这一段时间正好是ACK返回时间加上重发的FIN到达发起方的时间。另一个原因是如果没有TIME_WAIT就马上建立了新的连接,那么网络中遗留下来的旧的数据包将可能会干扰接收方的接收,接收方无法识别出是新的数据包还是旧的数据包,因此在TIME_WAIT接收到的其它数据包会被丢弃。
其实TCP释放连接的方法除了四次握手外还有直接重置RST的强制释放方法,在此不再赘述。
TCP拥塞控制
由于发送方到接收方之间的信道是公用的,因此如果发送方不考虑中间信道的容量随意发送就可能出现拥塞,拥塞会导致延迟严重,甚至大量丢包,因此我们需要进行拥塞控制。
拥塞控制的关键在于控制发送端的发送速率,发送端的发送速率受到发送窗口大小的限制,因此在TCP的拥塞控制中实际控制的是发送端的发送窗口大小。
当出现以下两种情况之一时,我们断定传输出现了拥塞:
- 连续(三个)的序号为x的ACK:说明序号为x的TCP数据段很可能丢失
- 超时时间到来前未收到ACK
当出现拥塞时,我们主要有以下方法进行拥塞控制:
为了防止拥塞窗口大小增加过快而导致网络拥塞,我们会设置一个慢开始门限状态变量:
- 当拥塞窗口大小 < 慢开始门限,使用慢启动算法
- 当拥塞窗口大小 > 慢开始门限,使用拥塞控制算法
- 当拥塞窗口大小 == 慢开始门限,使用两个算法都可以
AIMD
AIMD(additive increase multiplicative decrease)是一个拥塞控制算法,其意思即加性增加乘性减少,其初始拥塞窗口大小为任意值。
当我们每成功传输一个TCP数据段,拥塞窗口大小加1MSS(最大报文大小),此为加性增加;而当我们发现传输出现拥塞时,拥塞窗口大小减半,此为乘性减少。
这种算法的问题在于增加的速度慢,丢包代价大。
慢启动
慢启动的初始时拥塞窗口大小为1MSS(因此叫慢启动算法),最大为65535MSS(窗口大小只有16bit,因此最大也只能这么大)。慢启动算法开始时每成功传输一个TCP数据段,拥塞窗开大小也是增加1MSS,但当其发现拥塞时,会首先确定一个阙值:阙值为当前窗口大小的一半,然后根据不同的机制进行处理:
- Tahoe机制:出现拥塞时窗口大小会变回1MSS,但当窗口大小小于阙值时,传输成功窗口大小加倍(指数增长),大于阙值后改为加性增长。
- Reno机制:出现拥塞窗口大小直接变为阙值。(也称为快速恢复机制)