传输层
负责数据能够从发送端传输到接收端。
端口号(Port)标识了一个主机上进行通信的不同的应用程序。
- 0~1023:知名端口号。如FTP(21)、SSH(22)、Telnet(23)、SMTP(25)、HTTP(80)、HTTPS(443)。查看知名端口号
cat /etc/services
- 1024~65535:操作系统动态分配端口号。
在TCP/IP协议中,用"源IP“、“源端口号”、“目的IP”、“目的端口号”、"协议号"这样一个五元组来标识一个通信。
注意:一个进程可以绑定多个端口号,因为一个进程可以打开多个文件描述符,而每个文件描述符都对应一个端口号,所以一个进程可以绑定多个端口号。一个端口号不能被多个进程绑定。
netstat:一个用来查看网络状态的重要工具,常用选项如下:
语法:netstat [选项]
- n:拒绝显示别名,能显示数字的全部转化成数字
- l:仅列出有在listen的服务状态
- p:显示建立相关链接的程序名
- t:(tcp)仅显示tcp相关选项
- u:(udp)仅显示udp相关选项
- a:(all)显示所有选项,默认不显示listen相关
pidof:在查看服务器的进程id时非常方便。
语法:pidof [进程名]
1、UDP协议
协议格式
- 源端口号:16位
- 目地端口号:16位
- UDP长度(首部+数据):16位
- UDP校验和:16位
特点
- 无连接:知道对方的IP和端口号就直接进行传输,不需要建立连接
- 不可靠:没有确认机制,没有重传机制,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息
- 面向数据报:不能够灵活的控制读写数据的次数和数量
面向数据报
应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。但是UDP协议长度为16位,也就是说UDP能传输的数据最大是64K,如果要传输的数据超过64K,就需要在应用层手动分包、多次封装、多次发送,在接收段手动拼接。
UDP缓冲区
- UDP没有真正意义上的发送缓冲区。调用sendto会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。
- UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致,如果缓冲区满了,再到达的UDP数据就会被丢弃。
基于UDP的应用层协议
- NFS:网络文件系统
- TFTP:简单文件传输协议
- DHCP:动态住居配置协议
- BOOTP:无盘设备启动协议
- DNS:域名解析协议
UDP如何实现可靠传输?
在应用层引入和TCP可靠机制类似的实现逻辑。
2、TCP协议
协议格式
- 源端口号:16位
- 目的端口号:16位
- 序号:32位
- 确认序号:32位
- 首部长度(首部(不含数据)有多少个4字节(32位),(5+10(选项))*4):4位
- 保留:6位
- 标志位(URG、ACK、PSH、RST、SYN、FIN):6位
- 窗口大小:16位
- 检验和:16位
- 紧急指针:16位
- 选项:40字节
ACK(确认应答)机制
TCP将每个字节的数据都进行了编号,即为序列号。每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发。
超时重传机制
主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B,如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。
但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了,因此主机B会收到很多重复数据。那么TCP协议需要能够识别出那些包是重复的包,并且把重复的丢弃掉,这时候序列号就可以很容易做到去重的效果。
TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间。linux中超时以500ms为一个单位进行控制,每次判定超时都是500ms的整数倍,然后以指数的形式递增,即首次超时重传为1500ms,若未应答,第二次为2500ms,第三次为4*500ms…累计到一定重传次数,TCP认为网络或主机端异常,强制关闭连接。
连接管理机制
滑动窗口
对每一个发送的数据段,都要给一个ACK确认应答,收到ACK后再发送下一个数据段,这样做有一个比较大的缺点就是性能较差,尤其是数据往返的时间较长的时候。既然这样一发一收的方式性能较低,那么一次发送多条数据,就可以大大的提高性能。
窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。发送前四个段的时候,不需要等待任何ACK,直接发送。收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据,依次类推。操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答,只有确认应答过的数据,才能从缓冲区删掉。窗口越大,则网络的吞吐率就越高。
如果数据包抵达,ACK丢了,这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认。如果数据包丢了,当某一段报文段丢失之后,发送端会一直收到401这样的ACK,如果发送端主机连续三次收到了同样一个401这样的应答,就会将对应的数据401 - 500重新发送,这个时候接收端收到了401之后,再次返回的ACK就是901了,接收端之前就已经收到了501-900,被放到了接收端操作系统内核的接收缓冲区中,这就是快重传。
流量控制
接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制(Flow Control)。
- 接收端将自己可以接收的缓冲区大小放入TCP首部中的窗口大小字段,通过ACK端通知发送端
- 窗口大小字段越大,说明网络的吞吐量越高
- 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端
- 发送端接收到这个窗口之后,就会减慢自己的发送速度
- 如果接收端缓冲区满了,就会将窗口置为0,这时发送方不再发送数据,但是需要定期发送一个窗口探测数据,使接收端把窗口大小告诉发送端
拥塞控制
虽然TCP滑动窗口能够高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,仍然可能引发问题。因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵,在不清楚当前网络状态下,发送大量的数据,是很有可能引起网络拥塞,TCP引入慢启动机制,先发少量的数据探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据。
拥塞窗口:发送开始的时候,定义拥塞窗口大小为1,每次收到一个ACK应答,拥塞窗口加1,每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口。
慢启动:拥塞窗口的增长速度是指数级别,称慢启动。慢启动设定了一个阈值,在一开始以指数级别增长,当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长。当TCP开始启动的时候,慢启动阈值等于窗口最大值,在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置1。
拥塞控制小结:
- 慢开始:指数增长到阈值
- 拥塞避免:加法增大直到网络拥塞
- 网络拥塞:乘法减小,阈值减到发生拥塞时拥塞窗口的一半
延迟应答
如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。窗口越大,网络吞吐量就越大,传输效率就越高。
延迟应答:每隔N个包应答一次,超过最大延迟时间就应答一次。具体的数量和超时时间,依操作系统不同也有差异,一般N取2,超时时间取200ms。
捎带应答
在延迟应答的基础上,ACK把回应的消息一并发给对方。
面向字节流
创建一个TCP的socket,同时在内核中创建一个发送缓冲区和一个接收缓冲区。调用write时,数据会先写入发送缓冲区中,如果发送的字节数太长,会被拆分成多个TCP的数据包发出,如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多了或者其他合适的时机发送出去,接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区,然后应用程序可以调用read从接收缓冲区拿数据。TCP的一个连接,既有发送缓冲区也有接收缓冲区,那么对于这一个连接,既可以读数据也可以写数据,这叫全双工。
由于缓冲区的存在,TCP程序的读和写不需要逐一匹配。比如读或写100字节数据时。可以一次调用read或write,也可以每次read或write一个字节,执行100次。
TCP异常情况
进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有什么区别。
机器重启:和进程终止的情况相同。
机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset,即使没有写入操作,TCP自己也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放,另外,应用层也有这种检测机制。
TCP小结
- 高可靠性:校验和、序列号、确认应答、超时重传、连接管理、流量控制、拥塞控制、定时器
- 高性能:滑动窗口、快速重传、延迟应答、捎带应答
- 基于TCP的应用层协议:HTTP、HTTPS、SSH、Telnet、FTP、SMTP
- TCP/UDP对比:UDP适用于对高速传输和实时性要求高的通信,TCP适用于高可靠性通信。
来源:CSDN
作者:_NoBug_
链接:https://blog.csdn.net/qq_41245381/article/details/104310197