【转载】TCP协议
首部格式
图释:
各个段位说明:
- 源端口和目的端口:各占 2 字节.端口是传输层与应用层的服务接口.传输层的复用和分用功能都要通过端口才能实现
- 序号:占 4 字节.TCP 连接中传送的数据流中的每一个字节都编上一个序号.序号字段的值则指的是本报文段所发送的数据的第一个字节的序号
- 确认号: 占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号
- 数据偏移/首部长度:占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远.“数据偏移”的单位是 32 位字(以 4 字节为计算单位)
- 保留: 占 6 位,保留为今后使用,但目前应置为 0
- 标志位 占有6位,分别表示下面的标志
- 紧急URG:当 URG=1 时,表明紧急指针字段有效.它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)
- 确认ACK:只有当 ACK=1 时确认号字段才有效.当 ACK=0 时,确认号无效
- PSH(PuSH): 接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付
- RST (ReSeT): 当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
- 同步 SYN: 同步 SYN = 1 表示这是一个连接请求或连接接受报文
- 终止 FIN: 用来释放一个连接.FIN=1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接
- 检验和:占 2 字节.检验和字段检验的范围包括首部和数据这两部分.在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部
- 紧急指针:占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)
- 选项:长度可变.TCP 最初只规定了一种选项,即最大报文段长度 MSS.MSS 告诉对方 TCP:“我的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节.” [MSS(Maximum Segment Size)是 TCP 报文段中的数据字段的最大长度.数据字段加上 TCP 首部才等于整个的 TCP 报文段]
- 窗口扩大: 占 3 字节,其中有一个字节表示移位值 S.新的窗口值等于TCP 首部中的窗口位数增大到(16 + S),相当于把窗口值向左移动 S 位后获得实际的窗口大小
- 时间戳:占10 字节,其中最主要的字段时间戳值字段(4字节)和时间戳回送回答字段(4字节)
- 选择确认:接收方收到了和前面的字节流不连续的两2字节.如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据
- 填充 :这是为了使整个首部长度是 4 字节的整数倍
数据单位
- TCP 传送的数据单位协议是 TCP 报文段(segment)
特点
- TCP 是面向连接的传输层协议
- 每一条 TCP 连接只能有两个端点(endpoint),每一条 TCP 连接只能是点对点的(一对一)
- TCP 提供可靠交付的服务
- TCP 提供全双工通信
- 面向字节流
注意
- TCP 对应用进程一次把多长的报文发送到TCP 的缓存中是不关心的
- TCP 根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)
- TCP 可把太长的数据块划分短一些再传送.TCP 也可等待积累有足够多的字节后再构成报文段发送出去
每一条 TCP 连接有两个端点 - TCP 连接的端点不是主机,不是主机的IP 地址,不是应用进程,也不是传输层的协议端口.TCP 连接的端点叫做套接字(socket)或插口
自动重传请求ARQ
定义:
可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest)
累积确认:
- 定义: 接收方一般采用累积确认的方式.即不必对收到的分组逐个发送确认,而是对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已正确收到了
- 优点: 容易实现,即使确认丢失也不必重传
- 缺点: 不能向发送方反映出接收方已经正确收到的所有分组的信息
Go-back-N(回退N):
如果发送方发送了前 5 个分组,而中间的第 3 个分组丢失了.这时接收方只能对前两个分组发出确认.发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次
具体实现
说明:
- TCP 连接的每一端都必须设有两个窗口 一个发送窗口和一个接收窗口
- TCP 可靠传输机制用字节的序号进行控制.TCP 所有的确认都是基于序号而不是基于报文段
- TCP 两端的四个窗口经常处于动态变化之中
- TCP 连接的往返时间 RTT 也不是固定不变的.需要使用特定的算法估算较为合理的重传时间
图释:
发送缓存
发送缓存用来暂时存放:
- 发送应用程序传送给发送方 TCP 准备发送的数据
- TCP 已发送出但尚未收到确认的数据
图释:
接收缓存
接收缓存用来暂时存放:
- 按序到达的、但尚未被接收应用程序读取的数据;
- 不按序到达的数据
图释:
滑动窗口
图释:
特点:
- 以字节为单位的滑动窗口
- A 的发送窗口并不总是和 B 的接收窗口一样大(因为有一定的时间滞后)
要求:
- TCP 标准没有规定对不按序到达的数据应如何处理.通常是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程
- TCP 要求接收方必须有累积确认的功能,这样可以减小传输开销
具体实现:
确认丢失和确认迟到
超时重传时间选择
RTT,RTO
- RTT(Round Trip Time):一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值;
- RTO(Retransmission Time Out):重传超时时间,即从数据发送时刻算起,超过这个时间便执行重传。
- RTT和RTO 的关系是:由于网络波动的不确定性,每个RTT都是动态变化的,所以RTO也应随着RTT动态变化。
具体实现:
TCP 每发送一个报文段,就对这个报文段设置一次计时器.只要计时器设置的重传时间到但还没有收到确认,就要重传这一报文段
加权平均往返时间:
做法:
TCP 保留了 RTT 的一个加权平均往返时间 RTTS(这又称为平滑的往返时间),第一次测量到 RTT 样本时,RTTS 值就取为所测量到的 RTT 样本值.以后每测量到一个新的 RTT 样本,就按下式重新计算一次 RTTS:
公式:
新的 RTTS = ( 1 - α)×(旧的 RTTS)+α(新的 RTT 样本)
说明:
式中,0 ≤ α< 1.若α很接近于零,表示 RTT 值更新较慢若选择 α 接近于1,则表示 RTT 值更新较快
RFC 2988 推荐的 α 值为 1/8,即 0.125
超时重传时间RTO:
RTO 应略大于上面得出的加权平均往返时间 RTTS.
RFC 2988 建议使用下式计算 RTO:
RTO=RTTS + 4×RTTD
RTTD 是 RTT 的偏差的加权平均值
RFC 2988 建议这样计算 RTTD.第一次测量时,RTTD 值取为测量到的 RTT 样本值的一半.在以后的测量中,则使用下式计算加权平均的 RTTD:
新的 RTTD = (1-β)×(旧的RTTD)+β×|RTTS﹣新的 RTT 样本|
β是个小于 1 的系数,其推荐值是 1/4,即 0.25
在计算平均往返时间 RTT 时,只要报文段重传了,就不采用其往返时间样本
修正的Karn算法:
报文段每重传一次,就把 RTO 增大一些:
新的 RTO= γ×(旧的 RTO)
系数γ 的典型值是 2
当不再发生报文段的重传时,才根据报文段的往返时延更新平均往返时延 RTT 和超时重传时间 RTO 的数值
持续计时器
- TCP 为每一个连接设有一个持续计时器
- 只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器
- 若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值
- 若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器
- 若窗口不是零,则死锁的僵局就可以打破了
报文段的发送时机
TCP 维持一个变量,它等于最大报文段长度 MSS.只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去
由发送方的应用进程指明要求发送报文段,即 TCP 支持的推送(push)操作
发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去
运输连接
三个阶段:
- 连接建立:
- 图释:
- 步骤:
- A 的 TCP 向 B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x
- B 的 TCP 收到连接请求报文段后,如同意,则发回确认(B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x﹢1,自己选择的序号 seq = y)
- A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y﹢1(A 的 TCP 通知上层应用进程,连接已经建立,B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立)
- 步骤:
- 数据传送
- 连接释放:
- 图释:
步骤:
- 数据传输结束后,通信的双方都可释放连接.现在 A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接(A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认)
- B 发出确认,确认号 ack = u+1,而这个报文段自己的序号 seq = v(TCP 服务器进程通知高层应用进程.从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态.B 若发送数据,A 仍要接收)
- 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接
- A 收到连接释放报文段后,必须发出确认,在确认报文段中 ACK = 1,确认号 ack=w﹢1,自己的序号 seq = u + 1
注意:
TCP 连接必须经过时间 2MSL 后才真正释放掉(2MSL 的时间的用意 --- 为了保证 A 发送的最后一个 ACK 报文段能够到达 B.防止 “已失效的连接请求报文段”出现在本连接中.A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段,都从网络中消失.这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段)
- 发现丢失确认时候的处理:
三个问题:
- 要使每一方能够确知对方的存在
- 要允许双方协商一些参数(如最大报文段长度,最大窗口大小,服务质量等)
- 能够对运输实体资源(如缓存大小,连接表中的项目等)进行分配
发送TCP请求客户端
拥塞处理相关概念
拥塞窗口:
含义:
拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化.发送方让自己的发送窗口等于拥塞窗口.如再考虑到接收方的接收能力,则发送窗口还可能小于拥塞窗口
发送方控制拥塞窗口的原则:
只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去.但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数
乘法减小:
是指不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时(即出现一次网络拥塞),就把慢开始门限值 ssthresh 设置为当前的拥塞窗口值乘以 0.5
加法增大:
是指执行拥塞避免算法后,在收到对所有报文段的确认后(即经过一个往返时间),就把拥塞窗口 cwnd增加一个 MSS 大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞
快重传:
快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认.这样做可以让发送方及早知道有报文段没有到达接收方,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段
快恢复:
当发送端收到连续三个重复的确认时,就执行“乘法减小”算法,把慢开始门限 ssthresh 减半.但接下去不执行慢开始算法
发送窗口的上限值:
发送方的发送窗口的上限值应当取为接收方窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的一个,即应按以下公式确定:
发送窗口的上限值 Min [rwnd, cwnd]
- 当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值
- 当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值
免拥塞具体实现
慢开始算法:
- 在主机刚刚开始发送报文段时可先设置拥塞窗口 cwnd = 1,即设置为一个最大报文段 MSS 的数值
- 在每收到一个对新的报文段的确认后,将拥塞窗口加 1,即增加一个 MSS 的数值
- 使用慢开始算法后,每经过一个传输轮次(往返时间 RTT),拥塞窗口 cwnd 就加倍
拥塞避免算法:
拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,使拥塞窗口 cwnd 按线性规律缓慢增长
慢开始门限 ssthresh 的用法:
- 当 cwnd < ssthresh 时,使用慢开始算法
- 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法
- 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法
网络出现拥塞时(其根据就是没有按时收到确认):
- 就要把慢开始门限 ssthresh 设置为出现拥塞时的发送方窗口值的一半(但不能小于2)
- 然后把拥塞窗口 cwnd 重新设置为 1.执行慢开始算法
TCP 的有限状态机
说明:
- TCP 有限状态机的图中每一个方框都是 TCP 可能具有的状态
- 每个方框中的大写英文字符串是 TCP 标准所使用的 TCP 连接状态名.状态之间的箭头表示可能发生的状态变迁
- 箭头旁边的字,表明引起这种变迁的原因,或表明发生状态变迁后又出现什么动作
- 图中有三种不同的箭头
- 粗实线箭头表示对客户进程的正常变迁
- 粗虚线箭头表示对服务器进程的正常变迁
- 另一种细线箭头表示异常变迁
链接
【转载】TCP协议的更多相关文章
- [转载] TCP协议缺陷不完全记录
原文: http://www.blogjava.net/yongboy/archive/2015/05/07/424917.html tcp是一个非常复杂并且古老的协议, 之前教科书上将的很多东西应用 ...
- TCP 协议简介-阮一峰(转载)
TCP 协议简介 作者: 阮一峰 日期: 2017年6月 8日 TCP 是互联网核心协议之一,本文介绍它的基础知识. 一.TCP 协议的作用 互联网由一整套协议构成.TCP 只是其中的一层,有着自 ...
- 转载:TCP协议如何保证可靠传输
转载至:https://www.cnblogs.com/xiaokang01/p/10033267.html TCP协议如何保证可靠传输 概述: TCP协议保证数据传输可靠性的方式主要有: (校 序 ...
- 【转载】TCP协议疑难杂症全景解析
说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的3).针对对象:对TCP已经有了全面了解的人. ...
- 【转载】TCP协议要点和难点全解
说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面 2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的 3).针对对象:对TCP已经有了全面了解的 ...
- 【转载】Http协议与TCP协议简单理解
在C#编写代码,很多时候会遇到Http协议或者TCP协议,这里做一个简单的理解.TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上 ...
- Http协议与TCP协议理解(转载的)
TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通 ...
- 使用TCP协议的NAT穿透技术 (转载)
其实很早我就已经实现了使用TCP协议穿透NAT了,但是苦于一直没有时间,所以没有写出来,现在终于放假有一点空闲,于是写出来共享之. 一直以来,说起NAT穿透,很多人都会被告知使用UDP打孔这个技术,基 ...
- 浅析TCP协议---转载
https://cloud.tencent.com/developer/article/1150971 前言 说到TCP协议,相信大家都比较熟悉了,对于TCP协议总能说个一二三来,但是TCP协议又是一 ...
随机推荐
- Linux内核模块管理命令
1.insmod命令 在Linux系统下,insmod命令用于将给定的模块加载到内核中去,Linux系统有许多功能是通过模块的方式,在需要时才载入kernel,这样做可以使kernel较为精简,进而提 ...
- ES6高级技巧(二)
Array.from const cities = [ { name: 'Milan', visited: 'no' }, { name: 'Palermo', visited: 'yes' }, { ...
- spring aop 一个挡板例子
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.ann ...
- linux中awk工具的使用(转)
add by zhj: awk很强大,它是一个简单的编程语言,国外有本专门的书介绍它的用法.<effective awk programming>,它支持整型,字符串型,数组,变量在使用前 ...
- Java学习:数据结构简介
数据结构 数据结构: 数据结构_栈:先进后出 入口和出口在同一侧 数据结构_队列:先进先出 入口和出口在集合的两侧 数据结构_数组: 查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过 ...
- @Autowired注解到底是byType还是byName?
2016-08-05 14:29:32 杨家昌 阅读数 13400更多 分类专栏: spring 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明 ...
- apache设置外网访问的方法 (服务器)
环境:windows server 2012 R2 apache 2.4 首先,找到apache配置文件httpd.conf,找到配置: 代码展示: <directory /> optio ...
- (原创)C#操作MYSQL数据库
应用程序对数据库的操作都是只有4个:增,删,改,查. 只有”查”的操作需要使用适配器来存储查询得到的数据.其它3个操作不需要用到适配器. 不同的数据库有共同操作方法:都要建立连接对象,连接对象要有连接 ...
- 重温拉格朗日乘子法和KKT条件
在求取有约束条件的优化问题时,拉格朗日乘子法(Lagrange Multiplier) 和KKT条件是非常重要的两个求取方法,对于等式约束的优化问题,可以应用拉格朗日乘子法去求取最优值:如果含有不等式 ...
- 安装多个jdk导致eclipse打不开问题
问题描述 本来使用的是jdk1.8,由于其他原因需要使用jdk1.6,在安装完jdk1.6后打开eclipse就会报错: Version 1.6.0_43 of the JVM is not suit ...