当前位置: 首页 > news >正文

网络基础二——TCP可靠性实现机制补充

11.3.4确认应答机制

​ 1.双方通信时要返回确认应答报文,保证对方发送的报文是有效的;尽管整个通信过程中无法保证数据全部可靠,但是可以保证单个方向发送的数据是可靠的;

​ 发送的报文要设置序号,如果是应答报文要设置确认序号;

11.3.5超时重传机制

​ 当报文超时或者丢包就要进行重传;丢包分为消息报文丢失和应答报文丢失;

​ 当一个报文发送出去且没有收到应答之间,这段时间是不知道报文是丢了还是还在发送的过程当中;所以必须要设置一段特殊的时间间隔,在时间间隔之内没有收到应答就认为丢包了,就进行报文重传,这种策略叫做超时重传;

​ 如果补发多次没有成功,主机就会判定网络出现了问题,连接自动断开;

​ 由于超时重传,所以接收方一定会收到多个相同的报文,导致数据不可靠,所以需要进行去重;使用序号就可以实现去重;

超时时间设置

​ 1.对于网络情况好就需要时间间隔要短;时间过长就需要等待很长的时间才重传,效率太慢;

​ 2.网络情况较差,如果设置的时间间隔较长,就会导致发一个报文就需要进行重传,产生大量的重复报文,需要进行大量的去重,使得重传和去重变成了一种负担;

​ 为了保证TCP通信的高性能,时间间隔的设置是动态的,与网络状况是有关的;Linux中超时以500ms为一个单位进行控制,每次超时重传的时间间隔都是500ms的整数倍;默认是500ms,如果重传一次之后仍然得不到应当,就等待2*500ms后再进行重传,还是得不到应答就等待4*50ms,以此类推,当达到某一重传次数时,本机的TCP就会认为网络或者对端主机出现了异常,然后断开连接;

11.3.6连接管理机制

​ TCP通信是基于连接的,在连接建立和断开的过程中会进行三次握手和四次挥手;

​ 三次握手和四次挥手的原因是,保证双方互相给对方发送消息的可靠性;其实本质上是每次发送过去的报文要保证可靠性,都要有一个应答;如果数据报文不完整,则会导致功能不完整,应答不完整就会导致数据不可靠,甚至导致报文重传还需要进行去重;

​ 是三次握手而不是四次握手是因为,通信的前提是双方都建立连接,一方建立连接另一方不建立是无意义的,所以双方都要同步的发起建立连接请求,使用捎带应答的方式提高了通信效率;而四次挥手不是三次挥手是因为,双方断开连接是需要协商的,是有时间差的;即一方完成了通信的需求,但是另一方还未完成,需要继续通信,就不可以断开连接,只有双方都完成了通信才可以断开连接,才可以使用捎带应答的方式实现"类似的三次握手",但是这种情况占少数,不采用这种方式;

三次握手的原因

​ 1.三次握手有效的保证了客户端和服务器各自至少进行了一次收和发并且是可靠的,测试了连接是否通畅;

​ 2.没有应答机制,会导致服务端直接建立连接并且承担风险,影响其他客户端;

​ 如果是一次握手并且一次握手就使得双方建立连接,客户端就会存在先建立连接,然后一直向服务端发送建立连接请求的(SYN洪水)情况,这时服务端就会建立一大批连接的结构体并管理起来,但是实际上只是用一个连接资源管理就可以了,这样就会导致资源的闲置和浪费;

​ 3.奇数次握手保证了,握手失败的连接成本嫁接到了客户端,而不是服务端接收风险,降低了对其他客户端的影响;使用三次握手使得保证可靠性的同时建立连接的成本最小;

​ 如果是两次握手,会存在服务端返回确认应答并建立连接,客户端收到应答建立连接;服务端先建立了连接,不管客户端是否异常都会默认维护连接一段时间;如果客户端异常断开了,那么这些连接实际上是无效的,无法进行通信的;因为服务器是一对多的,服务器出现了问题,所有的客户端就都不可以使用了,不应该让服务器来承担风险;三次握手保证了是让客户端先建立了连接,这样就让风险由客户端来承担,影响就减少了;

​ 其实TCP服务端在第一次握手的时候是会建立连接的,只不过叫做半连接;大量的客户端与服务端进行第一次握手时,就会将服务端的连接资源消耗殆尽;黑客可以使用恶意程序控制多台机器,定期领取任务向服务端发起第一次握手,这些机器就叫做肉机;所以一些企业实际上是会设计一些策略,对大流量的访问进行限流,防止服务器挂掉;

四次挥手的原因

​ 四次挥手保证双方都可以得知对方不发数据的意愿;如果只有一方关闭了连接而另一方并没有,其实连接是没有被关闭的,这时候另一方就可以继续发送完数据再进行关闭;此时对方就会收到数据,最后整个连接才是真正地关闭了;换句话说,关闭连接其实是不想发送数据了,就会将发送缓冲区关闭,但是接收缓冲区还在,所以还具有读的功能;

​ 四次挥手其实就是,双方互相协商,主动断开连接的一方会发送FIN,状态设为FIN_WAIT_1,服务端收到报文后,将状态设为CLOSE_WAIT并且发送ACK,客户端收到应答报文后,就会将发送缓冲区关闭,将状态置为FIN_WAIT_2不会发送数据只是发送应答报文,这时候服务端可以继续发送数据,如果服务端要关闭连接就会发送FIN并将状态置为LAST_ACK,客户端收到后将自身设置为TIME_WAIT状态(一段时间后自动设为CLOSED状态),返回应答报文,服务端接收到应答就会将自身设置为CLOSED状态;

在这里插入图片描述

11.3.7验证客户端和服务端三次握手和四次挥手时的状态

三次握手

#include <sys/types.h>        
#include <sys/socket.h>
int listen(int sockfd, int backlog);
netstat ntp
//查看连接的状态

​ 将TCP服务端套接字设置为listen状态之后,此时服务端是处于LISTEN状态的;服务端没有使用accept接口时,在收到客户端的连接请求时双方会经历3次握手,最终都处于ESTABLISHED状态;即连接的建立和accept没有关系,三次握手是双方操作系统自动完成的

​ 当listen的第二个参数设为一时,能建立连接的连接数是2;操作系统会将没有被上层accept的连接管理起来,对它们先描述再组织,并且以队列的方式管理这些连接结构;三次握手时每次形成的连接本质上就是创建一个连接结构体对象并将其链入到队列当中,而accept就是从队列中将连接取走和特定的文件关联起来,返回特定的文件描述符;listen的第二个参数+1表示已经建立好的连接队列的最大长度,这个队列叫做全连接队列;accept和连接入队还有全连接队列构成了CP模型;服务端三次握手完成或者建立连接成功就将连接入队列,如果队列满了就无法入队列了,就会将连接状态设置为SYN_RECV状态,换句话说就是因为全连接队列满了,服务端将客户端发送过来的第三次握手应答报文直接丢弃了;

​ 如果服务端长时间无法得到应答就会释放掉SYN_RECV状态的连接,这种连接叫做半连接;半连接也需要进行管理,所以也会存在半连接队列,节点并不会长时间维持;

​ 这样就出现了客户端和服务器连接不一致的问题;服务端直接将应答丢弃,但是确实是收到了应答,所以第二次握手时可靠的,知道客户端建立连接成功了,并不会发送RST标志位;对于客户端建立连接成功了,但是发送数据不成功,就转而继续开始进行三次握手;

​ 大量建立半连接会导致真正地SYN洪水;服务器资源有限制不会挂掉,但是其他客户端就无法正常的访问了;

​ 全连接队列长度不可以太长,因为上层处理繁忙时,就无法保证将全连接队列获取完,而队列长度过长就会导致资源闲置,维护还要有成本,而且变相地减少了上层空间,降低了处理的效率;而队列的存在可以保证,半连接变成全连接和全连接被上层处理可以并发运行;所以一般全连接队列的长度一般要设置为10左右;

相关文章:

  • Composer常见错误及解决方法
  • 金融中的数学知识
  • 内部类(InnerClass) 总结
  • 计算机网络-从输入网址到访问网站的全过程
  • 金融数据_PySpark-3.0.3随机森林(RandomForestClassifier)实例
  • AI大模型与网球运动结合的应用场景及案例分析
  • 精品PPT-2023年无人驾驶汽车车联网网络安全方案
  • Unity开发者3D模型基础
  • Java中的try catch finally结构
  • MongoDB聚合运算符:$maxN
  • 前视声呐目标识别定位(二)-目标识别定位模块
  • Rust egui(4) 增加自己的tab页面
  • 将打印jar包直接打包成windows的插件,然后通过调用插件的接口地址将流传到接口实现解析并无需预览直接打印PDF
  • android studio中添加module依赖
  • Spirngboot JWT快速配置和使用
  • hexo+github搭建个人博客
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 2017 前端面试准备 - 收藏集 - 掘金
  • PaddlePaddle-GitHub的正确打开姿势
  • scala基础语法(二)
  • Swift 中的尾递归和蹦床
  • ------- 计算机网络基础
  • 扑朔迷离的属性和特性【彻底弄清】
  • 悄悄地说一个bug
  • 通过几道题目学习二叉搜索树
  • 微信公众号开发小记——5.python微信红包
  • 微信支付JSAPI,实测!终极方案
  • Java总结 - String - 这篇请使劲喷我
  • 函数计算新功能-----支持C#函数
  • ​你们这样子,耽误我的工作进度怎么办?
  • ​香农与信息论三大定律
  • ​学习一下,什么是预包装食品?​
  • (27)4.8 习题课
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (五)c52学习之旅-静态数码管
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (转)一些感悟
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .Net Core和.Net Standard直观理解
  • .net 使用ajax控件后如何调用前端脚本
  • .so文件(linux系统)
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @Service注解让spring找到你的Service bean
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [2021 蓝帽杯] One Pointer PHP
  • [BJDCTF2020]The mystery of ip1
  • [BUUCTF]-PWN:[极客大挑战 2019]Not Bad解析
  • [C++打怪升级]--学习总目录
  • [C语言]一维数组二维数组的大小
  • [git] windows系统安装git教程和配置