浅谈网络通信(2)

文章目录

  • 一、TCP
    • 1.1、TCP提供的api —— ServerSocket 、Socket
    • 1.2、使用TCP协议编写回显服务器
    • 1.3、长/短连接
  • 二、应用层协议、传输层协议详解
    • 2.1、应用层(后端开发必知必会)
      • 2.1.1、自定义应用层协议
      • 2.1.2、通用的协议格式
        • 2.1.2.1、XML
        • 2.1.2.2、json
        • 2.1.2.3、protobuffer
    • 2.2、传输层
      • 2.2.1、UDP

一、TCP

TCP服务器端需要做的事:
1、获取连接
2、处理连接:(1)、读取请求并解析 (2)、根据请求计算出响应 (3)、写回响应
TCP客户端需要做的事:
1、构造请求并发送
2、从服务器端获取响应
3、把响应显示

1.1、TCP提供的api —— ServerSocket 、Socket

1、ServerSocket:
ServerSocket 是提供给服务器使用的类。
由于TCP特点是有连接的,因此TCP服务器启动后的第一件事不是读取客户端请求,而是先处理客户端的 “连接”。

握手是由系统内核负责的,写代码过程中无法感知到握手的过程,写代码时主要是处理连接,连接是握手之后得到的东西,是比较抽象的,就是说客户端和服务器彼此保存了对方的信息,这个抽象的连接是由系统内核完成的)。

一个服务器要对应很多的客户端,因此内核中的连接很多,这些连接就像一个一个的待办事项,这些待办事项存储在一个队列这样的数据结构中,应用程序就需要从队列中一个一个的取出连接,完成这些连接任务。

2、Socket:
既会给服务器使用,也会给客户端使用。

TCP传输数据的基本单位是 字节流,一个TCP数据报,就是一个字节数组 byte[] buf。

1.2、使用TCP协议编写回显服务器

使用TCP协议编写回显服务器的源码地址
代码详解:
1、serverSocket.accept():把内核中的连接获取到应用程序中。(但是此处的返回值并非是一个 “Connection” 这样的对象,而是一个 Socket 对象,这个 Socket 对象,就像一个耳麦一样,拿着它既可以讲话让对方听见,也可以听到对方讲话的声音(是TCP全双工的表现))。
这个过程类似于 “生产者消费者模型”。

在这里插入图片描述
但有可能出现一种情况:即当程序执行到代码serverSocket.accept()时,有可能此时服务器还没有客户端连接,那么此时队列中也就没有任何连接,应用程序也就从内核中取不到任何连接,此时程序就会阻塞在accept()方法这里,直到有客户端连接成功为止。(一次IO分两个部分:1、等待(阻塞)。2、拷贝数据)

为啥建立连接要进行握手??就像相亲时不可能双方一见面就马上结婚(结婚也是一种抽象的连接),必须有一个相互了解的阶段。此处衍生出一个重要的面试题:TCP的3次握手和14次挥手。(后面再详解)

2、在TCP服务器代码处,有两种 Socket 对象,一种是 ServerSocket ,一种是 Socket 。
在这里插入图片描述
那这两种 Socket 有什么区别?
serverSocket 就像面包店外试吃区的销售人员,socket 就像面包店里售卖面包的销售人员。试吃区的销售人员其实就是在为面包店拉客,面包店里的销售人员会给被试吃区拉来的顾客详细介绍店里的面包种类,来进一步吸引顾客购买。这两种销售人员虽然有不一样的称呼,但是他们的目的都是为了销售面包店里的面包给顾客。

ServerSocket 只有一个,生命周期跟随程序,不关闭也没事。但是对于 Socket 来说,一定要关闭。如果有1w个客户端连接,就会有1w个Socket,此处的 Socket 是被反复创建的,因此对于 Socket 来说,必须确保连接断开之后会被关闭!否则就会发生文件资源泄露,导致整个程序被带走。

3、在TCP服务器代码中,通过方法 processConnection() 处理客户端的一个连接,由于accept() 方法会阻塞,因此需要借助线程池来处理客户端的连接。当只有一个执行流时,accept()方法处发送阻塞会导致其他连接了服务器的客户端没办法继续执行,这显然不符合一个服务器的执行常理,因此服务器端需要借助线程池的多个执行流处理客户端的连接。

在这里插入图片描述
其实我们的服务器代码没加上线程池前,会出现一个问题:当第一个客户端连接好了之后,第二个客户端,不能正确被处理:即此时服务器看不到客户端上线,同时客户端发来的请求也无法被处理。当第一个客户端退出之后,之前第二个客户端发来的请求,就能正确的响应了。

在这里插入图片描述
但是对于服务器来说,服务器是能够同时处理多个客户端的请求,因此上述第一个客户端连接执行完毕后,第二个客户端连接才能被处理这种做法是不正常的,因为一个客户端连接不知道什么时候才能执行完,一个客户端连接是可以进行很多个请求、响应的,因此对应的也就不知道accept()方法的阻塞什么时候才能结束,因此想要解决accept()的阻塞,可以使用线程池来解决该问题,使用线程池后程序中就可以含有多个执行流,既可以执行accept(),也可以执行processConnection()方法。一个执行流执行processConnection()方法,另一个执行流也能快速调用到accept()。不使用线程池也可以,只要是多线程方式都可以解决该问题。(在网络编程中,多线程会常常使用到)

还有一个问题
有些同学可能会在TCP服务器端写出这样的代码:
在这里插入图片描述

还有问题:我们引入了 线程池 解决了 accept() 阻塞问题,但是线程池也是有开销的,在服务器对应的客户端很多的情况下,服务器就需要创建出大量的线程去处理客户端连接的任务,此时服务器的开销是很大的,响应速度也会大打折扣。那么是否有办法,使用一个线程或者3、4个线程就能让服务器高效的处理客户端的并发(几万/几十万客户端)请求?

其实随着互联网的发展,客户端会越来愈多,请求也越来越多,C10M就出现了。C10M:同一时刻,有1kw的客户端并发请求。此时服务器的负担真的很大,因此引入了很多技术,其中一个很有效的手段就是:IO多路复用!(一种节流的方式,在同样的请求下,消耗的硬件更少了,本质上就是减少线程的数量)。

解决高并发,其实就是两步走:1、开源:引入更多的硬件资源。2、节流:提高单位硬件资源能够处理的请求数,同样的请求数,消耗的硬件资源更少。

4、String request = sc.next();
此处使用 next() 读取数据,一直读到空白符算结束。那什么是空白符?包括但不限于:换行符(\n:让光标另起一行)、回车符(\r:让光标回到行首(不会另起一行))、空格键、制表符、换页符、垂直制表符…

5、PrintWriter

在这里插入图片描述
访问IO比访问内存的开销大,因此进行IO的次数越多,程序的速度越慢。因此通常会使用一块内存作为缓冲区,写数据的时候,先写到缓冲区里,缓冲区里攒一波数据,统一进行IO。而 PrintWriter 内置缓冲区。printWriter.flush() 是进行手动刷新,就是确保缓冲区里的数据真的通过网卡发出去了,而不是残留在内存缓冲区里,缓冲区内置了一定的刷新策略,例如缓冲区满了,就会触发刷新,例如程序退出,也会出发刷新。

6、
在这里插入图片描述
流对象中持有的资源,有两个部分:1、内存(对象销毁,内存就会被回收)。2、文件描述符。

当 while 循环一圈,内存自然就会被销毁。 在我们服务器端的代码,Scanner 和 PrintWriter 没有持有文件描述符,他们持有的是 inputStream、outputStream 的引用,当 inputStream、outputStream 被销毁之后,Scanner 和 PrintWriter 也都被销毁了;而 inputStream、outputStream 是被 Socket 对象持有的,因此当 Socket 对象被关闭之后,inputStream、outputStream 也就随之被销毁了。

1.3、长/短连接

TCP程序时,涉及到两种写法:1、短连接:一个连接中只传输一次请求和响应。2、长连接:一个连接中可以传输多次请求、连接。

二、应用层协议、传输层协议详解

2.1、应用层(后端开发必知必会)

2.1.1、自定义应用层协议

应用层这一层,有很多现成的协议,也有很多时候,需要我们程序员自己去自定义应用层协议。自定义应用层协议,也是一件很简单的事情。

举个例子:此处有一个需求场景:一个外卖软件,需要在用户打开此软件时,给用户显示用户住址附近的商家列表,列表中有很多项,每一项都包含了一些信息:譬如:商家名称、商家图片、商家店铺好评率,商家与用户的距离、商家评分…(其实外卖软件和服务器之间的沟通,有很多种方式,展示商家列表,只是其中之一)

客户端(用户…):需要给服务器发起一个请求,服务器收到请求之后,就给客户端返回一个响应。[!]那么这个请求里应该包含什么信息呢??该请求应该按照什么格式组织呢??同样的,这个响应应该包含什么信息??应该按照什么格式解析??

此时程序就应该做出如下设计:
1、明确当前程序的请求和响应中都包含哪些信息??(一般在实际开发工作中,请求和响应中都包含哪些信息是根据需求文档里标的来写的)
2、明确具体的请求和响应的格式。[所谓的“明确格式”就是看你按照啥样的方式构造出一个字符串,后续这个字符串就可以作为 tcp/udp的payload进行传输]

明确具体的请求和响应的格式:
示例1:假设此处的请求包含的信息:用户身份、用户当前位置;响应包含的信息:商家名称、商家图片、商家好评率、商家距离用户的位置、商家评分…
请求:1234,80 100\n
响应:蓝胖子肉蟹煲,1.jpg,98%,1km,4.9\n 美蛙鱼头,2.jpg,95%,2km,4.2\n \n
示例1 的响应使用\n来分割每条商家信息。

示例2:
请求:1234;80,100.
响应:蓝胖子肉蟹煲;1.jpg;1km;98%;4.7!美蛙鱼头;2.jpg;2km;95%;4.2!.
示例2 的响应使用!来分割每条商家信息。
其实我们可以看到示例2的商家列表的信息顺序跟示例1并不一样,这是因为这些都是可以自定义的,不需要一样。

示例3:
在这里插入图片描述
从上述几种示例可知,请求和响应的数据组织格式非常灵活,程序员想怎么组织就怎么自定义,当然了,自定义的时候必须要能够保证客户端和服务器这边使用的是相同规则即可。因为在实际开发中,客户端和服务器,往往是由不同的人员负责,因此开发之前,双方就必须共同约定好请求和响应的数据组织格式。

虽然说程序员可以自定义应用层协议,但是为了避免出现过于天马行空的设计,此时行业标准就规定了一些“通用的协议格式”,程序员开发时参考这些格式,就可以在自定义应用层协议时更加严谨、正确。

2.1.2、通用的协议格式

2.1.2.1、XML

xml:是以成对的标签来表示键值对的信息,标签支持嵌套,就可以构成一些更复杂的树形结构数据。
以上面的外卖软件例子为例,使用xml格式来表示 请求:

<request><useId>1234</useId><position> 80 100</position>
</request>

响应:

<response><shops><shop><name>蓝胖子肉蟹煲</name><image>1.jpg</image><distance>1km</distance><rate>98%</rate><star>4.7</star></shop><shop><name>美蛙鱼头</name><image>2.jpg</image><distance>2km</distance><rate>95%</rate><star>4.2</star></shop></shops>
</response>

上面的 xml 格式表示的是 键值对 结构。key:userId,value:1234。其实对象本质上也是键值对,属性的名字就是 键,属性的值就是 值。

xml 优缺点:
优点:非常清晰的将结构化数据表示出来了。
缺点:表示数据需要引入大量的标签,看起来繁琐,同时也会占用不少的网络带宽。

其实我们有没有觉得 xml 的编写形式和 html 有些类似,html是编写网页的语言,也是以标签的形式出现。但是 xml 里的标签是程序员自定义的,html 里的标签是有自己的一套使用标准的。(可以把 html 视为是 xml 的特化版本)

2.1.2.2、json

json,当前最主流的一种网络传输数据的格式,本质上也是键值对,但json看起来,比 xml格式 简单便捷、干净很多;json对于换行并不敏感,如果这些内容全都放在一行,也是完全合法的。

一般网络传输时,会对json进行压缩(即去掉不必要的换行和空格),同时把所有数据都放到一行去,要传输的数据其整体占用的带宽就降低了。但可能这样的压缩会影响可读性,不过可以使用一些现成的 json 格式化工具恢复json原有的格式。

在json中,使用 { } 表示键值对,使用 [ ] 表示数组,数组里的每个元素,可以是数字、字符串、字母、或者是其他的 { } 、[ ]…

json格式的请求:
{
userId:1234,
position:“100 80”
}

响应:
{
{
name:“蓝胖子肉蟹煲”
image:“1.jpg”,
distance:“1km”,
rate:98%,
star:4.7
}

{
name:“鱼头”
image:“2.jpg”,
distance:“2km”,
rate:95%,
star:4.2
}
}

json优点:相比于 xml ,表示的数据简洁很多。

2.1.2.3、protobuffer

protobuffer是谷歌提出的一套二进制数据序列化方式,使用二进制的方式,约定几个字节,表示哪个属性。

优点:可以最大程度上节省空间,节省带宽,最大化效率。即不必传输 key,可以根据位置和长度,区分每个属性。
缺点:是二进制数据,无法直接肉眼直接观察,不方便调试。

这类格式很有可能会在工作中用到,尤其是在一些规模复杂的后端服务器。

Java标准库提供好了上述3种序列化方式(数据组织格式),而其他的第3方库,提供的方式更加丰富,后续再介绍。

2.2、传输层

传输层最常见的协议是 UDP、TCP,学习一个协议,不仅要掌握协议的特性,还需要理解协议报文格式

2.2.1、UDP

在这里插入图片描述
我们都知道 UDP 载荷部分里是应用层数据报,那么UDP报头里都有啥,都是啥信息??[重点理解]
在这里插入图片描述
从上图知:一个 UDP报头 含有4部分:1、源端口号。2、目的端口号。3、UDP报文长度。4、校验和。这4个部分都是2个字节的长度,那2个字节,表示的数据范围有多大(这可是最基本的知识点,必须牢记):
(1)、1字节:
有符号:-128 ~ +127
无符号:0~255
(2)、2字节:
有符号:-32768 ~ +32767
无符号:0~65535
(3)、4字节:
有符号:-21亿 ~ +21亿
无符号:0~42亿9千万

在程序中,程序员设定某个这些基本单位时,一定一定要小心,不然程序极易出现错误:

例子1:假如一家游戏公司,使用单位为2字节的某个字段实现游戏的某个功能,我们知道2字节可以表示的数据范围为:0~65535,那么用户在玩游戏时,疯狂玩,此时其收获的成绩峰值就极速上升,上升至了6w,用户还不满足,希望自己的战绩能更好,再继续疯狂玩,但却突然发现,自己的战绩却从6w跌至0。这是不应该的,表示此时程序出现了bug。其实原因就是因为使用了2字节的字段作为表示用户战绩情况,2字节的数据表示范围:0 ~ 65535,当达到最大值之后,数值就无法再继续增大了,会从0重新开始。因此,程序中使用某个字段表示某个功能时,其字段的选择应该要慎重、要考虑其缺陷性。

例子2:假如我们在工作中,被安排了一个任务:记录这一天,公司的搜索浏览器一共有多少请求?假设公司搜索浏览器每天的请求量在10亿量级,此时记录请求的变量,是使用 int 还是 long 类型??

注意:10亿量级,是只有10亿吗??量级此单位,其实是2倍,10亿量级,其实是21亿多。那么此时,变量使用int就不合适了,因为int能够表示的数据范围是 0~65535,变量可以使用long类型,long类型的数据表示范围为 0 ~ 42亿9千万,此时该数据范围完全可以表示 21亿 。

报文长度:
UDP报文长度2个字节,通过换算单位,可得到64kB,因此一个 UDP数据报其最大长度就是64KB(2个字节 = 216,210 = 1KB, 1KB*2^8 = 64KB),那如果说,当前程序使用UDP协议通信,程序想发送的数据超过了64KB,此时怎么使用UDP数据报来携带已超过协议最大长度的数据进行网络传输?1、可以把数据拆分成多组,通过几个UDP数据报进行传输;2、使用 TCP 代替 UDP ,因为 TCP 没有长度限制。不管用啥办法,反正UDP就是不能超过它的最大长度。因为当时行业标准设定UDP的最大长度就是64KB,我们只能遵守这个规则。

源端口、目的端口:
UDP端口号长度2个字节:可以看到 UDP报头 包含 源端口和目的端口,因为端口号使用2字节表示,因此端口号的数据表示范围为0~65535,但对于 1 ~ 1024 的端口号范围,这个范围的端口号已经被一些知名的程序的服务器占用,因此我们写的服务器,很少会用1 ~ 1024 范围的端口号来表示了,一般都是使用 1024之后的端口号表示,不过 1024 之后的端口号也有一些已经被知名程序的服务器占用了,如 3306 已经被 MySQL 程序占用了。

校验和:
其实在网络传输中,受到外界的干扰,传输的数据很容易出错,因为数据传送过程中,本质上是 光信号/电信号/电磁波,这些形式很容易受到磁场、高能粒子射线的干扰。此时就会导致本来你要传输的数据发生比特翻转,如 0 ——> 1、1 ——> 0…此时接收方接收到的数据就是错的。尤其是UDP的长度是64KB,遇上大过64KB的数据就需要进行拆分,将数据分成多组UDP数据发送,此时拆分的数据虽然说是传输过去了,但是对于接收方来说,还需要将数据拼接起来,此时怎么拼接?拼接过程发生了差错怎么办??怎么校验差错??那么,此时协议就通过 校验和 来对网络传输过来的数据进行校验,查看当前数据是否出错。实际的校验和,是会根据数据内容来生成,因此当数据出错,校验和就能感知到数据出错。校验和使用的是CRC校验算法(循环冗余校验和):即把UDP数据报中的每个字节都依次进行累加,把累加结果保存到2个字节的变量中,加着加着,可能就溢出了,但溢出也无所谓,所有字节都加了一遍,最终就得到了校验和。其实在传输数据时,就会把原始数据和校验和一起传递过去,接收方收到数据,同时也收到了发送端传送过来的校验和(旧的校验和),接收方按照同样的方式再算一遍,得到新的校验和。如果新的校验和 与 旧的校验和 相同,则可以视为数据传输过程中,数据是正确的,未发生差错;否则则反之。但是需要注意:数据相同,可推出校验和相同;校验和相同,无法推出数据相同!

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

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

相关文章

Protected and unprotected Meilisearch projects(/health)

Elasticsearch 做为老牌搜索引擎&#xff0c;功能基本满足&#xff0c;但复杂&#xff0c;重量级&#xff0c;适合大数据量。 MeiliSearch 设计目标针对数据在 500GB 左右的搜索需求&#xff0c;极快&#xff0c;单文件&#xff0c;超轻量。 所以&#xff0c;对于中小型项目来说…

02通讯录管理系统——创建项目

创建项目步骤如下&#xff1a; 1.创建新项目 2.添加文件 2.1创建项目 打开vs2019后&#xff0c;点击创建新项目&#xff0c;创建新的C项目 填写项目名称&#xff0c;选择路径 2.2添加文件 添加成功后&#xff0c;效果如图

【QT5】<知识点> QT串口编程

目录 前言 一、串口编程步骤 0. 添加串口模块 1. 自动搜索已连接的串口 2. 创建串口对象 3. 初始化串口 4. 打开串口 5. 关闭串口 6. 发送数据 7. 接收数据 二、简易串口助手 1. 实现效果 2. 程序源码 3. 实现效果二 前言 本篇记录QT串口编程相关内容&#xff0…

React基础教程(06):Ref的应用

7、Ref的应用 7.1 给标签设置ref"username" 通过这个获取this.refs.username&#xff0c;ref可以获取到应用的真实dom <input style{{width:300}}ref{"text"}/> {/*非常推荐*/} <Button style{{backgroundColor:#2ba471, border:"none&qu…

毕业了!给学计算机朋友的 10 条血泪建议

大家好&#xff0c;我是程序员鱼皮。最近高考结束了&#xff0c;也有很多同学毕业了&#xff0c;首先祝福这些朋友在人生的新阶段一帆风顺。 刚参加完高考的朋友&#xff0c;面临的最大问题就是选专业&#xff0c;这段时间也有一些家长向我咨询&#xff1a;还能不能选计算机啦…

人脸匹配——OpenCV

人脸匹配 导入所需的库加载dlib的人脸识别模型和面部检测器读取图片并转换为灰度图比较两张人脸选择图片并显示结果比较图片创建GUI界面运行GUI主循环运行显示全部代码 导入所需的库 cv2&#xff1a;OpenCV库&#xff0c;用于图像处理。 dlib&#xff1a;一个机器学习库&#x…

基于深度学习视觉算法的多模型文件融合检测系统设计与实现及优化(工人姿态检测+安全帽佩戴检测系统)

1&#xff0c;融合pose.pt(姿态检测)(安全帽佩戴检测)效果图 实时检测优化后FPS可达20 2,原理介绍 YOLOv5是目前应用广泛的目标检测算法之一&#xff0c;其主要结构分为两个部分&#xff1a;骨干网络和检测头。 输入&#xff08;Input&#xff09;: YOLOv5的输入是一张RGB图像…

定档6.20,创邻科技图数据库先锋版发布会来了!

6月20日 14:00 &#xff0c;创邻科技将重磅召开 2024 Galaxybase银河图数据库先锋版发布会&#xff0c;戳此预约&#xff01; 书于竹帛&#xff0c;镂于金石&#xff0c;琢于盘盂。历史长河中&#xff0c;数据通过不同形态承载着人类文明&#xff0c;人们在数千年中始终保持着…

使用Python和Matplotlib绘制复杂数学函数图像

本文介绍了如何使用Python编程语言和Matplotlib库来绘制复杂的数学函数图像。通过引入NumPy库的数学函数,我们可以处理包括指数函数在内的各种复杂表达式。本文详细讲解了如何设置中文字体以确保在图像中正确显示中文标题和标签,并提供了一个完整的代码示例,用户可以通过输入…

找不到xinput1_3.dll文件要怎么修复?有哪些有效修复xinput1_3.dll文件的方法

要解决xinput1_3.dll文件缺失的问题&#xff0c;首先我们需要对这个文件有所了解。理解了这个文件的性质和作用后&#xff0c;才能更科学、有效地解决因其丢失而导致的问题。那么接下来&#xff0c;让我们不浪费时间&#xff0c;直接深入研究如何修复xinput1_3.dll文件的最佳方…

震坤行亮相2024成都工博会,赋能产业新发

为期3天的成都工博会于2024年4月23日在成都国际会展中心完美落幕。震坤行再次紧跟西部智能制造产业发展步伐&#xff0c;亮相现场&#xff0c;实力“圈粉”&#xff0c;为西部地区的制造企业带来打造了一场工业互联网盛宴。 本届成都工博会成功举办&#xff0c;展会聚集了各个国…

在ubuntu中恢复误删除的文件

1、安装 TestDisk 在 Ubuntu 上&#xff0c;可以使用以下命令安装 TestDisk&#xff1a; sudo apt-get install testdisk2、查询你删除的文件所在那个分区 #查询分区 df -h #我这里是/dev/sda2 #也可以使用下面命令查看具体哪个分区 lsblk3、查询该分区是什么系统类型 sudo …

java:【@ComponentScan】和【@SpringBootApplication】扫包范围的冲突

# 代码结构如下&#xff1a; 注意【com.chz.myBean.branch】和【com.chz.myBean.main】这两个包是没有生重叠的。 主程序【MyBeanTest1、MyBeanTest2、MyBeanTest3】这两个类是在包【com.chz.myBean.main】下 # 示例代码 【pom.xml】 org.springframework.boot spring-boot-…

java采集微信公众号数据

需求背景: 最新需要调用微信公众号api 去微信公众号采集 发布文章数据。 &#xff08;本片文章的意义&#xff1a;根据自己开发的方案来提供思路&#xff0c;当然那不会提供代码。代码是最没有 含金量的东西。&#xff09; 1:遇到的坑:首先 想到的是调用 https://api.weixin…

科技项目验收测试必须进行吗?软件测试公司推荐

科技项目验收测试是指在科技项目开发周期中&#xff0c;对项目完成后进行的一种测试和评估工作。它的目的是验证项目是否达到预期的要求&#xff0c;并确保项目交付给客户前达到预期的质量标准。 一、科技项目验收测试的必要性   科技项目验收测试是项目管理中不可或缺的一个…

Maven认识与学习

1. Maven介绍 1.2 初识Maven 1.2.1 什么是Maven Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 官网&#xff1a;Maven – Welcome to Apache Maven Apache 软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受…

Linux C语言:变量的作用域和生命周期(auto、register、static和extern)

一、变量存储类型-auto 1、auto变量的说明 变量在程序中使用时,必须预先说明它们的存储类型和数据类型。 变量说明的一般形式是&#xff1a; <存储类型> <数据类型 > <变量名> &#xff1b; <存储类型>是关键词auto、register、static和extern<…

湘江早报专访惟客数据李柯辰:湖南伢子返湘玩转“AI+金融”

来源 |《湘江早报》 记者 | 黄荣佳 ​ 随着数字化浪潮的到来&#xff0c;AI的风吹遍了各行各业&#xff0c;金融作为对新兴技术最敏感的行业&#xff0c;前沿技术的赋能&#xff0c;让金融科技成为行业发展的“新赛点”。作为一家以大数据和AI人工智能技术驱动的新一代数字化…

多源最短路径算法 -- 弗洛伊德(Floyd)算法

1. 简介 Floyd算法&#xff0c;全名为Floyd-Warshall算法&#xff0c;亦称弗洛伊德算法或佛洛依德算法&#xff0c;是一种用于寻找给定加权图中所有顶点对之间的最短路径的算法。这种算法以1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特弗洛伊德的名字命名。 2. 核心思…

加码多肤色影像技术 这是传音找到的“出海利器“?

全球化时代&#xff0c;市场竞争愈演愈烈&#xff0c;产品差异化已然成为了企业脱颖而出的关键。在黄、白肤色长期占据人像摄影主赛道的背景下&#xff0c;传音就凭借独一无二的多肤色影像技术走出非洲&#xff0c;走向了更广阔的新兴市场。 聚焦深肤色人群拍照痛点&#xff0c…