【网络】传输层协议——TCP协议
TCP协议
TCP全称为“传输控制协议((Transmission Control Protocol)”,即对数据的传输进行一个详细的控制;
1.TCP协议段格式
- 源端口号:表示发送端口号,字段长度16位;
- 目标端口号:表示接受端口号,字段长度16位;
- ***:字段长32位,***是指发送数据的位置,没发送一次数据,就累加一次该数据字节数的大小;
- 确认应答号:字段长32位,是指下一次应该收到的数据的***。
- 数据偏移:该字段表示TCP所传输的数据部分应该从TCP包的哪个位开始计算,当然也可以把它看做TCP首部的长度;
- 保留:该字段主要是为了以后扩展时使用,长度为4位,一般设置为0,但即使收到的包在该字段不为0,此包也不会被丢弃;
- 控制位:字段长8位,主要有以下6个标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:为1时,表示需要将受到的数据立刻传给山城应用协议,为0时,则不需要立即传而是先进行缓存
RST:对方要求重新建立连接;我们携带RST标识的称为复位报文段
SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
FIN:通知对方,本段要关闭了,我们称携带FIN标识的为结束报文段
- 窗口大小:字段长为16位, 用于通知从相同TCP首部的确认应答号所指位置开始能接受的数据大小(8位字节)
- 校验和:字段长为16位,发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也包含 TCP数据部分;
- 紧急指针:字段长16位,标识哪部分数据是紧急数据;
2.确认应答机制
利用序号+确认序号实现
3.超时重传机制
TCP内部实现,动态计算的。以单方向数据传输最大时间*2作为超时时间(发送一次,接受一次确认应答)
4.连接管理机制
三次握手和四次挥手
5.滑动窗口
- 作用:提高网络传输效率
- 原理:一去一回串行的网络数据传输,转变为并行的收发数据;通过序号+确认号保证数据传输的安全性;
- 窗口:无需等待确认应答二可以继续发送数据的最大值
- 滑动:并行发送数据报,需要接收到ACK的响应报文段才表示数据发送成功。而窗口是否能够滑动,以及能够滑动到哪个位置都由ACK响应报文的下一个序号决定,具体是能滑动ACK相应的报文连续的最大确认序
6.流量控制
背景:接受端能力有限,如果接收缓冲区被打满,会造成丢包等一系列问题;
原理:使用窗口大小字段,告诉发送端发送数据的大小
7.拥塞控制
背景:不清楚当前网络状态的情况下,贸然发送大量的数据,可能引发网络拥堵雪上加霜
原理:
(1)慢启动机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据
(2)拥塞窗口初始值为1,开始呈现为指数曲线,到达后阈值变为线性增长;
8.延迟应答
作用:提高网络传输效率
原理:接收到数据报时,不马上响应ACK,而是延迟一段时间后再应答,这样可以增加滑动串口的大小。提高系统吞吐量
9.捎带应答
作用:提高网络传输效率
原理:合并发送数据报
10.面向字节流
面向字节流的话,虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序看成是一连串的无结构的字节流。TCP有一个缓冲,当应用程序传送的数据块太长,TCP就可以把它划分短一些再传送。如果应用程序一次只能发送一个字节,TCP也可以等待积累有足够多的字节后再构成报文段发送出去。
创建一个TCP的socket,同时在内核中创建一个发送缓冲区和一个接受缓冲区。
- 调用write时,数据会先写入发送缓冲区中;
- 如果发送的字节数太长,会被拆分成多个TCP的数据包发出;
- 如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多了,或者其他合适的时机发送出去;
- 接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区;
- 然后应用程序可以调用read从接受缓冲区拿数据;
- 另一方面,TCP的一个连接,既有发送缓冲区,也有接收缓冲区,那么对于这一个连接,既可以读数据,也可以写数据,这个概念叫做全双工;
由于缓冲区的存在,TCP程序的读和写不需要一一匹配。
写100个字节数据时,可以调用一次write写100个字节,也可以调用100次write,每次写一个字节;
读100个字节数据时,也完全不需要考虑写的时候是怎样写的,既可以一次read100个字节,也可以read一个字节,重复100次;
11.粘包问题
- 首先要明确,粘包问题中的“包”,是指的应用层的数据包;
- 在TCP的协议头中,没有如同UDP一样的“报文长度”这样的字段,但是有一个序号这样的字段;
- 站在传输层的角度,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中;
- 站在应用层的角度,看到的只是一串连续的字节数据;
- 那么应用程序看到了这么一连串的字节数据,就不知道从那个部分开始到哪个部分,是一个完整的应用层数据包;
如何避免粘包问题呢?归根结底就是一句话:明确两个包之间的边界。
- 对于定长的包,保证每次都按固定大小读取即可;
- 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
- 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序员自己来定的,只要保证分隔符不和正文冲突即可)
对于UDP协议,是否也存在“粘包问题”?
- 对于UDP,如果还没有上层交付数据,UDP的报文长度仍然在,同时,UDP是一个一个把数据交付给应用层,就有很明确的数据边界;
- 站在应用层的角度,使用UDP的时候,要么收到完整的UDP报文,要么不收,不会出现“半个”的情况。
12.TCP异常情况
进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有什么区别;
机器重启:和进程种植的情况相似;
机器掉电、网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接不在了,就会进入reset,即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放;
另外,应用层的某些协议,也有一些这样的检测机制,例如HTTP长连接中,也会定期检测对方的状态,例如QQ,在QQ断线之后,也会定期尝试重新连接。
13.TCP总结
保证TCP的可靠性:
- 校验和
- ***(按序到达)
- 确认应答
- 超时重传
- 连接管理
- 流量控制
- 拥塞控制
提高性能:
- 滑动窗口
- 快速重传
- 延迟应答
- 捎带应答
其他:
- 定时器(超时重传定时器,保活定时器,TIME_WAIT定时器等)
14.基于TCP应用层的协议
- HTTP
- HTTPS
- SSH(加密的远程登录系统)
- Telnet(远程终端接入)
- FTP(文件传输)
- SMTP(电子邮件)