IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Java EE ——TCP的重要概念解析 -> 正文阅读

[网络协议]Java EE ——TCP的重要概念解析

可靠传输

TCP的其他特性在代码中有所体现,但是可靠传输并不能在代码中体现。
可靠传输的含义就是知道对方有没有收到自己发的消息

例如A给B发了一个在吗,如果A看到B给自己回了一个在,就说明自己发的消息B能收到,且B给A发的消息A也能收到

在TCP中有确认应答机制,可以通过对方发送给自己的应答报文中的ACK中是1还是0,判断这是应答报文还是普通报文

而如果A给B发了一个晚上打王者好不好,紧接着又发了一个晚上一起去吃饭好不好,而B对A的第一个问题回答好,第二个问题回答不好,但是由于网络传输的不稳定性,可能第二个回答在第一个回答之前,因此会导致理解上的差异

为了解决上述问题,我们的请求和应答报文就会进行编号,让请求和响应能够一一对应

比如,如果主机A给主机B发送1到1000的数据,主机B给主机A确认应答是1001,意思就是前面的1000个数据都收到了,该发第1001个数据了

丢包

因为网络的环境十分复杂,上网需要接入运营商的网络,而运营商有很多的路由器和交换机,这些机器上传输着很多人的数据,由于交换机的能力有限,如果数据过多,就会导致有些数据的传送超时了

超时重传

如果数据丢包了,那么就需要超时重传了
比如还是刚才那个例子,A给B发了一个在吗,如果这时候A的网不好,那么B就没收到A的消息,A一看都过了一天了B还没回我,于是A又给B发在吗

但是还有一种可能,就是B收到了A的消息,但是B的网不好,B给A发的在的丢包了,于是A还是等了一天了也没等到B的消息,于是A还是会再发一次在吗

而系统中一般会有一个配置项来确定超时时间,到了这个时间就会超时重传。而如果多次没有收到ack应答,那么这个时间就会逐渐变长,比如A一开始过了5分钟又发了一个在吗,然后过了一天又发了一个在吗,然后就再也不发了,因为多次丢包的概率是很小的,这个时候要么是运营商的交换机坏了,要么就是B不想搭理A

连接管理

我们两台主机在使用TCP进行通讯交流时会建立连接,这个连接并不是物理上用网线进行连接,而是逻辑上的虚拟连接。主机A会在自己的系统内核中记录主机B的IP,端口号,协议类型等

三次握手

这是一个双方建立连接的过程
例如A对B说,你愿意做我女朋友吗,然后B说收到你的请求,你愿意做我男朋友吗,然后A再说,收到你的请求。这样,A和B的男女朋友关系就建立好了

而在数据通信中,主机A会先给主机B发送一个报文,这个报文的SYN标志位是1,代表这是一个同步报文段,也就是请求建立连接的,而B收到后会发送一个ACK加上一个SYN,等主机A收到后,再给主机B发送ACK确认应答

建立连接就是为了确认两台主机间的网络情况是正常的,并且自己主机的发送和接收信号的能力是正常的

例如如果A和B两个人要开黑,那么A先说一个喂喂喂,这时B听到了A的喂喂喂,说明B的耳机是正常的,然后B再回复一个喂喂喂,A收到后既证明了自己的耳机没问题,也证明了自己的话筒没问题,然后A再说okok,这时B听到了证明自己的话筒也是没问题的。这三次通话缺一不可,否则就没法证明双方的耳机和话筒都是正常的了

并且,两台主机建立连接时还会确定很多参数的信息,比如TCP的序号从几开始

对应的TCP状态

LISTEN 代表服务器启动,绑定了端口,别人可以给他发送数据

ESTABLISHED 代表连接已经建立好了

四次挥手

双方断开连接的过程
主机A先给主机B发送一个报文,这个报文中FIN标志位为1,然后B立即会给A发送一个ACK表示确认收到,这个ACK是操作系统内核触发的,然后等主机B的相关工作完成后,应用程序显式的调用socket的close方法时,才会给主机A发送FIN请求,这时A再给B发送ACK

而我们的三次握手,主机B发的ACK和SYN都是系统内核触发的,因此发送的时机是一样的,因此不是四次握手而是三次握手

对应的TCP状态

CLOSE_WAIT 代表主机在等待代码中调用close方法
TIME_WAIT 主动发起关闭的一方会进入这个状态,因为自己发送的ACK不确认对方是否能够收到,如果没收到还有机会进行重传,而当两者把四次挥手都完成了,两者才会进入CLOSE状态

如果最后一个ACK丢包了,那么主机B会重发一次FIN给主机A,因此,主机A如果发送完ACK后很长时间没有收到主机B的FIN,也就说明ACK顺利到达了,于是主机A就可以CLOSE了

滑动窗口

由于我们发送消息的数目很多,因此有TCP中的滑动窗口这个机制可以提升传输的效率

如果主机A给主机B发送一条消息,等待B回复ACK后再发送第二条消息。那么这样一条发,一条接收的效率是很慢的,因此,主机A会发送一定数量的消息,然后等主机B发送完这一批的ACK后再发送下一批消息。这些数据的多少就是窗口的大小

事实上,主机A也并不是把所有ACK都接收到才开始发送下一批消息的,而是收到一部分ACK后就开始发送相应ACK数量的数据。比如一开始主机A给主机B发送了5000个数据,而主机B发送了1000的ACK,这样的话主机A就会再发1000条数据,而不是等待这5000条的ACK全部接收后再发送5000条。
这样的话我们的窗口就像滑起来一样的发送数据,也就是滑动窗口

我们的窗口越大,效率肯定也就越高,如果窗口是无穷大,那么就相当于UDP传输了,那样的话也就失去了TCP传输的可靠性,因此我们的窗口大小不能太小也不能太大

如果我们的主机A给主机B发送10000条数据,主机A先发送前5000条,然后这时1000到2000的这个数据报丢包了,此时主机B就会一直给主机A发送下一个包是1001,主机A收到多次这个消息后,就会把1000到2000这个包重新发送,这样的话,主机B就会发送下一个包是5001,也就说明2001-5000的包没有丢失,于是主机A可以正常发送5001到7000的包

流量控制

我们的滑动窗口是发送方主动对自己的发送速率做出的限制,而速率的依据应该是根据接收方接收的能力而改变的,因此流量控制这个机制就是接受方对发送方发送速率的控制,接受方使用接收缓冲区的剩余空间的大小来作为发送方的窗口大小的参考数值。

接受方收到数据后,会先放在系统内核的接收缓冲区中,等待应用层的socketAPI将数据读取走。因此,发送方和接收方就相当于生产者消费者模型,消费者吃不了那么多汉堡了,那么生产者就应该少生产一点。接受方的缓冲区已经爆满了,那么发送方就应该少发送一点数据

上面我们讲的TCP格式中有一个16位窗口大小,接受方给发送方回复的ACK报文中可以用这个来告诉发送方窗口应该调整为多大,TCP报头中还有一个特殊的值,也就是窗口大小的扩展因子,能够让窗口大小变化

例如,主机A给主机B发送数据,先发送1-1000,主机B的ACK告诉主机A下一个是1001,窗口大小3000,于是主机A就发送1001-4000,主机B收到这些数据报后分别回复窗口大小还有2000,1000,0.由于窗口已经到0了,主机A就不能再给主机B发数据了,但是由于没发报文,也就没有回应的ACK告诉窗口大小是不是变大了,因此主机A会发送一个窗口探测的包,这个包中没有别的数据,而这时如果主机B返回ACK还是下一个是4001,窗口大小是0,就说明主机B的缓冲区中的数据还没有取完。然后,等主机B处理完数据后,就会发送一个窗口更新的包,告诉主机A下一个是4001,窗口大小是2000,这样的话主机A就可以发送4001-6000了

拥塞控制

由于网络十分复杂,发送方和接收方之间有无数的交换机路由器,因此发送效率也由这些交换机的转发速率决定。这就相当于木桶原理,一个桶能盛的水由最短的板决定,而我们的发送速率也由转发最慢的交换机决定。

为了确定这个速率到底是多少,我们的发送方一开始会发一个很少的数据,然后指数增长到ssthresh的初始值(也就是初始阈值,由系统配置),这时发送速率就会变成线性增长,如果遇到了网络拥塞,那么发送速率就会乘法减少,然后再次开始指数增长,增长到新的ssthresh值(会比上一次的值有所减少)后变成线性增长。这样的话,我们的发送速率就会控制在一个合理的范围内

延迟应答

由于我们的应用数据是从缓冲区拿走数据的,而ACK应答根据缓冲区的数据多少来回复发送方应该发送多少数据。因此假如我们的缓冲区是10mb,发送方发送了5mb的数据。如果我们的接受方在收到数据后立即进行回复,就会直接回复还剩5mb空间。而如果稍微等一会,等应用层从缓冲区中读取完一部分数据,例如3mb,这样的话就可以告诉发送方还剩8mb空间了

实际上的TCP也不仅仅是利用时间衡量延迟多久发送ACK数据,也有可能根据传输的轮次进行衡量

捎带应答

由于在网络中我们的接受方也有可能是发送方,因此当我们的接受方在收到消息后,本身系统内核要立即返回ack应答的。但是由于延迟应答的机制,因此,如果延迟的时间正好赶上接受方的数据传输报文,两个报文就会合二为一,一起传输

粘包问题

TCP的数据报和UDP不同,一个UDP数据报对应一个应用层报文。而我们的TCP数据报是面向字节流的,因此有可能两个本身无联系的数据被当成一个报文一起进行解析,也有可能一个数据被当成两个报文分别进行解析。

解决办法:

  1. 报和报之间约定特殊的分隔符
  2. (在数据报的开头)申明包的长度

异常处理

当我们的发送方或接受方的机器出现问题时,TCP对应有一系列解决措施

程序崩溃

也就是我们的应用程序的异常退出。这时我们的操作系统舅舅回收进程的资源,也就会释放文件描述符表,这样的话就相当于调用了socket中的close,也就会触发FIN报文,开始四次挥手

正常关机

正常关机时系统就会强制结束各种进程,和上面一样,触发FIN报文,开始四次挥手

主机掉电

接收方主机掉电

我们的发送方发了半天数据后,没有收到ACK,就会触发超时重传,这时还没有ACK,就会尝试重新连接,TCP报文格式中的RST是1的是复位报文段,如果还是失败就会放弃连接

发送方主机掉电

接受方会隔一段时间发送一个“心跳包”,这个包不携带任何的数据,只是确定对方是不是还在,如果对方一直不回复心跳报,那么接受方就会放弃连接

网线断开

这种情况和主机掉电是一样的,发送方会尝试重新连接,发送复位报文段,而接受方会一直发送心跳报,这两者都接受不到回应,也就会都放弃连接

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:53:47  更:2022-10-22 21:55:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:43:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码