一个TCP连接由4个元组组成:2个ip地址和2个端口号
tcp三次握手
为什么是三次握手
解决历史连接问题
- 通过三次握手才能阻止重复历史连接的初始化
- 通过三次握手,才能对通讯双方的初始序号初始化
如果只有2次握手,发送方一旦发送创建连接的请求就无法撤回,如果网络环境较差,发送方连续发送多次连接请求,如果只有2次通信,接收方只能接受或者拒绝请求,且接收方不知道这个请求是不是历史请求。
所以通过三次握手和引入RST机制,接收方接到请求时会将发送方发来的seq+1发送给对方,此时由发送方来判断连接是否是历史连接
- 如果是历史连接(seq过期或者超时),发送方会发送RST控制消息终止这次连接
- 如果不是历史连接,发送方发送ack,完成连接的建立
解决序号问题
通信双方都需要获得一个用于发送信息的初始化序号,需要向对方发送syn并携带自己的期望的初始化序号,对方在收到后会回复ack以及seq+1 来确认
TCP 半关闭
同时打开
同时打开需要4次数据交换
同时关闭
初始化序号
初始化序号会随时间的变化而变化,每个连接拥有不同的初始化序号。
一个TCP连接只有具备了4元组与当前窗口序号,才会被对方认为是正确的
建立连接超时
TCP为了建立连接频繁以指数回退的方式的发送SYN报文段,一些系统可以配置SYN的次数
TCP 选项
最大段大小选项
指的是TCP协议允许的从对方收到的最大报文段。这是通信对方在发送数据时能够使用最大报文段,最大段只记录了TCP数据的字节数不包括TCP和IP头部。当创建TCP连接时,通信的每一方都要在SYN报文段的MSS选项中说明自己允许的最大段大小。在没有事先指明的情况下,最大段默认大小为546字节(任何主机都能处理至少576字节(546+ 20 + 20))字节的ip数据报
选择确认选项
由于ack采用累积,TCP不能正确的确认之前已经接收之前已经收到的数据。如果发送方能够了解接收方当前的空洞,它就能在报文丢失或者遗漏时更好的进行重传。 TCP 选择确认(SACK)提供了上述功能。通过接收SYNC(SYNC+ACK)报文段中的允许选择确认选项。使用SACK选项用来来描述这些乱序的数据。从而帮助对方有效的重传
TCP最大传输单元发现
最大传输单元:两台主机之间路径的所有网络报文段中最大传输单元的最小值
发现过程:在一个连接建立时,TCP使用对外接口的最大传输单元的最小值,或者根据通讯对方的声明的最大段大小来选择发送方的最大段大小。路径最大传输单元不允许TCP发送方有超过另一方所声明的最大段大小的行为。如果对方没有指明最大段大小的数值,发送方将假设使用默认的536字节。注意,一条连接的两个方向上的最大段大小是不同的。
一旦发送方的最大段大小选定了初值,TCP通过这条连接发送的所有IPV4数据报都会对DF字段进行设置。如果收到PTB消息,TCP就会较少段的大小,然后用修改过的段进行重传。如果PTB中包含了下一跳的推荐最大传输单元,段大小可以设置为下一跳的最大传输单元减去IPV4(IPV6)与TCP头部的大小。如果不包含最大传输单元,发现和需要尝试多次
由于路由是动态变化的,在减少段大小的一段时间后,需要尝试一个更大的数值
TCP状态转换
FIN_WAIT_1 、FIN_WAIT1、TIME_WATI 称做主动关闭,表示当本地程序发起一个关闭请求时,会进入的状态集合
CLOSEWAIT、LASK_ACK 称作被动关闭。
从LISTEN 到 SYN_SENT 的状态转换是合法的
从SYNC_RCV返回到LISTEN的状态只有在SYNRCVD状态是有LISTEN状态而非SYN_SENT状态转换而来的情况下才是正确的。这意味着一个被动打来操作(进入LISTEN状态)接收一个SYN,发送一个带ACK确认的SYN(进入SYN_CRVD)状态,然后收到一个重置消息而非ACK,端点就会返回到LISTEN状态,并等待另一个请求的。
TIME_WATI状态
在该状态中,TCP将会等待2倍最大段生存期。当TCP发送一个主动关闭的并发送最终的ACK时,连接必须处于TIME_WATI并报出2倍最大段生存期
TIME_WAIT仅在主动调用的一方出现,被动调用的一方会直接进入CLOSED状态。需要等待2MSL的原因是
- 防止延迟的数据段被其他使用相同源地址、源端口。目的地址。目的端口的TCP收到
- 保证TCP连接的远程被正确关闭
延迟数据段
为了保证新的TCP连接的数据段不会与还在网络中传输的历史连接的数据段重复,TCP连接在分配新的序列号之前需要至少静默数据段在网络中存活的最长时间
2MSL的原因是,网络中可能存在来自发起方数据段,当这些发起方的数据段被服务端处理后又会想客户端发起响应。所以一来一回需要2MSL
FIN_WAIT2 状态
在该状态,某TCP通讯端已经发送FIN,并已得到另一端的确认。除非出现半关闭状态,否则该TCP端将会等待另一端识别出自己已经收到一个文件末尾的通知并关闭这一端引起发送FIN连接。
同时打开和关闭的转换
同时打开
通信双方几乎同时想对方发送SYN报文段,然后进入SYNCSENT。当他们收到对方的SYN会进入到SYN_CRVD。然后重新发送一个新的SYN并确认之前收到的SYN。当通信两端都收到了SYN和ACK时,他们的状态都将变为ESTABLISED
同时关闭
两端同时从ESTABLISED变为FIN_WATI_1,同时他们都会向地方发送FIN,在接收到对方发来的FIN后,两端变成CLOSED状态,然后发送都发送ACK,当双端接收到ACK后,每个端都会将状态改为TIME_WAIT,从而初始化2MSL
重置报文段
当发现一个到达的报文段对于相关连接而言不是正确的,TCP就会发送一个重置报文段。
当一个请求到达本地没有相关的进程在目的端口监听时就会产生一个重置报文段。
半开连接
在未知另一端的情况下,通信的一端关闭或终止连接,那么认为该条TCP连接为半开连接。只要不通过半开连接传递数据。正常工作的一端不会检测出另一端已经奔溃
时间等待错误
等待的一端不需要做任何操作,只需要维持当前的状态到2MSL的计时结束。如果他在这段时间内接收到来自于这条连接的一些报文,或是更加特殊的重置报文。它将被破坏。这种情况称作时间等待错误。
连接队列
一个并行的服务器会为每一个客户端分配一个新的进程或线程。在被用于应用程序之前可能会处于 1. 尚未完成但已经接收到SYN (SYNC_CRVD)。 2. 已经完成3次握手处于(ESTABLISHED)。在内部操作系统用2个不同的连接队列分别对应上述2中情况。
- 当一个连接请求到达(SYN报文),将会检查系统参数net.ipv4.tcp_max_synbacklog。如果处于SYN_CRVD的个数超过这个阀值,进入的连接将会被拒绝
- 每一个处于监听状态下的节点都有一个固定长度的连接队列,其中的TCP连接已经被接受,但未被应用程序接受。
- 如果监听节点的队列有空间存储新的连接,TCP模块完成连接 客户端可能会认为服务器已经准备好接收数 据,然而服务器上的应用程序此时可能还未收到关于新连接的通知。如果这种情况发生,服 务器的TCP模块将会把到来的数据存人队列中
- 如果队列中已经没有足够的空间存放新的连接,TCP将会延迟对SYN的响应。