TCP
- 点对点:
- 一个发送方,一个接收方
- 可靠的、按序的字节流
- 流水线机制:
- TCP拥塞控制和流量控制机制, 动态调整窗口尺寸
-
发送方/接收方缓存
TCP发送方/接收方缓存.png
(和SR略有相似)
-
全双工:
- 同一连接中能够传输双向数据流
- 面向连接:
- 通信双方在发送数据之前必须建立连接
- 连接状态只在连接的两端中维护,在沿途节点中并不能维护状态(中间的路由器之类的并不维护这种连接的状态)
- TCP连接包括:两台主机上的缓存、连接状态变量、socket等
- 流量控制机制
TCP段结构
TCP段结构.pngTCP:序列号和ACK
序列号:
- 序列号指的是segment中第一个字节的编号,而不是segment的编号
- 建立TCP连接时,双方随机选择序列号
ACKs:
- 希望接收到的下一个字节的序列号
- 累计确认:该序列号之前的所有字节均已被正确接收到(和GBN类似)
处理乱序到达的segment:
- TCP规范中并没有规定,由TCP的实现者做出决策
TCP的可靠数据传输
-
TCP在IP层提供的不可靠服务基础上实现可靠数据传输服务
-
TCP使用了流水线机制
-
TCP使用了累计确认机制
-
TCP使用单一重传定时器
-
触发重传的事件:1. 超时 2.收到重复ACK
-
渐进式:1.暂不考虑重复ACK 2.暂不考虑流量控制 3.赞不考虑拥塞控制
TCP RTT和超时
设置定时器的超时时间时,考虑RTT的大小,需大于RTT。如果过短,则会进行不必要的重传;如果过长,又会对段丢失时间反应慢。
则需要估计RTT:
- SampleRTT:测量从段发出去到收到ACK的时间:忽略重传
-
测量多个SampleRTT,求平均值,形成RTT的估计值EstimatedRTT
RTT估计值
每次测量一次SampleRTT,就用该公式更新一下现有的EstimatedRTT。
定时器超时时间的设置:
- EstimatedRTT + “安全边界”
- EstimatedRTT变化大——说明需要较大的边界
安全边界的确定:
-
测量RTT的变化值:SampleRTT和EstimatedRTT的差值
RTT的变化值.png
则定时器超时时间的设置:
定时器超时时间的设置.png
TCP发送方事件
从应用层收到数据:
- 创建segment
- 序列号是segment第一个字节的编号
- 开启计时器
- 设置超时时间:TimeOutInterval
超时:
- 重传引起超时的segment
- 重启定时器
收到ACK:
如果确认此前未确认的segment:
- 更新SendBase
- 如果窗口中还有未被确认的分组,重新启动定时器
TCP重传示例
TCP重传示例(a).png在(a)例中,ACK丢失,引起超时重传,重新传送seq92.
TCP重传示例(b).png在(b)例中,超时时间设置过短,则ACK=100在超时时间内并未被收到,因此重传seq=92。接着又陆续收到ACK=100,ACK=120,因此陆续更新sendbase=100, sendbase=120。此时接收方又收到了seq=92,而之前接收方已经发送过ACK=120,故此时再发送一个ACK=120。
TCP重传示例(c).png在(c)例中,ACK=100没有被收到,但是接收方并不知道,接收方已经正确的接收了seq=
92,则seq=100是按序收到的,于是接收方继续发送ACK=120。此时发送方收到120,则确认此前未确认的segment,并将sendbase更新为120。
TCP ACK的生成:
接收方:
- 收到一个按序的段,有个延迟ACK的动作,等待最多500ms,如果没有下一个段,就发送ACK
- 如果一个按序的段到了,并且之前有段在等待,则立即发送累计ACK,确认这两个段
- 如果一个乱序的段到了,立即发送重复ACK
快速重传机制
为什么要快速重传? TCP的实现中,如果发生超时,超时时间间隔将重新设置,即将超时时间间隔加倍,导致其很大
- 重发丢失的分组之前要等待很长时间
可以通过重复ACK检测分组丢失:
- sender会背靠背地发送多个分组
- 如果某个分组丢失,可能会引发多个重复的ACK
如果sender收到对同一数据的3个ACK,则假定该数据之后的段已经丢失
- 快速重传:在定时器超时之前即进行重传
TCP流量控制
接收方为TCP连接分配buffer:
接收方buffer.png
流量控制:控制发送方不会传输太多、太快以至于淹没接收方(buffer溢出),实际上是一个速度匹配机制
假定:TCP receiver丢弃乱序的segments
则如上图所示,buffer中的可用空间(spare room)= RcvWindow = RcvBuffer - [LastByteRcvd - LastByteRead]
-
recevier通过在segment的头部字段将RcvWindow告诉sender
-
sender限制自己已经发送的但还未收到ACK的数据不超过接收方的空闲RcvWindow尺寸
-
如果recevier告知sender RcvWindow=0,则还是允许sender发送一个非常小的segment,以重新返回RcvWindow的大小。
TCP连接管理
TCP的sender和receiver在传输数据前需要建立连接
初始化TCP变量
- seq.#
- buffer和流量控制信息
Client:连接发起者
Socket clientSocket = new Socket("hostname", "port number");
Server:等待客户连接请求
Socket connectionSocket = welcomeSocket.accept( );
三次握手(非常重要):
- 客户机发送TCP SYN段给服务器,无数据
- 服务器接收SYN,回复SYNACK段给客户机,此时分配buffer给它
-
客户机接收SYNACK,回复它一个ACK段
三次握手.png
四次挥手(非常重要):
TCP连接关闭:
四次挥手.pngclient closes socket: clientSocket.close( );
- 客户机向服务器发送TCP FIN控制segment
- 服务器收到FIN,回复ACK,关闭连接,发送FIN
- 客户机收到FIN,回复ACK
- 进入等待:如果又收到FIN, 则会重新发送ACK
- 服务器收到ACK,连接关闭。
网友评论