传输层协议TCP(2)
• [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用 close), 服务器会收到结束报文段, 服务器返回确认报文段并进入 CLOSE_WAIT;• [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入 FIN_WAIT_2, 开始等待服务器的结束报文段;• [FIN_WAIT_2 -> TIME_WAIT] 客户端收
传输层协议TCP(2)
TCP 协议段格式
16位窗口大小是用来缓冲剩余空间的大小,这个窗口是记录自己的空间大小,
发送端如何知道对方的接受能力,需要知道一个概念叫流量控制,也就是我们知道对方缓冲区的剩余空间大小,我们所创建的报文都是给对方的
标志位:本质是报头的比特位
为什么要有标志位?
申请建立连接的时候,要有表示报文类型的字段,接收方接收的报文一定是不同类型的,需要我们接收方有不同的做法
6 位标志位:
○ URG: 紧急指针是否有效
○ ACK: 确认号是否有效
○ PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
○ RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段
同步标志位:建立连接,握手过程使用的标志位
前两次握手,不能携带数据,因为三次握手还没有完成,三次握手已经到了双方可以协商的地步
ACK表明报文是一个应答报文,ACK几乎设为1
连接建立成功是否一致,可能有时间差
URG特定偏移量,只有一个字节,表示状态码
确认应答(ACK)机制
TCP 将每个字节的数据都进行了编号. 即为序列号.
每一个 ACK 都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.
超时重传机制
• 主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机 B;
• 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发;
但是, 主机 A 未收到 B 发来的确认应答, 也可能是因为 ACK 丢失了;
因此主机 B 会收到很多重复数据. 那么 TCP 协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.
这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.
那么, 如果超时的时间如何确定?
• 最理想的情况下, 找到一个最小的时间, 保证 “确认应答一定能在这个时间内返回”.
• 但是这个时间的长短, 随着网络环境的不同, 是有差异的.
• 如果超时时间设的太长, 会影响整体的重传效率;
• 如果超时时间设的太短, 有可能会频繁发送重复的包;
TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.
• Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.
• 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
• 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
• 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接
连接管理机制
在正常情况下, TCP 要经过三次握手建立连接, 四次挥手断开连接
服务端状态转化:
• [CLOSED -> LISTEN] 服务器端调用 listen 后进入 LISTEN 状态, 等待客户端连接;
• [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送 SYN 确认报文.
• [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED 状态, 可以进行读写数据了.
• [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用 close), 服务器会收到结束报文段, 服务器返回确认报文段并进入 CLOSE_WAIT;
• [CLOSE_WAIT -> LAST_ACK] 进入 CLOSE_WAIT 后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用 close 关闭连接时, 会向客户端发送FIN, 此时服务器进入 LAST_ACK 状态, 等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN)
• [LAST_ACK -> CLOSED] 服务器收到了对 FIN 的 ACK, 彻底关闭连接.
客户端状态转化:
• [CLOSED -> SYN_SENT] 客户端调用 connect, 发送同步报文段;
• [SYN_SENT -> ESTABLISHED] connect 调用成功, 则进入 ESTABLISHED 状态, 开始读写数据;
• [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用 close 时, 向服务器发送结束报文段, 同时进入 FIN_WAIT_1;
• [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入 FIN_WAIT_2, 开始等待服务器的结束报文段;
• [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出 LAST_ACK;
• [TIME_WAIT -> CLOSED] 客户端要等待一个 2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入 CLOSED 状态
connect参与三次握手,accept不参与
为什么要进行三次握手?
以最小的成本确认双方100%愿意通信
以最短的方式验证全双工
三次握手的本质是四次应答
更多推荐
所有评论(0)