详解:TCP/IP五层(四层)协议模型

一.五层(四层)模型

1.概念

TCP/IP协议模型分为五层:物理层、数据链路层、网络层、传输层和应用层。这五层每一层都依赖于其下一层给它提供的网络去实现需求。

1)物理层:这是最基本的一层,也是最接近硬件的一层。其规定了网络通信中的一些硬件设施要求。

2)数据链路层:完成两个相邻设备之间的如何进行通信。如通过网线把电脑链接到路由器/交换机上,这里的电脑与路由器/交换机就是相邻的设备。

3)网络层:完成两个任意设备之间的如何进行通信,考虑的是通讯中间的过程是怎么样的。

4)传输层:完成两个任意设备之间的如何进行通信,考虑的是通讯的起点和终点。

5)应用层:网络编程实现我们想要的效果(需求)。

举个形象例子:网购。我们可以将网购送货分成各个层次。首先最基础的,运货要有路,这个公路就是最基础的“物理层”。再说,快递员将货物运输到各个转运中心,这就是两个相邻的设备中间的通讯,是“数据链路层”。快递公司给快递小哥规划路线,让他怎么走,考虑的是中间的过程,这是“网络层”。网购商家只管填上发货地和收货地,其他不用管,不关心快递小哥是走哪几个转运中心的,只管能不能到收货地,这就是“传输层”。最后,快递到我们手里了,我们怎么使用是我们决定的,正如应用层代码是我们自己实现的,实现的是什么由我们自己决定,这就是“应用层”。

透过上面的例子大家应该对这五层模型是什么有了更深刻的印象了。

回答一下为什么有人说五层,有人说四层。说四层其实是将最下层的物理层和数据链路层合并成一个,与硬件设备直接相关,只是说法不同,实际上都是一样的。

2.网络设备所在分层

1)主机:通过应用程序满足网络通信的需求,涉及 物理层 -> 应用层。

2)路由器:组建局域网,进行网络数据包转发,涉及 物理层 -> 网络层。

3)交换机:对路由器接口的拓展,涉及 物理层 -> 数据链路层。

二.传输层协议

传输层有两个核心协议,一个是TCP,一个是UDP。

1.UDP

1)特点:无连接,不可靠传输,面向数据报,全双工。

UDP不保存通讯对端的信息,这就是无连接。UDP发出数据后直接就不管了,一点不可靠。UDP在读写数据的时候,是以一个数据报为单位去读写的,注意一次必须读写一个数据报,半个不行,因此不存在粘包问题(这个在下面的TCP会解释)。全双工的意思的能读也能写,与之对应的是半双工,只可以读或只可以写。

2)报文格式:

源端口号和目的端口号这两个好理解,就是起点和终点。

UDP长度指的是整个UDP的长度,包括报头和载荷,长度这个位置最多存储两个字节的数据,也就是整个UDP长度最长是64kb。如果我们传输的数据超过64kb,比较大,这个时候我们就要考虑拆包了传输了。

校验和用来验证数据是否发生修改。这个校验和不是用来保证数据安全的,而是用来防止数据在运输的过程中发生比特翻转的现象。比特翻转就是数据的比特位1变成0,0变成1。

UDP校验和使用了CRC(循环冗余校验)的方法,把每个字节都当作整数进行累加,不管溢出,直至最终,得到校验和。

数据在发出端计算一次校验和,再放入报文中,传给目的端,目的端再算一次校验和,看看两个是不是一样。如果是一样,只能确定可能没有发生比特翻转;而不一样,肯定是发生比特翻转了。

UDP在发现校验和不同时只会丢弃,不会重发,如果要重发要我们自己写代码实现。

2.TCP

1)特点:有连接,可靠传输,面向字节流,全双工。

TCP会保存对端的信息,这就是有连接。TCP有两个核心机制保证其是可靠传输。TCP在读写数据的时候是以字节为单位的,支持任意长度,因此存在粘包问题。TCP支持读也支持写。

2)报文格式:

TCP报文内容与TCP的核心机制有关,具体各个部分是什么在下面解释。这里只是补充下面没有提到的。

16位紧急指针(URG)在标志位处有,用来跳过前面的数据,直接从某一个开始读。

PSH(催促标志位)发送方给接收方的数据中带有这个标志,接收方会尽快的将这个数据read。

3.TCP十大核心机制

1)确认应答

在日常生活中,我们怎判断我们叫了某个人他有没有听见,他回应一声不就行了。

TCP也是这么想的,我们在发送数据后,需要对方给一个应答报文(acknowledge,简称ack)。我们收到了这个ack后,就知道了目的端已经收到数据了。这就是TCP是可靠传输的一大原因。

但是在数据传输时可能会出现先发后到的情况。我们在发送数据后,这个数据会经过多个路由器/交换机。每个数据走的路线不同,可能先发的数据走的“路”比较长,花的时间更长,导致“来的比较完”。

针对这种情况,TCP会对载荷中的每个字节进行编号,32位序号就是载荷部分第一个字节的序号,序号连续递增。

32位确认序号的目的就是告诉发送者,我已经收到了那些数据,下次发送从确认序号这个位置开始发。32位确认序号的值就是收到的数据载荷的最后一位+1。注意,这个32位确认序号只在应答报文中生效。

那怎么才能知道这个TCP是应答报文?这就是上面标志位(下图)管的了。

可以看到第二个表示位是ACK,也就是应答报文的意思,如果这一位是 1 ,说明这个报文就是应答报文。

说回来,有了序号之后,应用程序会通过socketAPI读到正确的顺序,不用担心先发后到的情况了。

2)超时重传

超时重传是针对丢包问题进行的处理。丢包问题是不可避免的客观情况。

TCP规定了一个超时时间阈值,这个阈值不是固定不变的,是动态变化的。如果超过这个阈值就是触发重传,同时延长这个时间阈值。但是这个重传和时间阈值是有上限的,超过这个上限后就是放弃传输。

一次信息传输可能有两种丢包情况:

情况一:源端口发送的数据丢失,这个时候直接重传就可以了。

情况二:目的端发送的ack丢失,源端口迟迟没有收到ack,会认为是自己发送的数据丢失,重发一次。这时目的端会收到相同的数据,TCP有一个接收缓存区,数据会先到缓存区,如果发现数据已经存在了就丢弃,如果没有就放入。

3)连接管理

连接分为建立连接和断开连接。

TCP建立连接是通过“三次握手”来实现的。

syn(synchronized,同步)表示的是同步报文,在上图表示为中有,如果syn是1的话,表示这个报文是同步报文。当然,一个报文可以既是同步报文也是应答报文。

建立连接的过程:1. A先给B发一个同步报文。2. B收到后会给A发一个同步报文同时发一个应答报文,这两个报文可以分开,但没必要,因为这两个都是内核负责的,可以保证同一时机。3. A收到同步报文和应答报文后会发给B一个应答报文。 

三次握手的作用:1.探一探网络的通信链路是否通畅,这个网络可靠传输的前提条件。2.验证双发的发送能力和接收能力是不是正常。3.协商关键信息,比如通讯序号从几开始。

TCP断开连接是通过“四次挥手”来实现的。

FIN(finish,完成),表示发送方已经没有数据要发送了,请求断开连接,FIN位为1表示FIN报文。FIN不是由内核负责,而是与我们写的程序有关,代码中调用socket.close或进程结束时才会发送。

断开连接的过程:1.A给B发一个FIN,请求断开连接。2.B给A一个ACK,表示收到A的请求。3.等到B的逻辑执行完了,给A发送FIN,B请求断开连接。4.A给B发一个ACK,表示收到B的请求。

下图是整个连接的全过程

介绍一下上图中出现的部分状态的含义:

ESTABLISHED:连接完成,可以发送数据了。

CLOSE_WAIT:被发起FIN的一方进入该状态,表示等待程序调用close方法。

TIME_WAIT:主动发起FIN的一方进入该状态,表示等待对方结束。主动发起方不会一直等待对方发FIN,而是由一个等待上限,上限时间是2*MSL(网络上两个任意节点传输过程中消耗的最大时间)。

4)滑动窗口

前面说TCP采用一问一答的方法来进行数据传输,这个其实效率比较低。如果我们一下发好几个,不用等待应答,这样就可以提高效率。我们一下发出好几个后,返回一个应答,就再发送下一条。这个不就是滑动窗口嘛。

窗口越大,批量发的数据越多,效率就越高。但是窗口不能无限大,太大了会影响可靠性。

滑动窗口丢包的情况:

这个问题不大,超时后重传。

 正如上图说的那样,1001-2000的数据丢了后,主机B没有收到这个数据,其会再应答报文的确认序号哪里一直返回1001。主机A连续3次收到相同的确认序号时会意识到1001-2000这部分数据丢失了,会重发1001-2000。已经发的2001-7000受不受影响呢?答案是不受影响,为什么?

前面说了,在读数据的时候会按顺序读数据,读到1001,发现没有,队列堵塞,后面的数据一直堵在哪里,等到1001-2000来了后才继续读。这个队列不是一个纯粹的队列,我们发的每个数据都是有序号的,可以根据这个序号来准确的算出数据应该放的位置,如果没有就空着这个位置。

这种重传的方式叫快速重传,即只传丢了的数据,不传其他数据。注意快速重传是在滑动窗口下出现的,不要弄错情况。

5)流量控制

前面说了窗口越大,效率越高,但窗口过大,就是影响可靠性。为了提高效率的同时保证传输可靠性,TCP对流量进行了控制。

TCP有一个接收缓冲区,里面有一些待处理的数据。进入缓冲区的速度取决于发送方发送的速度,出缓冲区的速度取决于应用程序读取的速度。TCP可以根据处理数据的速度,反馈给发送方,限制它的发送速度。

怎么做到的?滑动窗口的大小会动态变化。在TCP的报文中有一栏就是滑动窗口的大小。

这个窗口的大小等于 接收缓冲区剩余空间的大小。剩的多了,就多放进来一点;剩的少了,就少放一点呗。

一旦发现返回的窗口的大小是0,发送方就会暂停发送,过一段时间发送一个窗口探测包,“问问”接收方的接收缓存区有没有空间,有空间了,继续传输数据。

6)拥塞控制

上面说的流量控制是依据接收的处理能力进行限制。而拥塞控制是依据传输链路的转发能力进行限制的。它通过不断试验的方法区找到一个合适的窗口大小,大了就减,小了就加,说白了就是“面多加水,水多加面”。

拥塞机制的工作过程:

先慢启动,再指数增长,再线性增长。发现丢包了,窗口减小,回到新的阈值处。

7)延时应答

默认情况,发送方发送数据后会立即返回ack,但是如果我们延时发送ack,效率会提高。

如果延时发送,接收缓冲区的数据会被处理更多,这个时候返回ack,会返回更大的滑动窗口大小。我们知道窗口越大,效率越高,这样延时发送就会提高效率。

所有包都可以延时应答吗?不是。有数量限制,每隔N个包就要应答一次。也有时间限制,超过最大延迟时间就应答一次。

8)捎带应答

基于延时应答,TCP可以将上次的ack捎并带回,这样将两个包放在一起传输,提高了效率。

9)面向字节流

前面在介绍TCP的特点的时候就提到了一点,因为TCP是面向字节流传输的,支持任意长度,因此就有粘包问题。

什么是粘包问题?粘包问题粘的是应用层数据包,各个包之间由于没有长度限制,而且是面向字节流,不是数据报,因此有时候会分不清字节要读到哪里停止,会出现多读或漏读的情况。粘包问题在TCP层面是无解的,我们要在应用层方面区解决这个问题。定义好应用层的协议,明确包之间的边界。

10)异常情况的处理

TCP通讯过程中会出现的特殊情况。

情况一:  进程崩溃/主机关机

本质上与主动退出没有区别

情况二:  主机断电/网线断开

分为接收方断电和发送方断电。

接收方断电:发送方发送的数据没有ack返回,超时重传后还没有返回。重传到一定次数会触发“重置TCP连接”,发送方会主动发一个复位报文(RST),如果还没有用,发送方就会单方面释放连接。

发送方断电:发送方断电后,接收方此时判断不出来发送方是断电了还是暂时没有数据发送。等待一段时间后接收方会发送一个特殊报文—“心跳包”,这个报文不携带数据,只是为了触发ack,跟上面的窗口探测一样。如果不跳了,就发一个复位报文,如果还不好使,就单方面释放连接。

三.网络层协议

1.IP协议基础

概念:用于唯一标识网络中的每台计算机。我们可以在cmd中查看ip地址:ipconfig。

IP地址的表示形式:点分十进制 xx.xx.xx.xx,每个十进制数的范围是0—255。

IP地址的组成:网络地址+主机地址。

同一个局域网当中网络地址必须相同,主机地址必须不同。相邻的局域网中网络地址必须不同,主机地址随意。

Ipv4是由4个字节(32位)表示,而I,Pv6是由16个字节(128位)表示。

IP协议的作用主要是下面两个:

1)地址管理,用来标识网络上的某个设备的位置。

2)路由选择,在两个通信的节点之间,规划出一个合理的路径。

这是以前使用的IPv4地址分类,现在不用了:

各类表示范围:

那现在的IPv4怎么分网络号和主机号呢?

打开ipconfig:

看到下面的子网掩码,255的表示网络地址位,0表示主机地址位。

特殊的IP地址:

1)将IP地址中的主机地址全部设成0就成了网络号,代表这个局域网

2)将IP地址中的主机地址全部设为1,就成为了广播地址,用于给同一个链路中相互连接的所有主机发送数据包

3)127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1

2.IP协议报文

1)4位版本:IPv4或IPv6

2)4位首部长度:因为报头有选项这一栏,所以报头长度也是变长的

3)8位服务类型:决定了IP地址的工作方式,3位优先权字段(已弃用)+ 4位TOS字段 + 1位保留字段(必须设置为0)。4位TOS字段分别表示:最小延时,最大吞吐量,最高可靠性,最小成本。注意这四个TOS字段是不共存的,只能是其中一个,要根据实际情况选择。

4)16位总长度(字节数):报头+载荷的长度

5)16位标识、3位标志,13位片偏移:

IP协议内置了拆包组包的功能,拆完了包我们要给包一个标识,要不然怎么组包,怎么知道谁跟谁是一组的。16位标识位就是给包一个标识,拆出来的包都是一个标识,组包的时候就将相同标识的包组在一起。3位标志用来标志有没有触发拆包操作,并且记录这个包是不是最后一个包。13位片偏移描述了先后顺序,偏移小的放在前面,偏移大的放在后面

6)8位生存空间(TTL):一个IP数据报能在网络上传输的最大时间,单位是次数,IP数据报每经过一个路由器就TTL就减小一次

7)8位协议:标识传输层使用什么协议

3.NAT机制

NAT机制,即网络地址转换,是当今网络时间解决IPv4不够用的最重要的方式。

其将说有IP分成两类:一是公网/外网,另一是私网/内网。公网IP是唯一的,但是私网IP在不同的局域网中是可以重复的。

如上面的例子,运营商路由器具有NAT功能,能将我的设备的IP地址进行转换:192.168.100.1->100.1.1.1。

可能会有多个设备对运营商的服务器发送请求,但是到了运营商的路由器都会被转换成同一个IP

服务器收到请求后会返回给运营商路由器。但是运营商怎么知道这个哪一个设备发送的请求呢?

运营商在地址转换时会将两个地址存入一个记录映射关系的表格,记录替换前的地址和替换后的地址,同时也会记录端口。NAT设备进行转换的时候可以修改端口号,这一就避免了端口相同找不到源地址的情况。

4.路由选择

这里介绍路由选择的简单模型:探索式。

网络环境是非常复杂的,路由器没有办法将所有的网络信息都存储,只存储周围的网络情况。当数据包到了某个路由器,就会匹配这个路由器的路由表。路由表中记录了这个路由器周围的设备的IP地址是什么,以及记录每个设备要通过哪个口转发过去。

如果目的IP地址刚好匹配到了路由表中的记录,就直接转发到对应的口。

如果没有匹配到,路由表会有一个特殊的表项——下一跳,指向的设备就是上一级路由器所在的位置。

四.数据链路层

1.以太网

以太网帧格:

1)目的地址和源地址这里存储的地址不是IP地址,而是mac地址(物理地址)。

想看这个地址要在cmd中输入:ipconfig /all

2)类型是用来确定载荷的数据格式的

3)CRC:帧尾,校验和

4)ARP:根据IP地址,得到对应的mac地址。具体做法:通过广播地址,发送ARP数据报,询问周围的网络设备的IP地址和mac地址,路由器会构建出一个映射表来存储这些IP地址和ARP地址

五.应用层

1.DNS

可以认为是应用层的一个协议也可以认为是一个系统。这个系统就是域名解析系统(域名是什么在后面的网络基础知识中有)。

最初DNS通过一个hosts文件,这个文件中存储域名和IP地址的映射关系。我们在访问某个网站的时候,会先查询DNS服务器,把域名对应的IP拿到,再访问服务器。

现在全世界的服务器这么多,我们都访问DNS服务器,服务器会承受海量的并发量,容易挂。

这里有两个方法去解决:

1)缓存,我们再DNS服务器找到IP地址后会存储再缓存中,下次访问这个域名就不用去DNS服务器查找了

2)DNS服务器有很多,存储原始数据的是根服务器,各个网络运营商可以搭建镜像服务区。

2.InetAddress类

常用方法:

方法说明
getLocalHost获取本机InetAddress对象
getByName

根据主机名/域名 获取InetAddress对象

getHostName获取InetAddress对象的主机名
getHostAddress获取InetAddress对象的地址

代码示例:

//1.获取本机的InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
//输出设备名称和IP
System.out.println(localHost);

//2.根据主机名 获取InetAddress对象
InetAddress host1 = InetAddress.getByName("LAPTOP-RPIOC01F");
System.out.println(host1);

//3.根据域名 获取InetAddress对象
InetAddress host2 = InetAddress.getByName("www.bilibili.com");
System.out.println(host2);

//4.通过 InetAddress 对象,获取对应的地址
String hostAddress = host2.getHostAddress();
System.out.println(hostAddress);

//5.根据 InetAddress 对象,获取对应主机名/域名
String hostName = host2.getHostName();
System.out.println(hostName);

3.TCP网络通信

1)Socket

Socket开发网络应用程序被广泛采用,以至于成为事实上的标准。通信的两端都要有Socket,是两台机器间通信的端点。网络通信其实就是Socket间的通信。

Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。

一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。

怎么理解这个Socket呢?可以从它的英文原意入手,socket->插座、插口。它就是一个插口,中间连接一个数据通道

2)使用字节流

代码示例:

//客户端

//1.连接服务器(ip,端口),如果连接成功返回Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端返回:"+socket.getClass());
//2.连接上后,生成Socket对象,通过socket.getOutputStream()得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3.通过输出流,写入数据到数据通道
outputStream.write("hello".getBytes());
//4.设置结束标记
socket.shutdownOutput();
//5.关闭流对象
outputStream.close();
socket.close();
System.out.println("客户端退出");
//服务端

//1. 在本机的9999端口监听,等待连接
//要求在本机没有其他服务在监听9999
//这个 ServerSocket 通过accept() 返回多个Socket
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听,等待中。。。");
//2.当没有客户端连接9999端口时,程序会阻塞,等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
//3.通过 读取客户端写入到数据通道的数据
InputStream inputStream = socket.getInputStream();
//4.IO读取
byte[] bf=new byte[1024];
int readLen=0;
while((readLen=inputStream.read(bf))!=-1){
    System.out.println(new String(bf,0,readLen));
}
//5.关闭流
inputStream.close();
socket.close();
serverSocket.close();

3)使用字符流传输文件

代码示例:

//客户端

//1.连接服务端,得到Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//2.创建读取磁盘文件的输入流
String path="C:\\JavaNet\\Java.png";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
//将文件内容读入数组中
byte[] bytes=StreamUtils.streamToByteArray(bis);
//3.传输到服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bis.close();
socket.shutdownOutput();    //设置写入数据结束

//4.接收消息
InputStream inputStream = socket.getInputStream();
byte[] b=new byte[1024];
int readLen=0;
while ((readLen=inputStream.read(b))!=-1){
    System.out.println(new String(b,0,readLen));
}
//5.关闭流
inputStream.close();
bos.close();
socket.close();
//服务端

//获得端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在8888端口等待...");
//等待连接
Socket socket = serverSocket.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
//拿到文件
byte[] bytes=StreamUtils.streamToByteArray(bis);
String path="C:\\JavaNet\\pic.png";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
bos.write(bytes);
bos.close();

//发送信息
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("已收到图片");
writer.flush();         //刷新内容到数据通道
socket.shutdownOutput();
System.out.println("已收到图片");

//关闭资源
writer.close();
bis.close();
socket.close();
serverSocket.close();

4)补充

使用缓冲流一定注意要刷新数据到数据管道,否则就白写了。

在写入完后一定要记得设置写入数据结束。

4.UDP网络通信编程

1)基本流程

核心的两个类/对象 DatagramSocket 与 DatagramPacket;建立发送端,接收端;发送数据前,建立数据包DatagramPacket对象;调用DatagramSocket的发送接收方法;最后关闭DatagramSocket。

2)应用

代码示例:

//发送端

//1.创建DatagramSocket对象,准备在9998接收数据
DatagramSocket socket = new DatagramSocket(9998);
//2.将需要发送的数据,封装到对象
byte[] data="秘制小汉堡".getBytes();
//说明:封装 DatagramPacket 对象,data ,长度,主机IP,端口
DatagramPacket packet =
        new DatagramPacket(data, data.length, InetAddress.getByName("10.40.91.181"),9999);
socket.send(packet);
socket.close();
System.out.println("B结束了");
//接收端

//1.创建一个DatagramSocket对象,准备在9999接收数据
DatagramSocket socket = new DatagramSocket(9999);
//2.构建一个 DatagramPacket对象,准备接收数据
byte[] buf=new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//3.准备接收数据,将通过网络传输的DatagramPacket对象填充到packet对象
//有数据就会接收,没数据就会阻塞
System.out.println("正在等待连接");
socket.receive(packet);
//4.可以把packet 进行拆包,取出数据,并显示
int length=packet.getLength();  //实际接收的数据字节长度
byte[] data=packet.getData();
String regStr = new String(data, 0, length);
System.out.println(regStr);
//关闭资源
socket.close();
System.out.println("A结束");

 六.网络的基础概念

1.网络通信

两台设备之间通过网络实现数据传输,将数据通过网络从一台设备传输到另一台设备。

在java.net包下提供了一系列的类或接口,供程序员使用完成网络通信。

2.网络

两台或多台设备通过一定物理设备连接起来构成了网络。

根据网络的覆盖范围可分为下面几类:

1)局域网:覆盖范围最小,仅仅覆盖一个教室

2)城域网:覆盖范围较大,可以覆盖一个城市

3)广域网:覆盖范围最大,可以覆盖全国

3.域名和端口号

域名概念:将IP地址映射成域名,也就是将IP地址变成了网站。IP地址一堆数字,太难记了,转变成域名后方便记忆。

端口号概念:用于标识计算机上某个特定的网络程序。我们可以通过端口号来访问某一个域名下的某个服务。ip定位主机,端口定位服务。比如说我们访问了B站的域名,要想连上网站服务,就需要一个端口号来实现。

端口号就好像是房子的门,如果我们想要进入房子就要通过门。一个房子可能有多个门,同样一个主机也有多个端口号,每个端口号都对应着其自身的业务。

端口号表示形式:以整数的形式,范围0—65535(2个字节表示端口)

避免使用0—1024端口,因为0—1024都被占用了。常见的网络程序端口号:tomcat:8080  mysql:3306  Oracle:1521  sqlserver:1433。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DeepSeek-R1:将强化学习用于激励大型语言模型的推理能力

目录 引言 一、DeepSeek-R1的贡献 二、DeepSeek-R1的方法 2.1、DeepSeek-R1-Zero:基础模型上的强化学习 2.2、DeepSeek-R1:冷启动强化学习 2.3、蒸馏:赋予小模型推理能力 三、DeepSeek-R1实验结果 3.1、模型优点 3.2、模型缺点 四、…

分布式微服务系统简述

distributed microservice 分布式与微服务的定义及关系;分布式微服务架构里的各组件,如:配置中心、服务注册/发现、服务网关、负载均衡器、限流降级、断路器、服务调用、分布式事务等;spring cloud 介绍及实现案例,如…

从Spring请求处理到分层架构与IOC:注解详解与演进实战

引言 在Spring开发中,请求参数处理、统一响应格式、分层架构设计以及依赖管理是构建可维护应用的核心要素。然而,许多开发者在实践中常面临以下问题: 如何规范接收不同格式的请求参数? 为何要引入分层架构? 什么是控…

神经网络|(三)线性回归基础知识

【1】引言 前序学习进程中,已经对简单神经元的工作模式有所了解,这种二元分类的工作机制,进一步使用sigmoid()函数进行了平滑表达。相关学习链接为: 神经网络|(一)加权平均法,感知机和神经元-CSDN博客 神经网络|(二…

2024年博客之星主题创作|猫头虎分享AI技术洞察:2025年AI发展趋势前瞻与展望

2025年AI发展趋势前瞻:猫头虎深度解析未来科技与商业机遇 摘要 2024年,AI技术迎来爆发式增长,AIGC、智能体、AIRPA、AI搜索、推理模型等技术不断突破,AI应用场景持续扩展。2025年,AI将进入全新发展阶段,W…

Android多语言开发自动化生成工具

在做 Android 开发的过程中,经常会遇到多语言开发的场景,尤其在车载项目中,多语言开发更为常见。对应多语言开发,通常都是在中文版本的基础上开发其他国家语言,这里我们会拿到中-外语言对照表,这里的工作难…

【Maui】提示消息的扩展

文章目录 前言一、问题描述二、解决方案三、软件开发(源码)3.1 消息扩展库3.2 消息提示框使用3.3 错误消息提示使用3.4 问题选择框使用 四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移…

AI导航工具我开源了利用node爬取了几百条数据

序言 别因今天的懒惰,让明天的您后悔。输出文章的本意并不是为了得到赞美,而是为了让自己能够学会总结思考;当然,如果有幸能够给到你一点点灵感或者思考,那么我这篇文章的意义将无限放大。 背景 随着AI的发展市面上…

pycharm 运行远程环境问题 Error:Failed to prepare environment.

问题排查 拿到更详细的报错信息: Help > Diagnostic Tools > Debug Log Settings section: 添加下面的配置 com.intellij.execution.configurations.GeneralCommandLine 重显报错,我这里是再次运行代码打开 Help | Collect Logs and Diagnosti…

C语言自定义数据类型详解(一)——结构体类型(上)

什么是自定义数据类型呢?顾名思义,就是我们用户自己定义和设置的类型。 在C语言中,我们的自定义数据类型一共有三种,它们分别是:结构体(struct),枚举(enum),联合(union)。接下来,我…

Windows上通过Git Bash激活Anaconda

在Windows上配置完Anaconda后,普遍通过Anaconda Prompt激活虚拟环境并执行Python,如下图所示: 有时需要连续执行多个python脚本时,直接在Anaconda Prompt下可以通过在以下方式,即命令间通过&&连接,…

MinIO的安装与使用

目录 1、安装MinIO 1.1 下载 MinIO 可执行文件 1.2 检查 MinIO 是否安装成功 1.3 设置数据存储目录 1.4 配置环境变量(可选) 1.5 编写启动的脚本 1.6 开放端口 1.7 访问 2、项目实战 2.1 引入依赖 2.2 配置yml文件 2.3 编写Minio配置类 2.4…

零基础Vue学习1——Vue学习前环境准备

目录 环境准备 创建Vue项目 项目目录说明 后续开发过程中常用命令 环境准备 安装开发工具:vscode、webstorm、idea都可以安装node:V22以上版本即可安装pnpm 不知道怎么安装的可以私信我教你方法 创建Vue项目 本地新建一个文件夹,之后在文件夹下打开…

Linux查看服务器的内外网地址

目录: 1、内网地址2、外网地址3、ping时显示地址与真实不一致 1、内网地址 ifconfig2、外网地址 curl ifconfig.me3、ping时显示地址与真实不一致 原因是dns缓存导致的,ping这种方法也是不准确的,有弊端不建议使用,只适用于测试…

二叉树的最大深度(C语言详解版)

一、摘要 嗨喽呀大家,leetcode每日一题又和大家见面啦,今天要讲的是104.二叉树的最大深度,思路互相学习,有什么不足的地方欢迎指正!好啦让我们开始吧!!! 二、题目简介 给定一个二…

OpenCV imread函数读取图像__实例详解

OpenCV imread函数读取图像__实例详解 本文目录: 零、时光宝盒 一、imread函数定义 二、imread函数支持的文件格式 三、imread函数flags参数详解 (3.1)、Flags-1时,样返回加载的图像(使用alpha通道,否…

VMware虚拟机安装macOS11

1.安装虚拟机 如果尚未安装虚拟机,请先进行安装。地址:VMware17下载地址​​​​​​ 2、下载苹果镜像文件 macOS Big Sur 11.0.1 (20B29) 3、下载unlock文件(目的是开启VMware的macOS选项功能) https://download.csdn.net/d…

探究 Facebook 隐私安全发展方向,未来走向何方?

随着社交媒体的普及,隐私和数据安全问题成为了全球关注的焦点。Facebook,作为全球最大的社交平台之一,其隐私安全问题尤其引人注目。近年来,随着用户数据泄露事件的不断发生,Facebook 不断调整其隐私政策,探…

jQuery阶段总结(二维表+思维导图)

引言 经过23天的学习,期间有期末考试,有放假等插曲。本来应该在学校里学习,但是特殊原因,让回家了。但是在家学习的过程,虽然在学,很让我感觉到不一样。但是效果始终还是差点的,本来17、18号左右…

LabVIEW太阳能照明监控系统

在公共照明领域,传统的电力照明系统存在高能耗和维护不便等问题。利用LabVIEW开发太阳能照明监控系统,通过智能控制和实时监测,提高能源利用效率,降低维护成本,实现照明系统的可持续发展。 ​ 项目背景 随着能源危机…