4 TCP(Transmission Control Protocol)
TCP是传输控制协议,一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。
4.1 特点
面向连接
连接需要先创建再使用,创建连接的三次握手有一定开销。两个使用 TCP的应用在交换数据前必须先建立一个 TCP 连接,在一个 TCP 连接中,仅有两方进行彼此通信,广播和多播不能用于 TCP
每条 TCP 连接只能有两个端点(endpoint)
每条 TCP 连接只能是点对点(一对一)
可靠交付
全双工通信
面向字节流
两个应用程序通过 TCP 连接,TCP 不在字节中插入记录标识符。TCP对字节流内容不做任何编解码解释,不知道传输的字节流数据是二进制数据还是 ASCII 字符或其它类型数据,对字节流的编解码由TCP连接双方的应用层协商。
字节是发送数据的最小单元,TCP协议本身无法区分哪几个字节是完整的消息体,也无法感知是否有多个客户端在使用同一个TCP连接,TCP只是一个读写数据的管道。
TCP 面向流的概念
注意
- TCP 连接是一条虚连接而不是一条真正的物理连接
- TCP 对应用进程一次把多长的报文发送到TCP 的缓存中是不关心的
- TCP 根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(而UDP 发送的报文长度是应用进程给出的)
- TCP 可把太长的数据块划分短一些再传送
TCP 也可等待积累有足够多的字节后再构成报文段发送出去
4.2 TCP 的连接
TCP 把连接作为最基本的抽象,每一条 TCP 连接有两个端点。TCP 连接的端点不是主机、主机的IP 地址、应用进程、运输层的协议端口,TCP 连接的端点叫做套接字(socket)!端口号拼接到(contatenated with) IP 地址即构成了套接字。
4.2.1 套接字 (Socket)
Socket = (IP地址: 端口号) 。每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定,即:
TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}
所以一个 socket 就是一个网络通信资源组。
Socket的多重含义
- 应用编程接口 API 称为 socket API,简称为 socket
- socket API 中使用的一个函数名也叫作 socket
- 调用 socket 函数的端点称为 socket
- 调用 socket 函数时其返回值称为 socket 描述符,可简称为 socket
- 在操作系统内核中连网协议的 Berkeley 实现,称为 socket 实现
4.2.2 三次握手
- TCP建立连接的三次握手
- 第一次握手
建立连接时,客户端发送syn包(syn=j)到服务器,进入SYN_SEND
态,待服务器确认
SYN:同步序列编号(Synchronize Sequence Numbers)
第二次握手
服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,服务器进入SYN_RECV态
第三次握手
客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
完成三次握手,也就建立了客户端与服务端的连接。客户端与服务器开始传送数据。一个完整的三次握手也就是:请求—应答—再次确认。
那说到现在,到底什么是连接?也就是经过 TCP 三次握手后,双方主机准备好数据传输的资源(比如各种数据结构)。
4.2.3 四次挥手
由于TCP连接是全双工,因此每个方向都必须单独进行关闭
。
原则
当一方完成它的数据发送任务后,就能发送一个FIN来终止这个方向的连接。
收到一个 FIN只代表这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。
首先进行关闭的一方将执行主动关闭,另一方执行被动关闭。
工作流程
- 客户端A发送一个FIN,以关闭Client A ---->>>Server B的数据传送
- B收FIN,发ACK,确认序号为收到的序号加1
- B关闭与A的连接,发FIN给A
- A发ACK报文确认,并将确认序号设置为收到序号加1
- 如下图中上框就是三次挥手,下框内即是四次挥手
4.2.4 为什么建立连接是三次握手,而关闭连接却四次握手
服务端的listen
状态下的socket当收到syn报文的连接请求后,它可把ACK和SYN(ACK起应答作用,SYN起同步作用)放在同一个报文发送。
但关连接时,当收到对方的FIN报文时,仅表示对方没有数据发送给你了,但未必你所有的数据都全部发送给对方了,所以你大可不必立即关闭socket,即你可能还需发送一些数据后,再发FIN来表示你也可以关连接了,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。
4.3 可靠传输
4.3.1 工作原理
注意
- 在发送完一个分组后,必须
暂时保留已发送的分组的副本
- 分组和确认分组都必须进行编号
- 超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些
4.3.2 可靠传输的实现
TCP 通过下列方式提供可靠性
- 将应用数据分割为 TCP 认为最合适发送的数据块
- 超时重传
- 当 TCP 发出一个段后,他启动一个定时器,等待目的端确认收到这个报文段
若不能及时收到一个确认,将重发这个报文段
当 TCP 收到发自 TCP 链接另一端的数据时,它将发送一个确认(对于收到的请求,给出确认响应)
这个确认不是立即发送,通常将推迟几分之一秒(之所以推迟,可能是要对包做完校验)
若 TCP 收到包,校验出包有错,丢弃报文段,不给出响应,TCP 发送端会超时重传
对于失序数据进行重排序,然后交给应用层
TCP 报文段作为 ip 数据报进行传输,而 ip 数据报的到达会失序,因此 TCP 报文段的到达也可能失序。若必要,TCP 将对收到的数据进行重新排列,以正确的顺序交给应用层
对于重复数据,直接丢弃。
TCP 可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出。
使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信
这种可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest)
- ARQ表明重传的请求是自动进行的
接收方不需要请求发送方重传某个出错的分组
4.3.3 TCP 可靠通信的具体实现
TCP 连接的每一端都必须设有两个窗口
- 一个发送窗口
- 一个接收窗口
TCP 的可靠传输机制用字节的序号进行控制:所有的确认都是基于序号而不是基于报文段
TCP 两端的四个窗口经常处于动态变化中
TCP 连接的往返时间 RTT 也不是固定不变的:需要使用特定的算法估算较为合理的重传时间
应用场景
聊天消息传输、推送,单人语音、视频聊天等。几乎UDP能做的都能做,但需要考虑复杂性、性能问题。
限制
无法进行广播、多播等操作
5 TCP 报文段的首部格式
源/目的端口——各占 2 字节
端口是运输层与应用层的服务接口:运输层的复用和分用都要通过端口实现
序号——占 4 字节
传送的数据流中的每一个字节都编上一个序号:序号的值则指的是本报文段所发送数据的第一个字节的序号
确认号——占 4 字节
期望收到对方下一个报文段的数据的第一个字节的序号
数据偏移(首部长度)——占 4 位
指出报文段的数据起始处距离报文段的起始处有多远:“数据偏移”的单位是 32 位字(以 4 字节为计算单位)
保留——占 6 位
为今后使用,但目前应置为 0
紧急 URG
URG = 1:紧急指针字段有效.它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)
确认 ACK
只有当 ACK = 1 时确认号字段才有效;
当 ACK = 0 时,确认号无效
推送 PSH (PuSH)
接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付
复位 RST (ReSeT)
当 RST = 1 时:TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
同步 SYN
SYN = 1:这是一个连接请求或连接接受报文
终止 FIN (FINis)
用来释放一个连接
FIN = 1:此报文段的发送端的数据已发送完毕,并要求释放运输连接
窗口字段 —— 占 2 字节
用来让对方设置发送窗口的依据,单位为字节(发送方的接收窗口)
检验和 —— 占 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 字节)
选择确认选项
填充
这是为了使整个首部长度是 4 字节的整数倍