【网络面试(5)】收发数据及断开服务器(四次挥手)

 前面了解到服务器和客户端在创建套接字,建立连接后,就可以进入到下一步,双发可以互相发送和接收数据,本篇博客就来学习一下这个过程。
 我们印象里,发送数据应该是我们在浏览器输入网址,敲击回车的一瞬间,发送动作就完成了,回头服务器处理完成将数据发送客户端,浏览器解析出来,这就是反过来接收的过程。

1. 发送数据

 由浅入深,了解这个大体过程,我们先来看看发送数据的简单过程。对于浏览器,他没有办法直接向网络中发送数据,而是要将http请求委托给协议栈(操作系统的网络控制软件)来发送。但实际上,在计算机中,并不是只有浏览器会发送网络请求,QQ、微信等很多应用程序都会执行这个动作。所以协议栈工作就是会接收各种应用程序发送过来的网络请求数据,其实就是一堆的二进制字节数据。

 协议栈在拿到数据后,是不是会直接发送到网络中的呢?必然不是,他在内部会维护一段内存缓冲区,等待下一段数据,然后在某个合适的时机再发送出去。这块内存就是发送数据的专用缓冲区。当然,接收数据的时候也是有一块专用内存的,后面我们再说这个。这里还提到了,合适的时机发送数据,这个时机是根据两个要素来判断的,我们看看是哪两个。

1.1 网络包长度

 第一个因素是跟网络包长度相关的,什么意思呢,对于某些GET请求,要发送的请求内容必然很少,一个网络包就能放得下,但是有些POST请求,比如我要写的这篇博客,经过编码解析,需要很多歌网络包才能放的下,这里就涉及到拆包的概念。

 这里先了解两个网络词汇:MTUMSS

  • MTU: 指的是一个网络包的最大长度,以太网中通常是1500个字节。
  • MSS: MTU中去掉头部之后,所能容纳的数据的最大长度。

在这里插入图片描述

 了解这两个概念,我们在来看下上面说的拆包的概念,即我们发送的某次网络请求,可能是通过1个网络包发送给服务器的,也可能是很多个,决定因素就是MTU和MSS。

 在应用程序将数据发送给协议栈的时候,数据可大可小,协议栈无法决定,如果每次接收到应用程序的一次数据就立即发送出去,必然会导致发送大量小的网络包,网络效率下降。所以,协议栈一般会累积到数据量可以塞满一个网络包的时候再发送出去,即MTU的长度,这就是第一个决定协议栈发送数据的因素。

1.2 发送时间

 决定协议栈 发送数据的第二个因素是时间,为啥呢?我们可以试想一下,如果GET请求的数据长度无法达到一个MTU的长度,协议栈一直等待到一个网络包的数据长度再发出去,必然会产生很大的延迟,给我们卡顿的感觉。所以,某些情况下,即便网络包没有被填满,也会立即把数据发送出去。
 协议栈内部会维护一个计时器,在超过设定的时间阈值后,即便没有达到一个完整网络包数据长度,也会立即发送。一般,这个时间是由协议栈的开发者决定的,不同操作系统的不同版本会有不同实现。

 其实,决定协议栈发送数据的这两个要素,在某些情况下是比较矛盾的,立即发送会导致网络效率下降,等待太久又会造成延迟。过分依靠协议栈来决定发送时机会带来一些问题,所以协议栈也给了应用程序一个选项,来决定是否立即发送。像浏览器这样的会话型应用程序,一般会选择“立即发送”的选项。

2. 确认发送成功以及重发功能的实现

 TCP协议的非常重要的功能就是可以确认通信的一方是否已经成功收到了网络包,如果没有收到,必须具有重发的功能。这个功能的实现就是借助于ACK号和seq序号要进行对方接收确认的操作。

 上文我们说过,在网络请求内容过大的时候,TCP会有拆包的逻辑,那么在拆分的过程中,TCP就会计算好并记录每个网络小包在整个请求内容中处于第几个字节,然后再发送网络包的时候,在TCP头部记录这个字节数(就是seq序号,比如目前是第1个字节),服务器在接收到网络包的时候,会读取这个字节,然后再计算这个网络包MSS的长度(比如网络包数据长度是1000),在确认回复的时候,会将ACK赋值为ACK = 1 + 1000 并返回给客户端。客户端在接收到ACK号的时候就可以确定网络包已经顺利被对方接收,否则就会重试发送。

 我们可以想象一下,客户端在发送下一个网络包的时候,一定是从第1001个字节开始的,于是服务器在收到请求后,可以顺便验证1001是不是和自己最后一次ACK响应的字节数相等,如果相等说明中间没有丢包,如果是2001,说明中间丢失了至少一个网络包。

 这里我们已经提到了ACK和seq,TCP协议可以通过ACK号和序号就可以确认对方是否收到了网络包。我们来看一个虚拟的例子加深一下了解。

在这里插入图片描述

2.1 调整ACK号等待时间

 我们的网络传输并不是一帆风顺的,发生拥塞和抖动的情况是非常常见的。前文我们提到TCP会通过ACK号确认对方已经接收到网络包,但是在网络比较慢的情况下,发送和接收ACK号的平均响应时间就会比较长了,如果客户端在这个时候设置了比较短的等待时间,就会在没收到ACK的情况一直向以太网中发送数据,这对于本来已经繁忙的网络就更加糟糕了,这其实就是TCP的网络包重传。

 通常,当网络包重传发生后,有可能前一个相同网络包的ACK号才返回,这样的重传其实是不必要的。所以,对于等待时间来说,需要设置一个合适的值,这个时间应该是可以动态调整的,而计算方法就是根据过往发送数据的过程中,持续监测ACK号的响应时间,如果ACK号的返回时间变慢,就会响应延长这个等待时间,否则就缩短等待时间。

 除此之外,TCP还是使用了滑动窗口的方式来管理数据发送和ACK号的管理,大体思路就是第一个网络包在发送出去之后,并不是等待当前网络包的ACK号返回才发送下一个,而是直接发送下一个,或者说是下面一系列的网络包,这样的话,发送的等待时间就会被有效的利用起来了。这个过程相对复杂一些,涉及到窗口大小的概念,这个窗口大小就是指接收方网络协议栈中,在当前时间里,剩余的最大缓存空间,也就是能接收的字节数。下图中可以看出来一来一回和滑动窗口的方式,这里不再深入展开,可以查看相关资料。

在这里插入图片描述

3. 接收数据

 在客户端发送完数据的过程后,服务器端就可以接收并处理网络包了,对于单个网络包的处理比较简单,对于客户端拆分后分多次发送的网络包,服务器的TCP协议同样会以相同的方式拼接起来转换成为对应的网络请求,其实就是和客户端处理相反的方式进行的。服务器在处理请求后,就会将相应数据发送给客户端。

 我们可以想一下,客户端的浏览器程序在委托协议栈发送了网络请求后,就处于等待响应结果的状态。这个状态其实是浏览器调用了Socket组件库的read()函数,协议栈会将这个工作挂起,直到服务器数据相应之后,协议栈写入到接收缓冲区中,在这个过程之前,接收缓冲区一直是空的,浏览器就无法处理数据,这个挂起就是我们常说的阻塞过程。这个如果继续延伸的话,会有阻塞式IO,非阻塞式IO,IO多路复用等知识点,在此不深入。

 总结一下这个过程,客户端的协议栈会检查接收到的数据和TCP头部的内容,判断是否有数据丢失,如果没有问题会向服务器返回ACK号。然后协议栈将接收到的数据暂存到接收缓冲区(这个缓冲区是协议栈的)中,然后将数据块按照顺序连接起来还原成原始的数据,最后将数据交还给应用程序,其实是把协议栈缓冲区中的数据复制到浏览器制定的内存地址中,然后浏览器去解析的过程(这个过程还是在read里面实现并把控制流程交还给浏览器的)。

4. 断开连接

 接下来最后一个流程,就是数据发送完成之后的断开连接了,那么断开连接这个操作是由客户端还是服务端发起的呢?
 在协议栈中并没有规定哪一方应该先发起断开操作,通常是由应用程序判断自己的数据已经发起后就可以发起断开动作了。比如我们访问web服务器,发送请求,服务器接受请求处理完成会向客户端返回数据包,等到所有数据都返回了,服务器会主动发起断开操作。下面,我们就以这个例子,服务器先发起断开操作理解这个过程。

 所谓的断开操作也是由发起方调用Socket库的中close()程序实现的,在这个方法中,协议栈会生成包含了断开控制信息的TCP头部,具体来说就是将FIN比特位设置1,然后再委托IP模块将数据发给客户端,接下来,服务器套接字中就会记录下断开操作的相关信息。

 接下来看我们的客户端,在接收到FIN比特位为1的包时,客户端知道了,噢服务器要断开连接了,那好在自己的套接字中标记一下要进入断开操作了,记住这里只是标记一下,同时必须要返回服务器ACK号,告知服务器已收到FIN=1的断开网络包了。

 然后,待到客户端协议栈接收缓冲区数据被应用程序全部取走之后(前面讲到的应用程序的read()操作),客户端感觉时机成熟了,也会向服务器发送一个包含FIN=1头部的网络包,服务器同理也要返回ACK包,至此,双方的通讯正式结束。

在这里插入图片描述

5. 删除套接字

 接下来断开操作的最后一步就是删除套接字,这里尤其注意用来通讯的套接字不会立即删除,而是会等待一段时间后再删除,具体原因如下:

 我们现在举个跟上面相反的断开的例子,由客户端发起断开请求:

  • 客户端发送FIN=1
  • 服务器返回ACK
  • 服务器发送FIN=1
  • 客户端返回ACK

 这里特别注意最后一步,客户端在返回ACK号之后,如果立即删除套接字会发生什么呢?正常情况,可能是服务器收到客户端的ACK号双方通讯结束没问题。但是如果因为网络拥塞问题,服务器没有在规定时间收到第四步的ACK号,那么服务器又发送了一次FIN=1,这里可能会有问题了,因为客户端已经删除了套接字,此时如果恰巧又其他应用程序请求连接服务器并且创建了相同端口号的套接字,那么这个新创建的套接字因为收到了一条莫名奇妙的FIN=1就要进入断开操作了,就会有问题了。所以客户端并不会立即删除套接字,就是为了防止这个问题发生。
 通常,这个等待删除套接字的时间就是几分钟而已。

6. TCP的整体流程

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/590543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NGUI基础-三大基础组件之Panel组件

目录 Panel组件 Panel的作用: 注意: 相关关键参数讲解: Alpha(透明度值): Depth(深度): Clippinng(裁剪): ​编辑 None Tex…

Redis(Linux版本7.2.3)

1、停止Redis服务器 [roottssvr1-c1 sysconfig]# ps -ef | grep redis root 322 1 0 10月30 ? 02:58:53 ./bin/redis-server 0.0.0.0:6379 root 32664 12498 0 14:45 pts/0 00:00:00 grep --colorauto redis [roottssvr1-c1 sysconfig]# [roottssvr…

VMware虚拟机和Centos7镜像安装

文章目录 安装VMware虚拟机1、下载2、激活 安装Centos7镜像启动虚拟机 安装VMware虚拟机 1、下载 建议还是安装16版本 VMware16下载 https://www.123pan.com/s/HQeA-aX1Sh VMware15 链接:https://pan.baidu.com/s/11UD1hb6IydbxNNPxmh-MqA?pwd0630 提取码&am…

PiflowX组件-JDBCRead

JDBCRead组件 组件说明 使用JDBC驱动向任意类型的关系型数据库读取数据。 计算引擎 flink 有界性 Scan Source: Bounded Lookup Source: Sync Mode 组件分组 Jdbc 端口 Inport:默认端口 outport:默认端口 组件属性 名称展示名称默认值允许…

simulink代码生成(五)——SCI接受模块;如何将串口发送的数据显示在matlab中

首先,实现DSP28335的自收自发; 添加串口收发模块; 设置参数,根据硬件选择串口模块: 配置中断触发;SCIB的接收中断的CPU中断号为9,PIE级中断为3; 因此如下配置; 代码生成…

Hive06_基础查询

HIVE 查询语句 1 查询语句语法: SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference [WHERE where_condition] [GROUP BY col_list] [ORDER BY col_list] [CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list] ] [LIMI…

C++ 类和对象 (中)

默认成员函数: C环境下每一个类在定义是时编译器会自动生成六个成员函数(在没有显示定义的情况下),分别是构造函数、析构函数、拷贝构造函数、赋值运算符重载、普通变量和const常量的取地址重载,它们大大弥补了原先C语…

QT上位机开发(图形绘制)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 图形绘制是上位机软件开发很重要的一个功能。这个图形绘制,有的是离线的,有的是实时绘制的。就我个人而言,离线…

JoySSL怎么样

JoySSL是一家专业的SSL证书服务提供商,致力于为网站和在线业务提供最佳的安全加密解决方案。以下是JoySSL的一些优点: 提供多种类型的SSL证书选择:JoySSL提供单域名、多域名、通配符等不同类型的SSL证书,以满足不同网站的需求。证…

【嵌入式】飞凌嵌入式ELF1开发板 初体验 | 嵌入式Linux开发

文章目录 前言一、开机初体验1.1、开机1.2、连接WIFI 二、基本功能测试2.1、主板命令行测试2.1.1、TF卡热插拔测试2.1.2、LED命令行测试2.1.3、数据库测试 三、基础编程实战3.1、交叉编译链部署3.2、温湿度传感器程序3.3、看门狗程序3.4、六轴传感器程序3.5、MQTT物联网 bug记录…

ROS TF坐标变换 - 动态坐标变换

目录 一、动态坐标变换(C实现)二、动态坐标变换(Python实现) 一、动态坐标变换(C实现) 所谓动态坐标变换,是指两个坐标系之间的相对位置是变化的。比如机械臂末端执行器与 base_link 之间&…

渗透线上下料控制(SCL源代码)

有关渗透线的其它详细介绍请参考下面链接文章: https://rxxw-control.blog.csdn.net/article/details/133611151https://rxxw-control.blog.csdn.net/article/details/133611151这里的渗透线上下料属于整个渗透线流程里的最前端和最后端,分别负责待处理…

《Linux系统与网络管理》复习题库---简答题

1、简述这些分区的名字以及各自的作用。 答: /boot 存放内核镜像的地方,这个文件夹独立分区的意义在于降低不能开机的风险。 /根目录,一般采用 ext3 文件系统,分区的容量一定要大于安装软件包的容量。 /usr 多数软件的默认安装的地…

Anaconda3 2021.11安装

1. 镜像下载:Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2. 安装在D盘: 3. 配置环境变量: 在这里,第一个教程A在系统变量里配置了五个,但我没有 所以又搜了教程B&#xf…

扎根底层技术,推动机器人换代式升级

热赛道和冷市场的矛盾之下,机器人需要一次换代式升级。 冷中有热的资本市场 在宏观经济下行的影响下,我国服务机器人产量从2022年开始出现明显放缓,2021年12月至2022年12月,我国服务机器人产量都处于同比下滑的状态,…

LeetCode每日一题.05(N皇后)

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。 每一种…

以元旦为题的诗词(三)

愿新的一年给我们带来无尽的好运和幸福愿我们的梦想在新的起点绽放! 让我们在未来的日子里书写新的篇章! 接着分享几首以元旦为题的几首诗,喜欢的朋友可以自取,想要更多免费的诗词,请自行百度或小程序搜索:美诗计 元旦 元旦佳节…

剑指“CPU飙高”问题

一、什么是cpu飙高? 一般指程序运行时cpu占用率过高   linux系统中,我们使用top命令,会看到正在运行进程的cpu使用率等,同时在最上面也会看到总的cpu使用率,当总的cpu使用率过高,如果有运维监控平台&…

【Linux】理解文件系统

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 了解磁盘1.1 磁盘的物理结构1.2 磁盘的逻辑结构1.3 磁盘的存储结构 2. 文件系统2.…

2023年12月编程语言排行榜

TIOBE Index for December 2023 December Headline: C# on its way to become programming language of the year 2023 2023年12月的TIOBE指数&#xff1a;12月头条:c#将成为2023年最佳编程语言 Yes, I know, we have been here before. At the end of 2022, it looked like …