【JavaEE初阶 — 网络编程】TCP流套接字编程
TCP流套接字编程
1. TCP & UDP 的区别
TCP 的核心特点是面向字节流,读写数据的基本单位是字节 byte
2 API介绍
2.1 ServerSocket
定义
ServerSocket 是创建 TCP 服务端 Socket 的API。
构造方法
方法签名 | 方法说明 |
---|---|
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口 |
所以服务器启动,需要绑定端口号
方法
方法签名 | 方法说明 |
---|---|
Socket accept() | 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待 |
void close() | 关闭此套接字 |
2.2 Socket
- Socket 是客户端 Socket ,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
- 不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
构造方法
方法签名 | 方法说明 |
---|---|
Socket(String host, int port) | 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接 |
这个方法的两个参数,都是服务器的IP & 端口,这个版本的构造方法,就是给客户端用的,服务器怎么通过这个类来构造对象呢?后续再来看;
方法
方法签名 | 方法说明 |
---|---|
InetAddress getlnetAddress() | 返回套接字所连接的地址 |
InputStream getlnputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
TCP没有 send(),receive() 这样的操作,但是 TCP 调用 getlnputStream() 会得到个 InputStream 对象;调用 getOutputStream(),得到一个 OutputStream 对象,这两个对象是字节流对象;
虽然 Socket 自身没有读写操作,但是 Socket 可以拿到字节流对象,就可以通过字节流对象,来进行读写操作;
3. 通过TCP实现回显服务器
TCP Echo Server
创建关联对象
通过构造方法,绑定关联的端口号 (和 UDP类似,都是在构造对象的时候,绑定端口号)
实现 start()
处理客户端发送的连接
TCP 和 UDP 服务器 start() 的主循环的第一步有所区别:
- UDP 进入主循环,就可以直接处理请求,根据请求计算响应,把响应返回客户端;
- TCP服务器 ,进入主循环后,因为 TCP 是有连接的,所以第一步是先处理客户端发来的连接;
- 这个连接就类似于打电话,在客户端打电话给服务器时,服务器要先接通电话,才可以进行后续的正常通信;
所以TCP服务器进入主循环的第一步,就是进行接通电话的操作,而拨号操作,是客户端来完成的;
调用 ServerSocket 对象底下的 accept() 方法,起到接听电话的作用;
还需要接收 accept() 方法的返回值:
- 如果客户端和服务器确实已经建立连接了,那 accept() 是可以拿到这个请求连接的;
- 如果客户端没有发起连接,那么 accept() 就会产生阻塞 ,和前面的 receive() 类似;
TCP 服务器后续通过对clientSocket 进行读写数据,来和客户端进行通信;
进一步理解 ServerSocket 和 Socket 的职责划分
处理一个客户端的连接
处理连接的过程比较复杂,因此我们把这个操作封装成一个方法;
可能会涉及到多个客户端的请求和响应,如果服务器接收到多个请求,就要返还给客户端多个响应;
服务器与客户端成功连接,打印日志:
这两个方法可以拿到对端(客户端)的 IP & 端口号;
获取输入流对象&输出流对象
打印出客户端的IP&端口号后,就需要进一步地处理客户端的请求和响应,需要借助 Socket 类内置的 InputStream & OutputStream 来处理这些请求和响应
这里获取到的是输入流对象,后续提供这个对象,来读取客户端的请求;
接下来获取输出流对象,并且处理异常:
拿到输入流对象&输出流对象后,后续读取请求,就使用输入流对象;返回响应,就把响应的内容写入输出流对象中;
接下来,在 try 的代码块中,实现读取请求和返回响应的操作,这些操作分成三步
- 读取请求并解析
- 根据请求计算响应
- 返回响应给客户端
因为在一次连接中,这三个操作可能会解析多次,所以我们提供 while 循环来处理
读取请求
下列操作,读取到的请求是一个字节数组,还需要手动把字节数组再转成字符串,才方便后续的处理和打印:
我们可以借助 Scanner 来进行更简单直接的读取操作,既可以读请求,读出来的请求又已经是一个字符串;
- 把刚刚从 Socket 中拿到的 InputStream 填入 Scanner 中,后续通过 Scanner 直接读取请求中的内容;
- 如果 Scanner 没有再读取到数据,说明连接断开,就可以结束循环了
所以读取请求,可以直接借助 read(),也可以借助 Scanner 来辅助完成
补充
- Scanner 可以控制处理台输入,又可以控制处理文件的输入,还可以控制处理网络的输入;
- Scanner 的构造方法:
- Scanner 的构造方法,填入的是一个InputStream 对象
根据请求计算响应
- 当前编写的是一个回显服务器代码,所以可以直接在计算响应的逻辑返回请求即可
返回响应给客户端
下列写法,会直接拿到 response 中的字节数组,然后通过 outputStream 提供的 write(),来写入输出流对象即可;
这种计算响应的方法,是提供字节的方式填充输出流对象;
除了上述写法,我们还可以利用字符流的方式:
这里的 writer 和 System.out 起到的的效果类似,所以 println,printf 等等都可以通过调用
打印返回响应的日志和连接断开的日志
服务器一次连接可处理多个请求的原理
服务器 start() 的代码块中, process() 方法处理请求返回响应的逻辑,相当于嵌套了两层 while 循环:
因此,可以在服务器与客户端的一次连接中,服务器处理多个请求;
如果在一次连接中,客户端发送多次请求,服务器就返还多个响应(打一次电话可以说一句话或者很多句话);
补充
- 一个连接一个请求(短连接),一个连接多个请求(长连接);
- 因为连接过程的开销非常大,所以在日常开发中,更主流的是长连接,一个连接处理多个请求;
- 就好比锁消除,针对要加锁的多个逻辑,每个逻辑都进行加锁,开销非常大,所以更科学的做法是把这些逻辑合在一起,只进行一次加锁;(和领导汇报工作成果,应该在一次电话中一次性汇总完毕,而不是打多次电话。每次电话只汇报一个成果)
TCP Echo Client
创建 Socket 对象
Socket 在客户端和服务器都可以使用,服务器的 Socket 通过调用accept()拿到,但是客户端的 Socket 就需要通过实例来创建对象;
实现客户端构造方法
在客户端的构造方法中,传入服务器的IP和端口号;
传到构造方法中的字符串IP地址(类似127.0.0.1这样的字符串),不需要任何转换;
对比UDP 的客户端,TCP客户端在构造方法在实例Socket对象后,就会在底层和对端建立TCP连接,连接好后,服务器会记录对端的信息(实例化Socket对象时传入的IP和端口号);
因此,服务器的IP和端口号,在TCP客户端中就不需要再创建变量来保存了;
从控制台中读取请求,发送给服务器
从控制台中读取用户输入信息作为请求
为了实现客户端能够和服务器在一次连接的情况下,发送多次请求,我们设置一个循环:
这步操作可以读取刚刚输入控制台的一行信息,读取到的信息作为客户端的请求;
拿到输入流&输出流
之后就把这个请求写入 Socket 对象中,写的时候也需要拿到Socket对象的 InputStream 输入流& OutputStream 输出流;
为了使用方便,可以对拿到的输入流和输出流再套一层壳
完善循环逻辑
所以在主循环中,第一步操作是从控制台中读取用户输入,把读取到的输入设置为请求:
第二步就是把请求发送给服务器
第三步,就是读取服务器返回的响应,并且把读取到的响应打印到控制台
客户端与服务器交互过程
区分客户端与服务器的 Socket 对象
下列服务器和客户端的两个 socket 对象,分别在不同进程中,甚至在不同主机中,因此绝对不是同一个对象;
这两个对象存在密切的关联关系,可以把这两个 socket 对象理解为两部电话:
- 接通这两部电话后,从A听筒说话,B可以听见;从B听筒说话,A可以听见(从一边对Socket对象写数据,另一边的 Socket 对象就可以读到);
- 但是这两个对象绝对不是同一部电话;
处理细节问题
问题一:冲刷缓冲区
完善 main 方法
程序运行结果
关掉客户端:
再启动一次客户端,并且发送一个数据,并且一敲回车,发现没有反应:
为什么没有反应呢?因为其实刚刚客户端代码,并没有真的把请求发送出去:
这个操作只是把数据放到 “发送缓冲区” 中,还没有真正写入网卡里;
- 发送缓冲区其实就是一块内存空间,对网络/硬盘写数据是一个非常低效的操作,如果频繁地调用这些比较低效的操作,程序运行是非常缓慢的;
- 为了提高效率,就引入一个内存缓冲区,把要写入的数据都放入缓冲区中,再统一进行发送,这样可以减小写硬盘和写网络的次数;
- 但是提高效率的同时,也会产生副作用,就是调用 writer.println 这样的操作,并没有真正地触发发送数据操作,而只是把数据写入缓冲区;
- 当然,把数据写入缓冲区,而不是直接发送这样的行为,是 PrintWriter的行为,如果不套壳,是可以直接发送的;
- 但是在实际开发中,广泛使用了缓冲区这样的概念,调用flush()来刷新缓冲区这个操作是非常关键的;
如何真正地把数据发送出去呢?我们要使用刷新操作(调用 flush() 方法来冲刷缓冲区),把缓冲区的数据强制写入 IO 设备中:
客户端服务器交互结果
问题二:针对 hasNext 对一个完整请求/响应设置标识符
println 的操作,会自动加上一个 \n :
但是如果在这个代码中不加这个 \n,直接使用 print行不行呢?
我们重新启动一下客户端,并且发送内容,发现客户端又没有反应了,并且服务器也没有读到信息:
造成上述原因,是因为 next() 的问题,修改成 print 后,客户端输入的数据也是发送到服务器上了,并且服务器也收到了,但是服务器并没有真正处理,因为服务器有一个hasNext()判断:
补充
- hasNext() 的行为是,判断当前收到的数据是否包含“空白符”,什么是空白符呢?
- 换行,回车,空格,制表符,翻页符......都是空白符;
- 遇到空白符,hasNext()才会认为是一个完整的 next,否则在遇到空白符之前,hasNext() 都会阻塞。
所以刚刚在修改成 print 之后,发送的内容是不包含空白符的内容,hasNext() 就会阻塞而无法进入下面读取请求的逻辑;
总结
- 使用 println,是在约定一个请求/响应,是在使用 \n 作为结束标记,对端在读取数据的时候,也会在读取到 \n 时,判断读取到一个完整的请求/响应;
- 这是我们在使用TCP时,特别需要注意的事项,并且和UDP不一样;
- UDP是以 DatagramPacket 作为单位的,但是TCP则是以字节为单位,但是实际上一个请求,往往是以多个字节构成的;
- 到底多少个字节为一个完整的请求/响应,就需要程序员想办法标记出来,引入分割符是标记一次完整请求/响应的典型方式,不一定是换行,也可以是其他分割符;
问题三:根据不同Socket的生命周期判断是否需要手动关闭
在TCP服务器刚刚编写的代码中,涉及两种Socket:
- ServerSocket的生命周期,贯彻整个服务区进程,不需要手动关闭
- clientSocket 的生命周期是一次连接,而不是整个服务器进程;
- 所以每个客户端连接,都会创建一个新的 clientSocket,每个客户端断开,这个对象就应该 close() 了,但是当前代码并没有对 clientSocket 进行 close() 释放;
- 没有在每次连接结束后,对 clientSocket 进行关闭,就会造成文件资源泄漏的问题(文件一直在打开,而不进行关闭,在打开到一定程度,会把文件描述表耗尽,就无法继续打开新文件)
- 在 poccessConnection() 方法的逻辑执行完毕之后,我们就可以对 clientSocket 进行关闭
总结
- 对于是否需要手动关闭 Socket ,需要我们分析请求它的生命周期是跟随整个进程,还是跟随某个环节;
- 如果是跟随整个进程,那么可以不手动关闭 Socket;如果是每个请求都会创建应该 Socket,或者每一次连接都会创建一个 Socket,或者某一个环节的执行周期,会创建一个Socket,这样的情况,就需要我们手动关闭 Socket;
问题四:服务器无法同时等待 accept() &等待已连接的客户端发送响应
一个服务器能同时给多个客户端提供服务,那么刚刚编写的TCP服务器也可以处理多个请求吗?我们关掉客户端,再重新启动多个客户端:
补充:修改同时启动多个客户端的IDEA设置
IDEA 会默认只启动一个客户端,再启动别的客户端,会先关闭上一个启动的客户端;我们通过这里的设置,就可以让 IDEA 启动多个客户端;
设置好后,我们再来重新启动两个客户端, 并且先后发送请求:
结果在第二个客户端发送请求时,又卡住了,并且第一个创建的客户端多次发送请求的操作是没问题的,服务器都会有一个正常响应,但是第二个客户端无论怎么发送请求,都不会有响应:
并且我们通过服务器日志,可以发现,在第二个客户端上线时,并没有再次打印日志;
如果我们关掉第一个客户端,第二个客户端发送的请求,会马上被服务器接收,并且返回响应
所以当前代码,TCP服务器在同一时刻,只能处理一个客户端发送的请求;
针对上面出现的问题,我们对服务器的处理请求,返回响应这一块代码的关键逻辑进行分析:
如果同一时刻,有多个客户端对一个服务器进行连接,那么第一个和服务器连接的客户端1:
所以当前这个服务器代码,如果已经在处理一个客户端的请求,就没办法处理另一个客户端的请求,服务器代码会卡在循环中,无法重新调用 accept()连接新的服务器,直到连接的客户端退出,导致循环终止;
总结
- 当前服务器代码,无法同时等待 accept 和 等待用户请求;在等待客户端发送请求的时候,没办法等待 accept() ,这个时候,如果有新的客户端连接,也无法接听电话(一个专业销售没办法在给先来的顾客讲解产品的时候,又去接待低级销售后面揽入店的顾客);
- 因此,服务器的代码,导致服务器一次只能处理一个客户端发送的请求,这个代码是不合理的;
4. 服务器引入多线程
如果只是单个线程,无法同时响应多个客户端;为了解决这个问题,此处给每个客户端都分配一个线程;
在服务器主线程中,就只是进行 accept(),每次有新的客户端 accept() 连接成功,就创建一个新的线程,又新线程负责完成,后续对客户端 Socket 对象的引用 clientSocket 的读写操作;
引入线程之后,重新启动服务器和两个客户端,可以发现服务器打印了两个带着不同端口号的日志;
因此,在引入线程之后,服务器可以一边等待请求,一边等待 accept() 连接新的客户端;
5. 服务器引入线程池
客户端连接,服务器就会创建新线程,客户端断开连接,客户端就会销毁线程,为了避免频繁创建销毁线程,也可以引入线程池;
线程池
对于在服务器引入线程池,一般不会使用 newFixedThreadPool,因为会创建一个固定线程数的线程池,意味着同时处理的客户端连接数目就固定了;
把任务都交到线程池中,线程池已经预先创建好了一些线程,提前创建好的线程就可以立刻投入工作,从而减少再去创建线程的开销;
线程不是越多越好,如果线程数量过多,CPU的利用率无法再被提高,还会导致系统调度速度下降;并且创建线程也是需要系统资源的,系统总体资源是有限的(一个主机差不多只能创建几千个线程);
无论是多线程,还是线程池,一个线程都对应一个客户端,并且一个主机创建的线程数目是有上限的,那如果有成千上万个客户端,同时访问一个服务器(一台主机),该怎么办呢?
IO多路复用/IO多路连接(这里不重点讲解,因为JVM中没有原生的 IO 多路复用 API,而是把API重新封装,已经不仅仅是多路复用了,后续会详细讲解针对 Java 的 IO多路复用所使用的 NIO,Netty 等知名网络框架,当前讲的IO是 BIO/Blocking IO);
扩展
基于BIO(同步阻塞IO)的长连接会一直占用系统资源。对于并发要求很高的服务端系统来说,这样的消耗是不能承受的。
- 由于每个连接都需要不停的阻塞等待接收数据,所以每个连接都会在一个线程中运行。
- 一次阻塞等待对应着一次请求、响应,不停处理也就是长连接的特性:一直不关闭连接,不停的处理请求。
实际应用时,服务端一般是基于NIO(即同步非阻塞IO)来实现长连接,性能可以极大的提升。
6. 长短连接
TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接;
长连接和短连接的概念
- 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
- 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。
长连接和短连接区别
- 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
- 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
- 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。
相关文章:
【JavaEE初阶 — 网络编程】TCP流套接字编程
TCP流套接字编程 1. TCP & UDP 的区别 TCP 的核心特点是面向字节流,读写数据的基本单位是字节 byte 2 API介绍 2.1 ServerSocket 定义 ServerSocket 是创建 TCP 服务端 Socket 的API。 构造方法 方法签名 方法说明 ServerS…...
I.MX6U 裸机开发20. DDR3 内存知识
I.MX6U 裸机开发20. DDR3 内存知识 一、DDR3内存简介1. DDR发展历程SRAMSDRAMDDR1DDR2DDR3DDR4DDR5 2. 开发板资源3. DDR3的时间参数1. 传输速率2. tRCD3. CL 参数作用取值范围工作原理4. tRC参数原理单位与取值5. tRAS重要性及作用 二、I.MX6U MMDC 控制器1. MMDC简介…...
微信小程序常用全局配置项及窗口组成部分详解
微信小程序常用全局配置项及窗口组成部分详解 引言 微信小程序作为一种新兴的应用形态,凭借其轻量级、便捷性和丰富的功能,已成为开发者和用户的热门选择。在开发小程序的过程中,了解全局配置项和窗口组成部分是至关重要的。本文将详细介绍微信小程序的常用全局配置项及窗…...
DVWA 在 Windows 环境下的部署指南
目录预览 一、靶场介绍二、前置准备1. 环境准备2.靶场下载 三、安装步骤1.配置Phpstudy2.配置数据库3.配置DVWA4.登入DVWA靶场 四、参考链接 一、靶场介绍 DVWA 一共包含了十个攻击模块,分别是: Brute Force(暴力(破解ÿ…...
JVM:即时编译器,C2 Compiler,堆外内存排查
1,即时编译器 1.1,基本概念 常见的编译型语言如C,通常会把代码直接编译成CPU所能理解的机器码来运行。而Java为了实现“一次编译,处处运行”的特性,把编译的过程分成两部分,首先它会先由javac编译成通用的…...
AI开发-机器学习库-sklearn
1 需求 官网:scikit-learn: machine learning in Python — scikit-learn 1.5.2 documentation scikit - learn(简称sklearn)是一个用于机器学习的开源 Python 库。它建立在NumPy、SciPy和matplotlib之上,提供了丰富的工具用于数…...
Opencv+ROS实现摄像头读取处理画面信息
一、工具 ubuntu18.04 ROSopencv2 编译器:Visual Studio Code 二、原理 图像信息 ROS数据形式:sensor_msgs::Image OpenCV数据形式:cv:Mat 通过cv_bridge()函数进行ROS向opencv转换 cv_bridge是在ROS图像消息和OpenCV图像之间进行转…...
git使用记录与总结
目录 前言 一、git是什么? 二、使用记录 1.git安装 2.git clone 3.-lfs初始化 4.git add 5.git commit 6.git push 相关问题与解决 总结 前言 随着Github、hugging face等平台各种开源代码、模型的广泛使用,个人可以使用git方便的下载代码与…...
uniapp中uni-popup在小程序中滚动穿透问题
uniapp中uni-popup在小程序中滚动穿透问题 官网例子 使用场景,在小程序中一个页面内容很长,点击某一项需要弹框,这个弹框需要定位在一定位置,下面的页面不需要滚动 1.直接在模板中添加 <template><page-meta :page-styl…...
限制账号密码格式的正则表达式来啦
. 代表任意字符 \w 代表字母、数字、下划线 \d 代表数字 指定字符重复1次或者n次,最少1次 ? 指定字符重复0-1次 {n} 只能重复n次 {a,} 最少重复a次 {,a} 最多重复a次 {a,b} 最少重复a次,最多重复b次 \s 空格 | 代表或者 [a-zA-Z0-9]…...
linux下USB设备状态查询
linux下USB设备状态查询 linux下USB设备状态查询 在buildroot RK3568平台上调试USB视频采集时发现,USB设备经常性断开,为发现其断开的规律,编写脚本记录其断开的时间 linux下USB设备状态查询 #周期性查询 USB设备 cat > /usr/bin/usbenq…...
Java 线程池有限大小工作队列 - 不丢弃任务的实现
我们在创建 Java 线程池,无论是用 Executors, ThreadPoolExecutor, 还是 Spring 的 ThreadPoolTaskExecutor, 如果不指定工作队列的大小的话,默认为 Integer.MAX_VALUE(2147483647), 基本不会把它爆满,但是在许多的任务要执行时大量 Runnable…...
GitLab的使用
文章目录 一、什么是GitLab、有什么用、与Jenkins的区别什么是GitLab及其用途GitLab与Jenkins的区别GitLab的CI/CD功能介绍 二、GitLab的安装与配置Linux下GitLab的安装*Linux下GitLab的简单使用 /etc/gitlab/gitlab.rb 的配置GitLab服务器的域名邮箱配置功能优化关闭一些暂时不…...
ffmpeg.js视频播放(转换)
chrome 临时设置SharedArrayBuffer "C:\Program Files\Google\Chrome\Application\chrome.exe" --enable-featuresSharedArrayBuffer 引用的js及相关文件 ffmpeg.min.js ffmpeg.min.js.map ffmpeg-core.js ffmpeg-core.wasm ffmpeg-core.worker.js 以上几个现…...
免费实用在线AI工具集合 - 加菲工具
免费在线工具-加菲工具 https://orcc.online/ sql格式化 https://orcc.online/tools/sql 时间戳转换 https://orcc.online/tools/timestamp Base64 编码解码 https://orcc.online/tools/base64 URL 编码解码 https://orcc.online/tools/url Hash(MD5/SHA1/SHA256…) 计算 h…...
C# 常量
文章目录 前言一、整数常量(一)合法与非法实例对比(二)不同进制及类型示例 二、浮点常量三、字符常量四、字符串常量五、定义常量 前言 在 C# 编程的世界里,常量是一类特殊的数据元素,它们如同程序中的 “定…...
elasticsearch单节点模式部署
原文地址:elasticsearch单节点模式部署 – 无敌牛 欢迎参观我的个人博客:无敌牛 – 技术/著作/典籍/分享等 第一步:下载 官方下载地址:Download Elasticsearch | Elastic,可以 wget 直接下载。 命令:wg…...
C#+数据库 实现动态权限设置
将权限信息存储在数据库中,支持动态调整。根据用户所属的角色、特定的功能模块,动态加载权限” 1. 数据库设计 根据这种需求,可以通过以下表设计: 用户表 (Users):存储用户信息。角色表 (Roles):存储角色…...
ubuntu客户端使用飞牛云的smb服务端共享,和ftp记录
ubuntu smb客服端链接 在Ubuntu上设置SMB客户端连接到SMB服务器,你可以使用smbclient工具或者挂载共享目录。以下是使用smbclient和挂载的简单示例: 使用smbclient连接SMB服务器 安装smbclient: sudo apt-update sudo apt-get install smbcli…...
自然语言处理工具-广告配音工具用于语音合成助手/自媒体配音/广告配音/文本朗读-已经解锁了 全功能的 apk包
Android -「安卓端」 广告配音工具用于语音合成助手/自媒体配音/广告配音/文本朗读。 广告配音工具:让您的文字“说话”,在这个快速发展的数字时代,广告配音工具为各种语音合成需求提供了一站式解决方案。无论是自媒体配音、商业广告配音、…...
华为E9000刀箱(HWE9000V2)服务器硬件监控指标解读
随着数据中心规模的不断扩大,服务器的稳定性和可靠性变得尤为重要。华为E9000刀箱(HWE9000V2)作为一款高性能的服务器设备,其硬件状态的实时监控对于保障业务的连续性和系统的稳定运行至关重要。 监控易作为一款专业的IT基础设施监…...
消息队列场景下的前端设计:如何优化用户体验
在现代分布式系统中,消息队列被广泛用于解耦服务和异步处理。但由于消息队列的异步特性,任务提交后无法立即获得处理结果,这给前端的交互设计带来了新的挑战。本文将探讨如何在这种场景下优化前端用户体验。 一、问题分析 在使用消息队列后&…...
智能探针技术:实现可视、可知、可诊的主动网络运维策略
网络维护的重要性 网络运维是确保网络系统稳定、高效、安全运行的关键活动。在当今这个高度依赖信息技术的时代,网络运维的重要性不仅体现在技术层面,更关乎到企业运营的方方面面。网络运维具有保障网络的稳定性、提升网络运维性能、降低企业运营成本等…...
23种设计模式-装饰器(Decorator)设计模式
文章目录 一.什么是装饰器设计模式?二.装饰器模式的特点三.装饰器模式的结构四.装饰器模式的优缺点五.装饰器模式的 C 实现六.装饰器模式的 Java 实现七.代码解析八.总结 类图: 装饰器设计模式类图 一.什么是装饰器设计模式? 装饰器模式&…...
分布式搜索引擎之elasticsearch单机部署与测试
分布式搜索引擎之elasticsearch单机部署与测试 1.部署单点es 1.1.创建网络 因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络: docker network create es-net1.2.加载镜像 这里我们采用elasticsearch的7.12.1版本的…...
Java项目中加缓存
Java项目中加缓存 1.更新频率低;但读写频率高的数据很适合加缓存; 2.可以加缓存的地方很多:浏览器的缓存;CDN的缓存;服务器的缓存; 本地内存;分布式远端缓存; 加缓存的时候不要…...
【计算机视觉】图像基本操作
1. 数字图像表示 一幅尺寸为MN的图像可以用矩阵表示,每个矩阵元素代表一个像素,元素的值代表这个位置图像的亮度;其中,彩色图像使用3维矩阵MN3表示;对于图像显示来说,一般使用无符号8位整数来表示图像亮度&…...
修改插槽样式,el-input 插槽 append 的样式
需缩少插槽 append 的 宽度 方法1、使用内联样式直接修改,指定 width 为 30px <el-input v-model"props.applyBasicInfo.outerApplyId" :disabled"props.operateCommandType input-modify"><template #append><el-button click…...
高级java每日一道面试题-2024年11月28日-JVM篇-调优命令有哪些?
如果有遗漏,评论区告诉我进行补充 面试官: 调优命令有哪些? 我回答: 在Java高级面试中,调优命令是面试官常问的问题之一。以下是对Java调优命令的详细介绍: 一、主要调优命令 1. jps(JVM Process Status Tool) 功能&#x…...
Dubbo 最基础的 RPC 应用(使用 ZooKeeper)
看国内的一些项目时 Dubbo 这个词经常闪现,一直也不以为然,未作搜索,当然也不知道它是做什么用的。直到最近阅读关于大型网站架构相关的书中反复提到 Dubbo 后,觉得不能再对它视而不见。Google 了一下,它是在阿里巴巴创…...
(0基础保姆教程)-JavaEE开课啦!--11课程(初识Spring MVC + Vue2.0 + Mybatis)-实验9
一、什么是Spring MVC? Spring MVC 是一个基于 Java 的 Web 框架,遵循 MVC 设计模式,用于构建企业级应用程序。它通过控制器(Controller)处理用户请求,模型(Model)处理业务逻辑,视图(View)展示数据,实现了请…...
九、Spring Boot集成Spring Security之授权概述
文章目录 往期回顾:Spring Boot集成Spring Security专栏及各章节快捷入口前言一、授权概述二、用户权限三、用户授权流程三、Spring Security授权方式1、请求级别授权2、方法级别授权 往期回顾:Spring Boot集成Spring Security专栏及各章节快捷入口 Spr…...
QT:多ui界面显示
文章目录 1.多ui界面添加2.跳转函数3.返回函数4.Qt5源码工程5.模态显示 1.多ui界面添加 最终生成这个目录 2.跳转函数 void MainWindow::on_pushButton_clicked() {//this->setWindowModality(Qt::WindowModal);test1 *t1 new test1();t1->setParentData(this);this-…...
人工智能在医疗领域应用的案例参考
以下是一些人工智能在医疗领域应用的具体案例: 疾病诊断辅助 谷歌旗下DeepMind与伦敦大学学院医院合作 案例详情:利用人工智能系统对眼部疾病进行诊断,分析眼部扫描图像,快速准确地检测出眼部疾病的早期迹象,如青光眼…...
vue3 与 spring-boot 完成跨域访问
spring-boot,写一个接口用于前端访问,并且给接口设置跨域访问,这里我前端的域名为 localhost:5173 RestController CrossOrigin(origins "http://localhost:5173") public class Vue3Controller {GetMapping("/vue")pu…...
CSS clamp() 函数:构建更智能的响应式设计
在响应式设计中,我们经常需要处理元素大小的动态变化。CSS clamp() 函数提供了一个优雅的解决方案,让我们的设计更加灵活和智能。 clamp() 函数是什么? clamp() 函数接受三个参数: clamp(最小值, 首选值, 最大值)这三个参数分别…...
【C++笔记】数据结构进阶之二叉搜索树(BSTree)
【C笔记】数据结构进阶之二叉搜索树(BSTree) 🔥个人主页:大白的编程日记 🔥专栏:C笔记 文章目录 【C笔记】数据结构进阶之二叉搜索树(BSTree)前言一.二叉搜索树的概念二.二叉搜索树的性能分析三.二叉搜索树的实现3.1二叉树的中序…...
c++设计模式模块与系统
c 中lambda 本质就是一个匿名(没有名)的函数; 可以用一个数组元素存储一个函数的指针; 通过数组下标来使用函数; 高内聚低耦合 如何理解设计模式中的高内聚低耦合 高内聚: 用于指导如何组织和划分软件设计。 **定义:**高内聚指的…...
【81-90期】Java核心面试问题深度解析:性能优化与高并发设计
🚀 作者 :“码上有前” 🚀 文章简介 :Java 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 文章题目:Java核心面试问题深度解析:性能优化与高并发设计 摘要: 本文聚…...
python实现TCP服务端,支持对所有客户端的数据收发,支持终端自定义命令操作,提供clear命令一键断开所有的客户端连接
前言 python实现TCP服务端,支持对所有客户端的数据收发,支持终端自定义命令操作,提供clear命令一键断开所有的客户端连接 简单易懂,直接上码 源码 import socket import threadingclass TCPServer:# 修改此处ip 端口def __ini…...
【R安装】R语言的详细安装及环境配置(2024年11月)
目录 R及Rstudio下载R下载Rstudio下载 R及Rstudio安装R安装Rtools 安装Rstudio安装 运行 RStudio通过RStudio配置使用特定的R版本 参考 R及Rstudio下载 R下载 R官网-The R Project for Statistical Computing 点击【download R】,进入下载界面: 选择…...
Android 12.0 通知--PendingIntent基本代码
一. PendingIntent 在 Android 通知中的使用场景 使用场景: Android 通知的 setContentIntent() 需要传入 PendingIntent , 即当点击通知时,执行 intent 的动作.如下例子: //1.创建Intent对象Intent intent new Intent(this, MainActivity1.class); //2.获取能启动 Activity 的…...
网络安全在数字时代保护库存数据中的作用
如今,通过软件管理库存已成为一种标准做法。企业使用数字工具来跟踪库存水平、管理供应链和规划财务。 然而,技术的便利性也带来了网络威胁的风险。黑客将库存数据视为有价值的目标。保护这些数据不仅重要,而且必不可少。 了解网络安全及其…...
文本搜索程序(Qt)
头文件 #ifndef TEXTFINDER_H #define TEXTFINDER_H#include <QWidget> #include <QFileDialog> #include <QFile> #include <QTextEdit> #include <QLineEdit> #include <QTextStream> #include <QPushButton> #include <QMess…...
云原生革命:构建未来应用的无限可能
在这个数字化飞速发展的时代,云原生技术如同一股不可阻挡的潮流,正深刻改变着软件开发和部署的方式。它不仅仅是一种技术变革,更是一场关于如何更高效、更灵活地构建和运行应用的革命。今天,我们就来深入探讨云原生的魅力所在&…...
【Ubuntu 24.04】How to Install and Use NVM
参考 下载 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash激活 Activate NVM: Once the installation script completes, you need to either close and reopen the terminal or run the following command to use nvm immediately. exp…...
android12锁屏界面pin码或者图案解锁居中显示
设置pin码或者图案锁屏后,在锁屏界面向上划左边,图案解锁就在左边, 向上划右边图案就在右边,如何设置一直居中显示呢? diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI…...
【VUE3】新版Vue3+ElementPlus全家桶开发视频项目实战
VUE 介绍 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。 Vue.js是一个MVVM(Model - View - ViewModel)的SPA框架。 Model:数…...
【UE5 C++课程系列笔记】05——组件和碰撞
效果 可以看到我们可以实现的功能是 (1)可以通过鼠标旋转视角 (2)通过使用Pawn移动组件来控制Pawn移动 (3)Pawn碰到物体会被阻挡然后逐渐滑动 (4)通过空格切换激活/关闭粒子效果…...
【docker 拉取镜像超时问题】
问题描述 在centosStream8上安装docker,使用命令sudo docker run hello-world 后出现以下错误: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Ti…...