本篇文章主要对TCP原理进行简单的分析和讨论。
TCP套接字中的I/O缓冲
前文有介绍过TCP通信数据无边界的特性,即本端一次发送的数据对端并不一定一次性接收,那剩余的数据在哪里呢?
实际上,write函数调用后并非立即传输数据,read函数调用后也并非马上接收数据。如下图所示,write函数调用瞬间,数据将移至输出缓冲区(适当的时侯传向对方的输入缓冲);read函数调用瞬间,从输入缓冲区读取数据。
TCP套接字的I/O缓冲
TCP的I/O缓冲有如下特点:
- I/O缓冲在每个TCP套接字中单独存在
- I/O缓冲在创建TCP套接字时自动生成
- 即使关闭套接字也会继续传输发送缓冲区中遗留的数据
- 关闭套接字将丢弃输入缓冲区中的数据
考虑这样一种情况,接收端输入缓冲区大小为50字节,而发送端输出缓冲大小为100字节,当发送端向接收端传输100字节的数据时会发生什么呢?接收端缓冲区溢出?其实,接收端可以正常处理这种情况,因为TCP会控制数据流(Flow Control),这是由TCP协议的滑动窗口(Sliding Window)机制来保证的。
关于数据交换时调用的函数write和read(阻塞模式下),write函数调用的返回时机是发送端将数据传输至输出缓冲区;read函数的返回时机是接收缓冲区有数据待读取时。
TCP内部工作原理1:与对方套接字的连接
整体来看,TCP套接字从创建到消失所经历的过程如下:
- 与对方套接字建立连接
- 与对方套接字进行数据交换
- 断开与对方套接字的连接
关于TCP套接字建立连接的过程如下图所示,该过程就是所谓的三次握手(Three-way handshaking)机制。
TCP套接字连接过程
[SYN] SEQ:1000,ACK:-
首次建立连接请求时使用的消息字段为SYN(Synchronization),即收发数据前传输的同步消息。SEQ值1000表示该数据包的编号,ACK字段为空。
[SYN+ACK] SEQ:2000,ACK:1001
ACK是向对端的反馈字段,值1001表示已收到对端编号为1000的消息。
通过数据包编号并确认的方式,可以在数据丢失时马上查看并重传丢失的数据包,这也是TCP消息可靠的原因。
关于三次握手中主机A最后一次ACK消息的讨论,若该数据包丢失会发生什么?
若最后的ACK消息丢失,服务器端(主机B)并不会重传SYN+ACK消息,而是直接发送RST报文进入closed状态,目的是为了防止SYN泛洪攻击;另一个考虑,若最初客户端主机A的SYN消息受网络阻塞很久才到达服务器端,而客户端由于长久未与服务端建立连接而关闭了套接字,则此时服务器端也不能收到ACK消息的回应,因此也就没必要重发SYN+ACK消息。
TCP内部工作原理2:与对方主机的数据交换
三次握手后双方便建立了有效的连接,接下来是数据交换的过程,如下图所示。
TCP套接字数据交换过程
以上通信过程的消息字段和三次握手过程一样,需要注意的是ACK消息字段的值是这样计算的:SEQ值 + 传递的字节数 + 1。加1是为了告知对方之前发送的消息已全部接收,下次可发送其余数据。如果数据包发生丢失又会怎样?
TCP套接字数据传输错误处理
如上图示过程,为了完成数据包重传,TCP套接字启动计时器以等待ACK应答。若相应计时器发生超时(Time-out)则重传。
TCP内部工作原理3:断开与套接字的连接
TCP套接字的结束过程也非常优雅。如果对方还有数据需要传输时直接断连会出问题,所以断连时需要双方协商。该过程如下图所示,也即四次挥手(Four-way handshaking)的过程。
TCP套接字断开连接过程
携带有FIN字段的数据包表示断开连接,也就是说,双方各发送一次FIN消息后断开连接。
原文地址:https://www.cnblogs.com/Glory-D/p/12075652.html