网络编程套接字TCP
前集回顾
上一篇博客中我们写了一个UDP的echo server,是一个回显服务器:请求是啥,响应就是啥
一个正常的服务器,要做三个事情:
- 读取请求并解析
- 根据请求,计算响应
- 把响应写回到客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,requestPacket.getSocketAddress());
//先得到字节数组,然后取字节,然后取数组的长度,这里的长度单位是“字节数”
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
//这里的长度单位是“字符数”
客户端的整体流程:
- 从控制台读取字符串
- 把字符串发送给服务器
- 从服务器读取到响应
- 把响应打印到控制台上
同时后面的serverIp为127.0.0.1,需要把字符串格式的ip地址转成Java能识别的对象,InetAddress对象,提供了getByName工厂方法,把上述字符串格式的ip地址,转成Java能识别的InetAddress对象了
这个对象里有的就是IP地址,会按照32位整数的形式来保存,计算机认识的是32位整数形式的ip,点分十进制是给人看的
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,InetAddress.getByName(serverIp), serverPort);
socket.send(requestPacket);
//读取响应数据
DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(responsePacket);
这个代码在写的时候,上面的send完成之后,就立即执行到下面的receive了,但是实际上,数据在网络传输过程中,也是需要时间的,此处的receive也会阻塞,阻塞到真正到达为止
上述阻塞行为,不需要咱们代码进行任何干预,都是人家的api内部已经实现好了(系统内核完成好了的功能)
在系统内核中,让某个线程阻塞是很容易的事情,通过链表方式来组织PCB,链表不只是一个,而是有多个,有的链表,称为“就绪队列”,这里的PCB就要参与cpu调度,有的链表,称为“阻塞队列”(这里的PCB不参与PCB调度),调用receive的时候,系统会看网卡上是否有数据来了(通过网卡驱动很容易能够感知到),然后如果没来,就把当前线程PCB放到阻塞的队列中即可(链表节点的删除/插入)
服务器代码
客户端代码
运行
先运行服务器,后运行客户端
服务器是被动方,要先准备好,得餐馆先开门,然后才能去吃饭
有个客户端,发来一个请求,请求内容是hello,响应内容也是hello,客户端ip是127.0.0.1,客户端的port是49874(系统自动分配的结果)
如何启动多个客户端
默认情况下,idea里面只能启动一个客户端,要想启动多个,需要如下操作:
在service中可以看到
刚才是客户端和服务器,都在同一个电脑上,如果是不同电脑呢?
Question:如果我把客户端发给你,你在客户端中填写这个ip,能否访问我的这个服务器程序呢?
Answer:不能,要想能访问,有一个前提,需要在同一个局域网下,如何能够让世界上任何一个能上网的人脸上咱们的服务器呢?不是咱们的程序代码不行(代码已经就绪),当前这个电脑的IP只是一个局域网内部使用的私有IP,而不是能够在广域网上直接使用的“公网IP”,需要一个云服务器来提供公网IP
通过XShell可以远程控制云服务器
上述一串数字就是云服务器IP,也就是公网IP,另外,在所有IP地址中,以下三种情况是私网IP,剩下的都是公网IP
私网IP常用格式
- 10.*
- 172.16-172.31.*
- 192.168.*
- 把写好的udpechoserver放到云服务器上,需要把服务器程序打一个jar包出来
- 把这个jar包传到云服务器上
- 运行这个程序
通过命令来运行程序
通过这串代码可以理解两方面:
总结
- socket api(UDP)
- 服务器程序的典型工作流程
- 读取请求并解析
- 根据请求计算响应
- 把响应写回到客户端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 1) 读取请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// 为了方便在 java 代码中处理 (尤其是后面进行打印) 可以把上述数据报中的二进制数据, 拿出来, 构造成 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2) 根据请求计算响应String response = this.process(request);// 3) 把响应写回到客户端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf("[%s:%d] req=%s, resp=%s\n", requestPacket.getAddress(), requestPacket.getPort(),request, response);}}// 由于当前写的是 "回显服务器"public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}
如果要写别的服务器(例如翻译网站),可以继承该服务器,然后重写process方法,在响应方面重新重写,使用Map来记录key-value之间的关系
TCP
TCP的socket api也有两个关键的类
ServerSocket
其中也有三个重要的方法:
接听操作方法
public Socket accept() throws IOException {if (isClosed())throw new SocketException("Socket is closed");if (!isBound())throw new SocketException("Socket is not bound yet");Socket s = new Socket((SocketImpl) null);implAccept(s);return s;
}
构造方法
public ServerSocket(int port) throws IOException {this(port, 50, null);
}
关闭资源的方法
public void close() throws IOException {synchronized(closeLock) {if (isClosed())return;if (created)impl.close();closed = true;}
}
Socket客户端和服务器都要用(两边都要用,不能叫做ClientSocket),TCP传输的是字节流,就是传输字节,传输的基本单位就是byte
Socket
其中重要的方法
构造方法
public Socket(String host, int port) throws UnknownHostException, IOException {this(host != null ? new InetSocketAddress(host, port) :new InetSocketAddress(InetAddress.getByName(null), port),(SocketAddress) null, true);
}
获取socket内部持有的对象
public InputStream getInputStream() throws IOException {if (isClosed())throw new SocketException("Socket is closed");if (!isConnected())throw new SocketException("Socket is not connected");if (isInputShutdown())throw new SocketException("Socket input is shutdown");InputStream in = this.in;if (in == null) {// wrap the input stream so that the close method closes this socketin = new SocketInputStream(this, impl.getInputStream());if (!IN.compareAndSet(this, null, in)) {in = this.in;}}return in;
}
获取socket内部持有的流对象
public OutputStream getOutputStream() throws IOException {if (isClosed())throw new SocketException("Socket is closed");if (!isConnected())throw new SocketException("Socket is not connected");if (isOutputShutdown())throw new SocketException("Socket output is shutdown");OutputStream out = this.out;if (out == null) {// wrap the output stream so that the close method closes this socketout = new SocketOutputStream(this, impl.getOutputStream());if (!OUT.compareAndSet(this, null, out)) {out = this.out;}}return out;
}
同时还可以获得源和目的主机的信息
public InetAddress getInetAddress() {if (!isConnected())return null;try {return getImpl().getInetAddress();} catch (SocketException e) {}return null;
}
ServerSocket和Socket这俩起到的作用,截然不同的,服务器一上来要先处理客户端来的连接
Socket clientSocket = serverSocket.accept();
//服务器一启动,就会立即执行到这里,如果客户端没有连接过来,accept也会产生阻塞,直到说有客户端真的连接上来了
举一个比较形象的栗子:有一个西装革履的小哥来到我面前,这个人不是大老板就是销售,他把我领到一个地方,这个地方都是西装革履的人,给我介绍房子,然后小哥就消失了,然后由别的人带我介绍,此时小哥就可以理解为ServerSocket,其他带我介绍的人可以理解为clientSocket
- ServerScoket用于在服务器端使用的(揽客) - accept
- Socket用于服务器和客户端来进行通信 - getInputStream,getOutStream
相当于打电话的时候,接通电话后,会说很多话,不是说一句就挂了
Scanner scanner = new Scanner(inputStream);
String request = scanner.next();
//这个读取方式,就是会读到“空白符”才会读取完毕,如果直接按照read方式来读,读出来的就是byte[]还需要转成Srting
//如果直接使用Scanner的话,直接读出来的就是String,Scanner已经帮我们做好上述的转换操作了
//客户端在发送数据的时候,无比要在每个请求的结尾,填上空白符(\n, \t, 回车, 换行)
//上述要求属于咱们对于通信细节的约定
由于TCP上面是按照字节来传输的,而是实际上,我们是希望,若干个字节能够构成一个“应用层数据报”,如何区分从哪到哪是一个应用层数据报?就可以通过“分隔符”的方式来约定,上述代码就是在约定说,使用空白符,来作为一个请求的结束标记
从TCP socket中读出一大串字节,可能会包含多个应用层的请求数据,就需要作出区分
不论是发请求,还是返回响应,也要使用Scanner的方式来next,因此就要求服务器返回的响应也要带有\n,使用next读取数据,如果数据中不带有\n等分隔符的话,此时next就会一直阻塞,Scanner是会带有阻塞功能的,
if (!scanner.hasNext()) {// 如果发现后续没有数据了, 此时说明 TCP 的连接是已经断开了的.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;
}
String request = scanner.next();
这里的scanner.hasNext就会阻塞等待请求的到达
- 请求到了,有明确的分隔符,返回true
- tcp连接断开了,返回false
scanner,可以认为是关联到了服务器这边的socket文件,socket是能感知到tcp断开连接的(本身是系统内核里面会有一系列的流程,四次挥手)
操作系统知道这个事情之后,就会告知socket,对应的scanner读取的文件,就相当于是“无效文件”,类似于读取到EOF这样的效果,使用scanner读文件的时候,就是读到文件末尾,hasNext也是会返回false,一旦tcp连接断开,scanner就相当于读到文件末尾的效果,都是读到EOF,反映到scanner上面就是hasNext为false
Question:
- hasNext方法阻塞时间长了就表名TCP连接断开了吗?
- 客户端自行断开会影响服务端吗?
Answer:
- 不是的,TCP连接断开,hasNext解除阻塞,并返回false,TCP连接仍然存在,但是对方没有发数据过来,hashNext是阻塞的,对方发数据过来了,hasNext解除阻塞,返回true
- 在TCP中是这样的,客户端断开连接,服务器是能感知到的
while (true) {// 3.1 读取请求并解析if (!scanner.hasNext()) {// 如果发现后续没有数据了, 此时说明 TCP 的连接是已经断开了的.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}String request = scanner.next();// 3.2 根据请求计算响应String response = process(request);// 3.3 把响应写回给客户端.outputStream.write(response.getBytes(), 0, response.getBytes().length);// 3.4 服务器打印日志System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request, response);
}
public void start() {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {Scanner scannerNetwork = new Scanner(inputStream);while (true) {// 1. 从控制台读取数据System.out.print("请输入要发送的数据: ");String request = scanner.next();// 2. 把请求发送给服务器, 发送的请求要带有 \n, 和服务器的 scanner.next 是对应的.// 由于上述通过 next 读到的 request 本身已经没有 \n 结尾了. 需要手动添加上换行request += "\n";outputStream.write(request.getBytes());// 3. 从服务器读取到响应if (!scannerNetwork.hasNext()) {break;}String response = scannerNetwork.next();// 4. 把响应显示到控制台上System.out.println(response);}} catch (Exception e) {e.printStackTrace();}
}
重点理解“客户端下线”操作,当强制终止客户端进程,或者通过代码调用客户端socket,close(),就会使客户端所在的主机的操作系统内核,触发TCP断开连接流程(四次挥手),服务器就能感知到,于是就会在hasNext解除阻塞,并返回false(if这里逻辑取反,于是就进入if语句内部,执行打印 下线 的操作,并break了)
上述代码,还存在一些问题
-
服务器代码这边,对于accept创建的socket对象,是没有进行关闭操作的
Socket clientSocket = serverSocket.accept();
//这个东西在processConnection中使用之后没有进行close,这个是不科学的
- serverSocket是可以不必特别关闭的,因为生命周期是跟随整个服务器进程的
- 客户端的socket也是可以不必特别关闭的
但是服务器的clientSocket就不行了,服务器会对应多个客户端,每个客户端都有一个对应的clientSocket,如果用完了不关闭,就会使当前clientSocket对应的文件描述符得不到释放,引起文件资源泄露
try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {...} catch (IOException e) {e.printStackTrace();
} finally {// 在这里关闭是比较靠谱的做法.// 即使当前 processConnection 在不同的线程中被调用, 也可以正确关闭.clientSocket.close();
}
有的时候,close操作的异常也需要单独处理,没啥太好的方法
-
当前这个代码,服务器是无法同时给多个客户端提供服务端
使用service操作,虽然有两个客户端了,但是服务器只感知到一个客户端上线,第一个客户端,发来的请求能够顺利处理,第二个客户端的请求就处理不了了,一旦第一个客户端结束,服务器就能立即感知到第二个客户端上线,以及感知到客户端之前的请求,并且立即返回响应
while (true) {// 3.1 读取请求并解析if (!scanner.hasNext()) {// 如果发现后续没有数据了, 此时说明 TCP 的连接是已经断开了的.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}String request = scanner.next();// 3.2 根据请求计算响应String response = process(request);// 3.3 把响应写回给客户端.outputStream.write(response.getBytes(), 0, response.getBytes().length);// 3.4 服务器打印日志System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request, response);
}
解决方案:多线程
第一个客户端连接之后,此时accept就返回了,进入到processConnection方法,就在方法内部的while循环,开始循环起来了,第二个客户端来了之后,此时,没有办法执行到第二次accept的(第二个客户端,给服务器打电话,服务器一直没接听!)一方面希望给第一个客户端提供服务,另一方面,还能希望快速第二次调用到accept,我们可以使用多线程
主线程,专门负责循环的处理accept,每次accept获取到一个客户端连接之后,都创建一个新的线程,用新的线程来给客户端循环的提供服务
public void start() throws IOException {System.out.println("服务器启动!");// 能一直扩容// 如果用固定线程个数的线程池, 不太合适, 就限制了最多有多少个客户端同时连接.ExecutorService pool = Executors.newCachedThreadPool();while (true) {Socket clientSocket = serverSocket.accept();// 代码改成多线程的形式, 就不能通过 try ( ) 的方式来关闭 clientSocket 了.// 否则就会使 clientSocket 被立即关闭, 此时 processConnection 还没来得及使用的.
// Thread t = new Thread(() -> {
// try {
// processConnection(clientSocket);
// // clientSocket.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// });
// t.start();// 把任务添加到线程池中pool.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}
}
如果线程太多,电脑会撑不住,所以这里核心解决方案:IO多路复用 + 多个服务器(分布式系统)
IO多路复用
通过AI可以知道IO多路复用是什么机制!
IO多路复用是一种同步非阻塞的IO模型,它允许单个线程处理多个文件描述符(FD),从而管理多个网络连接或IO流。这种机制使得服务器能够高效地处理大量的并发连接而不需要为每个连接创建一个独立的线程或进程。
IO多路复用主要通过三种机制实现:select、poll和epoll。
- select:这是最早的IO多路复用机制,它使用一个文件描述符集合来进行监控,并通过内核检查每个FD来确定是否有事件发生。select的缺点包括对文件描述符数量有限制(通常是1024),以及需要在用户态和内核态之间复制文件描述符集合,这会导致额外的性能开销。
- poll:poll是select的改进版,它没有最大文件描述符数量的限制,并且使用动态数组来存储FD。尽管如此,poll仍然需要遍历整个FD集合来查找哪些FD已经就绪,这在大量FD的情况下效率不高。
- epoll:这是Linux特有的IO多路复用机制,它比select和poll更高效。epoll使用内核事件表来管理FD,并且不需要复制文件描述符集合,从而减少了数据复制的开销。epoll还支持水平触发(LT)和边缘触发(ET)两种模式,其中边缘触发模式可以避免大量不必要的事件通知。
IO多路复用的优势在于它能够提高单个线程处理多个IO请求的能力,减少了线程创建和上下文切换的开销,提高了系统的并发性能。它在网络编程中特别有用,可以用于实现高性能的服务器和客户端应用程序。
在实际应用中,IO多路复用可以用于网络编程、高性能服务器、文件操作和定时器事件调度等场景。例如,Web服务器可以使用IO多路复用来同时处理大量并发请求,而不会因为某个请求的IO操作而阻塞其他请求的执行。
总结来说,IO多路复用是一种强大的技术,可以在单个线程中处理多个I/O操作,提高程序的实时性能,特别是在处理大量数据、提高实时性能和提高系统性能方面具有非常重要的作用。
当前写的tcp server和client这里,就涉及到三种socket
- 服务器ServerSocket
- 服务器Socket(通过这个Socket和客户端提供交互能力)
- 客户端Socket(通过这个Socket和服务器进行交互)
第二个socket,服务器这边会有多个这样的socket,每个客户端都有一个对应的socket,这个socket在客户端断开连接之后,就不再使用了,就需要关闭掉
第一个和第三个都是生命周期跟随整个进程,程序只要在运行,就需要这个socket,不能提前close的,随着进程结束,这些socket自然释放
何时关闭第二个socket?这个连接用完了之后
private void processConnection(Socket clientSocket) throws IOException;
此处的processConnection这个方法就表示一个客户端连接的,整个处理过程,这个方法执行完毕,就是用完了(这个方法里也是感知到客户端关闭(断开连接)才返回的),此时就可以在这个方法的末尾,进行close了
自定义应用层协议
- 信息
- 确定数据的格式
- 基于行文本的方式来传输
- 基于xml的方式
- 基于json
- yml
- protobuffer:针对要传输的数据进行压缩,虽然可读性不好,但是能够把空间最充分的利用,最节省网络带宽,效率也最高
相关文章:
网络编程套接字TCP
前集回顾 上一篇博客中我们写了一个UDP的echo server,是一个回显服务器:请求是啥,响应就是啥 一个正常的服务器,要做三个事情: 读取请求并解析根据请求,计算响应把响应写回到客户端 DatagramPacket res…...
Git
Git-2.34.1-64-bitGit-2.34.1-64-bitTortoiseGit-2.4.0.2-64bitTortoiseGit-LanguagePack-2.4.0.0-64bit-zh_CN 下载Git-2.34.1-64-bit、TortoiseGit-2.4.0.2-64bit、TortoiseGit-LanguagePack-2.4.0.0-64bit-zh_CN,依次安装。 # 配置本地Git的用户名与邮箱 git c…...
【日常记录】现在遇到的Y7000P亮度无法调节问题,无需改动注册表进行调整的方法。
1、winR 2、输入:services.msc 3、找到下面红框内的服务 4、右键后,点击重启任务,重启任务后,再次按热键即可恢复亮度调节。...
ubuntu20.04.6 触摸屏一体机,外接视频流盒子开机输入登录密码触屏失灵问题解决方法
1. 首先直接运行xrandr命令,查看设备的相关信息: 运行之后会显示当前连接设备的屏幕信息,如下图,LVDS和VGA-0,而HDMI屏幕为disconnect,意为没有连接: 2. 设置开机主屏幕显示: xrand…...
师生健康信息管理:SpringBoot技术指南
第3章 系统分析 3.1 需求分析 师生健康信息管理系统主要是为了提高工作人员的工作效率和更方便快捷的满足用户,更好存储所有数据信息及快速方便的检索功能,对系统的各个模块是通过许多今天的发达系统做出合理的分析来确定考虑用户的可操作性,…...
手机/平板端 Wallpaper 动态壁纸文件获取及白嫖使用指南
Wallpaper 动态壁纸文件获取及使用指南 目录 壁纸文件获取手机 / 平板使用手机 / 平板效果预览注意事项PC/Mac 使用 1. 壁纸文件获取链接 链接:夸克网盘分享 复制链接到浏览器打开并转存下载即可。 (主页往期视频的 4K 原图和 mpkg 动态壁纸文件…...
【软件工程】模块化思想概述
一、定义 模块化(modularization),也称为模组化,是产品设计以及项目管理中被广泛使用的一种设计理念。 模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部…...
解决方案:机器学习中,出现欠拟合和过拟合,这两种情况分别如何解决
文章目录 一、现象二、解决方案欠拟合(Underfitting)过拟合(Overfitting) 一、现象 在工作中,在机器学习中,出现欠拟合和过拟合的时候,需要有对应的解决方法,所以整理一下 二、解决…...
腾讯 25 届秋招算法工程师面经
最近已有不少大厂都在秋招宣讲了,也有一些在 Offer 发放阶段。 节前,我们邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对新手如何入门算法岗、该如何准备面试攻略、面试常考点、大模型技术趋势、算法项目落地经验分享等热门话题进行了…...
MySQL 实验1:Windows 环境下 MySQL5.5 安装与配置
MySQL 实验1:Windows 环境下 MySQL5.5 安装与配置 目录 MySQL 实验1:Windows 环境下 MySQL5.5 安装与配置一、MySQL 软件的下载二、安装 MySQL三、配置 MySQL1、配置环境变量2、安装并启动 MySQL 服务3、设置 MySQL 字符集4、为 root 用户设置登录密码 一…...
开源黑科技!Fish Speech TTS模型完美支持8种语言
开源黑科技!Fish Speech TTS模型完美支持8种语言 Fish Speech是一款神奇的AI语音克隆工具🎤,可快速模仿用户声音,支持八种语言🌍,简单易用,适合所有人👶。它在客服、新闻播报和在线…...
算法知识点————数论和链表
1、n数和 2数和 有序(递增):头尾相加,和目标值比较无序:哈希表(target - cur) 多数和: 先排序 拿一个数(检测 i 和i-1 重复的不选择) 2数和问题 &am…...
NASA:ATLAS/ICESat-2 L3B 每日和每月网格极地海面高度异常 V003
目录 简介 摘要 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 ATLAS/ICESat-2 L3B Daily and Monthly Gridded Polar Sea Surface Height Anomaly V003 ATLAS/ICESat-2 L3B 每日和每月网格极地海面高度异常 V003 简介 ATLAS/ICESat-2 L3B Daily and Monthly G…...
Java类设计模式
1、单例模式 核心:保证一个类只有一个对象,并且提供一个访问该实例的全局访问点 五种单例模式:主要:饿汉式:线程安全,调用效率高,不能延时加载懒汉式:线程安全,调用效率…...
Valhalla实现 使用Docker部署利用OSM(Mapbox)地图实现路径规划详细步骤
一. Valhalla基本概念 1. 背景介绍: 官网介绍文档:https://valhalla.github.io/valhalla/ Valhalla是一个开源的路由引擎,能够实现实时路径规划,处理大量请求返回最优路径。 基于 OSM 数据,结合灵活的多模式交通方式…...
blender解决缩放到某个距离就不能继续缩放
threejs中也存在同样的问题,原因相同,都是因为相机位置和相机观察点距离太近导致的。 threejs解决缩放到某个距离就不能继续缩放-CSDN博客 blender中的解决方案 1、视图中心->视图锁定->选择你想看的物体...
2022浙江省赛G I M
G - Easy Glide 题意 思路 由于数据范围比较小(1e3),把所有的移动的时间转化为图论上的边权就可以了,再用dijkstra解决,注意如果用的是邻接表存的话要建双向边 代码 #include <map> #include <set> #include <queue> #include <…...
数据链路层 ——MAC
目录 MAC帧协议 mac地址 以太网帧格式 ARP协议 ARP报文格式编辑 RARP 其他的网络服务或者协议 DNS ICMP协议 ping traceroute NAT技术 代理服务器 网络层负责规划转发路线,而链路层负责在网络节点之间的转发,也就是"一跳"的具体传输…...
在java中都是如何实现这些锁的?或者说都有哪些具体的结构实现
在Java中,多种锁机制的实现依赖于不同的类和接口。以下是一些常见的锁机制及其在Java中的具体实现: 1. 互斥锁(Mutex) 实现方式:Java中的互斥锁可以通过synchronized关键字或ReentrantLock类来实现。synchronized关键…...
用CSS创造三角形案例
6.3.2 用CSS创造三角形 用div来创建,角上是平分的,所以要是内部宽高为0,其他边透明,正好是三角形。 代码 div {border: 12px solid;width: 0;height: 0;border-color: transparent red transparent transparent; } 与伪元素aft…...
matlab-对比两张图片的Ycbcr分量的差值并形成直方图
%对比两张图片的Ycbcr分量的差值并形成直方图,改个路径就能用,图片分辨率要一致 close all; clear all; clc; I1imread(E:\test\resources\image\1.jpg); I2imread(E:\test\resources\image\2.jpg); ycbcr1 rgb2ycbcr(I1); ycbcr2 rgb2ycbcr(I2); % …...
Chromium 使用安全 DNS功能源码分析c++
一、选项页安全dns选项如下图: 二、那么如何自定义安全dns功能呢? 1、先看前端部分代码调用 shared.rollup.jsclass PrivacyPageBrowserProxyImpl {.................................................................getSecureDnsResolverList() {re…...
10.1 刷题
C语言 C...
车辆重识别(2021ICML改进的去噪扩散概率模型)论文阅读2024/9/29
所谓改进的去噪扩散概率模型主要改进在哪些方面: ①对数似然值的改进 通过对噪声的那个方差和T进行调参,来实现改进。 ②学习 这个参数也就是后验概率的方差。通过数据分析,发现在T非常大的情况下对样本质量几乎没有影响,也就是说…...
828华为云征文|针对Flexus X实例云服务器的CPU和内存性能测评
目录 一、Flexus X实例云服务器简介 1.1 产品摘要 1.2 产品优势 1.3 本次测评服务器规格 二、CPU性能测试 2.1 操作说明 2.2 操作步骤 2.2 结果分析 三、测试内存负载 3.1 操作说明 3.2 操作步骤 3.3 结果分析 四、测试终评 一、Flexus X实例云服务器简介 1.1 产品…...
Python知识点:如何使用Google Cloud IoT与Python进行边缘计算
开篇,先说一个好消息,截止到2025年1月1日前,翻到文末找到我,赠送定制版的开题报告和任务书,先到先得!过期不候! 如何使用Google Cloud IoT与Python进行边缘计算 边缘计算作为一种新兴的计算模式…...
力扣 最小覆盖子串
最小覆盖子串 https://leetcode.cn/problems/minimum-window-substring/ 题目描述 题目分析f 覆盖子串:首先根据题意,要求目标字符串的元素必须都在子串中出现过,这表明可以是乱序出现。所以在解决问题是我们需要对子串和目标字符串做匹配&a…...
python的内存管理机制
python的内存管理机制主要分为三个部分:引用计数、垃圾回收和内存池机制。 引用计数机制: python通过维护每个对象的引用计数来跟踪内存中的对象。当对象被创建时就会有一个引用计数,当对象不再被使用时,引用计数为0,…...
阿布量化:基于 Python 的量化交易框架
阿布量化(AbuQuant) 是一个开源的量化交易框架,专为金融领域的研究者和交易者设计。它基于 Python 语言开发,提供了一整套从数据获取、策略开发、回测分析到交易执行的解决方案。阿布量化不仅能够帮助用户快速实现量化策略的设计与…...
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-28
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-28 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-28目录前言1. Cognitive phantoms in LLMs through the lens of latent variables摘要研究背景问题与挑战创新点算法模型实验效果…...
南宁国贸网站建设/营销app
深度学习—从入门到放弃(二)简单线性神经网络 1.基本结构 就像昨天说的,我们构建深度学习网络一般适用于数据大,处理难度也大的任务,因此对于网络的结构需要有一个非常深入的了解。这里以一个分类猫狗的线性神经网络…...
西安北郊做网站公司/唐山seo快速排名
链接:题目 来源:牛客网 处女座的期末复习 时间限制:C/C 1秒,其他语言2秒 空间限制:C/C 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 快要期末考试了,处女座现在有n门课程需要…...
大连中山区网站建设/大庆黄页查询电话
前言 首先说明,对于JavaScript这门脚本语言,我是个菜鸟。虽然也写过不少JavaScript代码,但一直是不求甚解,直到最近才开始系统学习这门语言。学习的原因是我即将毕业,过了年就要正式工作了,而我要入职的职位…...
wordpress调用 php文件上传/百度下载安装到手机
事件: 由于前一天的晚上加班了、第二天又接着上班、所以精神上有点不在状态;收到客户的反馈说在slave上找不到master刚刚插入的数据; 阶段1: 遇到这事的第一感觉就是这可能是主从延时、或是slave的复制出错了使得数据没有同步、于…...
wordpress微信对接/seo如何快速排名百度首页
准备材料 高筋面粉,分量自己把握(据说高筋和低筋混合的比较好)酵母粉,分量自己把握黄油,分量自己把握花生油(有条件的可以用橄榄油)盐糖酱油料酒番茄酱洋葱彩椒翅根芝士(非常重要&a…...
一元购物网站怎么做/关于新品牌的营销策划
导LEAD语感谢关注matlab爱好者公众号!如果公众号文章对您有帮助,别忘了点击分享和“在看”哦!若您对公众号有什么意见或建议,请在公众号中回复或在任意文章底部留言!本文作者:过冷水优化算法的讲解姗姗来迟…...