目录
1. TCP协议头部格式
2. TCP协议原理
2.1 可靠传输机制
2.1.1 确认应答机制
2.1.2 超时重传机制
2.1.3 连接管理机制(三次握手,四次挥手)
2.1.4 流量控制
2.1.5 拥塞控制
2.2 效率机制
2.2.1 滑动窗口
2.2.2 延迟应答
2.2.3 捎带应答
3. 粘包问题
4. TCP的异常情况
5. TCP协议特点总结
6. 基于TCP的应用层协议
1. TCP协议头部格式
![【计算机网络】TCP协议详解_第1张图片](http://img.e-com-net.com/image/info8/3b88dc2df229436ba19be8d821427cb4.jpg)
- 源/目的端口:表示数据从哪个进程发送,发送到哪个进程去
- 32位序号:发送的数据按照一个字节一个编号存放进去
- 32位确认号:用于给对方的响应,值为收到TCP报文段的序号值加1
- 4位TCP报头长度:表示TCP头部有4个字节(32位),所以TCP头部最大长度为15*4=60
- 6个boolean值标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
RST:对方要求重新建立连接,把携带RST标识的称为复位报文段
SYN:请求建立连接,把携带SYN标识的称为同步报文段
FIN:通知对方,要关闭连接了,把携带FIN标识的称为结束报文
- 16位窗口大小:进行流量窗口控制
- 16位校验和:检验数据是否一致
- 16位紧急指针:标识哪部分数据是紧急数据
2. TCP协议原理
TCP协议是对数据传输提供的一个管控机制,主要体现在可靠和效率两个方面,即在保证数据可靠传输的情况下尽可能的提高效率
2.1 可靠传输机制
2.1.1 确认应答机制
向对方发送一个数据报,对方要返回一个确认应答的数据报
实现的方式:
![【计算机网络】TCP协议详解_第2张图片](http://img.e-com-net.com/image/info8/fdbf671719fa49c696a5a6c2c2f7fb03.jpg)
说明:
- 发送的数据是基于TCP报头中的“32位序号”来保存的,一个字节对应一个序号
- 确认应答的数据是基于TCP报头中的“32位确认序号”来保存的,ack(确认信息)标志位置为1,返回某个序列号,说明某个序列号之前的数据全部接收到
- 有了确认应答,它才可以继续发送后边的数据
2.1.2 超时重传机制
发送的数据报可能因为网络拥堵等原因,超过一定时间,还没有收到确认应答的数据报,就需要重新发送
- 没有收到确认应答,可能是因为发送数据时候就已经发生了丢包
![【计算机网络】TCP协议详解_第4张图片](http://img.e-com-net.com/image/info8/f50678a132ae46768d19412538af808e.jpg)
这种情况,主机B可能会接收到许多重复的数据,基于TCP协议报头中的“32位序号”可以识别到哪些包是重复的包,并把重复的包丢掉,达到去重的效果
超时时间如何确定?
如果超时时间设置的太长,会导致重传的效率
如果超时时间设置的太短,会导致频繁发送重复的数据
因此TCP协议为了保证在任何环境中都能有较高性能的通信,系统会动态的计算这个超时时间
- 超时以500ms为一个单位,每次判定超时重发的时间都是500ms的整数倍
- 重发一次,仍然不能收到应答,等待2*500ms后再进行重传
- 仍然等不到应答,等待4*500ms进行重传,以此类推,以指数形式增长
- 累积到一定重传次数,TCP协议认为网络或者对端主机出现异常,强制关闭连接
2.1.3 连接管理机制(三次握手,四次挥手)
真正发送数据之前,要先通过三次握手建立连接,不需要发送数据了,通过四次挥手断开连接
三次握手
- 客户端向服务端发送SYN,申请建立客户端到服务端的连接
- 服务端返回ACK(第一次SYN的应答)和SYN,申请建立服务端到客户端的连接
- 客户端收到数据,状态置为ESTABLISHED,表示客户端到服务端连接建立完成,并且发送ACK(第二次SYN的应答),服务端收到数据,状态置为ESTABLISHED,表示服务端到客户端的连接建立完成
四次挥手
![【计算机网络】TCP协议详解_第6张图片](http://img.e-com-net.com/image/info8/f1b7d232e7d74c3d904a28254fcdffac.jpg)
说明:关闭的时候服务端申请关闭或者客户端申请关闭都可以
- 客户端发送FIN到服务端,申请关闭客户端到服务端的连接
- 服务端收到FIN状态置为CLOSE_WAIT,并返回ACK应答(这个动作是系统实现TCP协议栈默认执行的,不需要程序来调用代码)
- 服务端发送FIN到客户端,申请关闭服务端到客户端的连接(程序手动调用socket.close发送)
- 客户端收到FIN返回ACK应答,并进入TIME_WAIT时间等待状态,客户端等待一段时间后,状态置为CLOSED,服务端收到应答后,状态置为CLOSED
思考:
- 为什么服务端不将ACK和FIN合并一起发送,形成三次挥手呢?
答:因为服务端状态置为CLOSED_WAIT说明服务端准备关闭连接,但是服务端可能还在继续发送数据,得处理完之前的数据,还可以执行一些关闭连接前的工作,如消耗资源等 ,所以是先给客户端发送应答,再处理完数据再向客户端发送FIN申请关闭连接
- 为什么客户端要等待一段时间状态才置为CLOSED,而不之间将状态置为CLOSED?
答:如果客户端给服务端的ACK丢包后,服务端得重新给和客户端发送FIN,此时客户端得给服务端应答,所以此时状态不能置为CLOSED,得等待一段时间确保服务端收到客户端的应答
2.1.4 流量控制
接收端主机处理数据的速度有限,如果发送端发送数据太快,导致接收端缓冲区被填满,这时,发送端继续发送数据的话就会造成丢包,继而引起丢包重传等一些列连锁反应,因此TCP协议根据接收端接收数据的能力,来决定发送端发送数据的速度,这个机制就叫作流量控制
- 接收端将自己剩余缓冲区大小存入TCP头部中的“16位窗口大小”字段 ,通过ACK通知发送端
- 窗口大小越大,说明网络吞吐量越高
- 发送端根据接收到这个窗口的大小,控制自己的发送速度
- 如果接收缓冲区满了,就会将窗口设置为0,这时,发送端不在发送数据,而是定期的发送一个窗口探测数据段,让接收端将窗口大小告诉发送端
2.1.5 拥塞控制
刚开始,发送端网络状况不明,如果贸然发送大量数据,就会造成大量丢包,所以TCP协议引入慢启动的方式,先发少量数据探探路,再决定按照多大速度发送数据
此处引入拥塞窗口,刚开始时,拥塞窗口设置为1,每收到一个ACK时,拥塞窗口加1,每次发送数据的时候,拥塞窗口和流量窗口的较小的值作为实际发送的窗口,即滑动窗口的大小
注意:上述增长方式是指数级别的,“慢启动”只是开始时慢,但是增长速度非常迅速
拥塞窗口变化的方式
为了不增长那摩快,引入一个慢启动的阈值,当拥塞窗口的大小超过了这个阈值,不在按照指数方式增长,而是按照线性方式增长,如下图所示:
![【计算机网络】TCP协议详解_第7张图片](http://img.e-com-net.com/image/info8/66c08ce5bb8843b7878dbd43cbc72999.jpg)
开始时,慢启动的阈值为窗口的最大值
网络拥塞时,拥塞窗口置1,慢启动阈值变为拥塞窗口/2,重新开始增长
2.2 效率机制
2.2.1 滑动窗口
前面的确认应答机制指出,对每一个发送的数据都对应有一个ACK确认应答,这样采取一发一收的方式有一个很大的缺点就是效率太差,为了提高效率采用滑动窗口,即一次性发送多个数据
![【计算机网络】TCP协议详解_第8张图片](http://img.e-com-net.com/image/info8/d0234f6c8ad4420fb4c89ff92f5d7a74.jpg)
- 窗口大小:指无需等待而可以继续发送数据的最大值,上图的窗口大小为4000个字节(四个段)
- 具体如何设置窗口大小:min(流量窗口的大小,拥塞窗口的大小)
- 窗口如何滑动:接收到的ACK下一个是n,滑动到n-1的位置
操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答,只有应答过的数据才能从缓冲区中删掉
如果出现了丢包,如何确保可靠传输?
![【计算机网络】TCP协议详解_第9张图片](http://img.e-com-net.com/image/info8/e4276d91ef0f479497e6644b002a2a02.jpg)
这种情况下,部分ACK丢了不要紧,因为可以通过后续的ACK进行确认
![【计算机网络】TCP协议详解_第10张图片](http://img.e-com-net.com/image/info8/42072acbb9ac4b449cd38191b530879d.jpg)
说明:
- 当1001~2000这段报文丢失后,发送端一直会收到1001这样的ACK
- 如果发送端主机连续三次收到相同的ACK如1001应答,那发送端主机就会重新发送1001~2000数据
- 此时,接收端收到1001~2000数据后,再次返回的ACK应答就是7001了,因为2001~7000数据都已经接收到了,被放到接收端操作系统内核的接收缓冲区了
这种机制,即时不超时也会发生重传,称作“高速重发控制”也叫“快重传机制”
2.2.2 延迟应答
如果接收端主机接收到数据时,立刻返回ACK应答,这时候返回的流量窗口就比较小,但是流量窗口越大,网络吞吐量越大,传输效率就越高,所以等待一部分时间,待接收端处理完一部分数据 ,就可以将流量窗口设置为大一点的值,这样网咯吞吐量大,效率高
延迟是为了高吞吐量,但是也不能无限延迟
- 数量限制,每隔n个包就应答一次
- 时间限制,超过最大延迟时间,就应答一次
具体的数量和时间,不同操作系统有差异,一般n取2,超时时间取200ms
2.2.3 捎带应答
服务端接收到客户端的消息后,要返回一个ACK有时候可能需要返回一个响应,此时ACK可以搭载顺风车,和响应合并为一个数据返回,不用再将ACK和响应数据分开发送
3. 粘包问题
TCP是面向字节流的,可以多次的接收和发送,对于应用层来说,一连串的字节数据,不知道从哪到哪算一个完整的应用层数据包,对应发送多少次算一个应用层完整格式的数据,和接收多少次算一个应用层完整格式的数据就不知道了
如何解决粘包问题?明确包的边界
- 对于定长的包,每次都按照固定大小读取即可
- 对于变长的包,可以在包与包之间明确分隔符(应用协议,程序员自己定,只要保证分隔符和正文不起冲突即可)
4. TCP的异常情况
- 进程终止:进程终止会释放文件描述符,仍然可以发送FIN。和正常关闭没有什么区别
- 机器重启:和进程终止的情况相同
- 机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了就会进行reset,即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放
- 另外,应用层的某些协议,也有一些这样的检测机制,例如HTTP长连接中,也会定期检测对方的状态,例如QQ,在QQ断线之后,也会定期尝试重新连接
5. TCP协议特点总结
- 有连接:通过三次握手建立连接后才可接发数据,TCP协议是全双工的,即每端既可以发也可以收
- 可靠传输:网络数据传输是一跳一跳的,经过路途中的设备可能发生数据丢失,可靠传输是可能发生数据丢失但有机制保证对方能接收到
- 面向字节流:可以多次的收发数据(连接没有关闭时,可以多次的接收和发送数据)
- 有接收缓冲区和发送缓冲区:发送数据时,是先写到发送缓冲区,再刷新缓冲区(flush)
- 大小不受限制:多次的收发数据,每次的数据可以很大
6. 基于TCP的应用层协议
- HTTP
- HTTPS
- SSH
- Telnet
- FTP
- SMTP
也包括自己写TCP程序时自定义的应用层协议