Java 输入与输出之 NIO【非阻塞式IO】【NIO网络编程】探索之【二】

news2024/9/24 15:19:19

上一篇博客我们介绍了NIO的核心原理、FileChannel和Buffer, 对Buffer的用法有了清晰的了解。上篇博客:
Java 输入与输出之 NIO【非阻塞式IO】【NIO核心原理】探索之【一】
本篇博客我们将继续来探索NIO,介绍如何使用SocketChannel和ServerSocketChannel来实现TCP协议的非阻塞套接字(Socket)网络通信程序编程。NIO的强大功能部分来自于Channel的非阻塞特性,套接字的某些操作可能会无限期地阻塞。例如,对accept()方法的调用可能会因为等待一个客户端连接而阻塞;对read()方法的调用可能会因为没有数据可读而阻塞,直到连接的另一端传来新的数据。总的来说,创建/接收连接或读写数据等I/O调用,都可能无限期地阻塞等待。
NIO的Channel抽象的一个重要特征就是可以通过配置它的阻塞行为,以实现非阻塞式的信道。
下面这行代码设置了通道的非阻塞模式:
channel.configureBlocking(false)

在非阻塞式信道上调用一个方法总是会立即返回。这种调用的返回值指示了所请求的操作完成的程度。例如,在一个非阻塞式ServerSocketChannel上调用accept()方法,如果有连接请求来了,则返回客户端SocketChannel,否则返回null。

三、利用NIO编写网络通信程序(Selector的核心应用)

网络通信相关的三大核心组件:

  1. 通道(channel):负责管道节点的连接及数据的运输
  2. 缓冲区(buffer):负责数据的存取
  3. 选择器(selector)及selectionKey:是selectableChannel的多路复用器,用于监控SelectableChannel的IO状况。而选择键(SelectionKey)则是一种将通道和选择器(Selector)进行关联的机制。

SocketChannel: 是通道Channel重要的实现类,用于TCP协议的网络通信,用于实现网络通讯客户端的应用程序;
ServerSocketChannel: 是通道Channel重要的实现类,用于监听TCP连接请求,主要用于实现网络通讯服务器端的应用程序。

阻塞与非阻塞

  1. 阻塞式
    传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
  2. 非阻塞式
    Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同
    时处理连接到服务器端的所有客户端。

利用Java NIO网络通讯应用程序的操作步骤和示意图
Java 在使用NIO进行网络编程时,多线程应用程序的操作步骤和示意图如下所示:
处理步骤:

  1. 创建通道:
    打开一个或多个通道,例如FileChannel、SocketChannel等。
    创建缓冲区:为每个通道创建一个或多个缓冲区,用于读取或写入数据。
  2. 注册通道:
    将通道注册到选择器,以便选择器可以监控这些通道的状态。
  3. 选择就绪通道:
    选择器等待通道就绪事件,一旦有通道准备好进行I/O操作,选择器将通知应用程序。
  4. 读取/写入数据:
    应用程序从通道读取数据或将数据写入通道,使用缓冲区来传输数据。

在这里插入图片描述
其中,通道和缓冲区是一对一的关系。每个通道都有一个与之对应的缓冲区,用于存储数据。
选择器(Selector)可以同时监视多个通道的状态。一个选择器可以绑定多个通道,以实现多路复用。
selectionKey有以下四个方法,可用来测试四种状态,它们都会返回一个布尔类型:
selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();

通过Selector选择通道
一旦向Selector注册了一个或多个通道,就可以调用几个重载的select()方法。这些方法返回你所感兴趣的事件(如连接、接受、读或写)已经准备就绪的那些通道。换句话说,如果你对“读就绪”的通道感兴趣,select()方法会返回读事件已经就绪的那些通道。

下面是select()方法:
int select()
int select(long timeout)
int selectNow()
select()阻塞到至少有一个通道在你注册的事件上就绪了。
select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。
selectNow()不会阻塞,不管什么通道就绪都立刻返回(译者注:此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。)。

select()方法返回的int值表示有多少通道已经就绪。

网络通信应用例程
我们先来看一个网络通信应用的例程,客户端采用NIO实现,而服务端依旧使用IO实现。

  1. NIO非阻塞实现的客户端

采用NIO的客户端程序源代码:

package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;
public class SocketClientNIO {
    public static void client(){
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        SocketChannel socketChannel = null;
        try
        {
        	SocketAddress server = new InetSocketAddress("127.0.0.1",8080);
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false); //非阻塞式
            socketChannel.connect(server);
            //与服务端连接成功
            if(socketChannel.finishConnect()) 
            {
                int i=0;
                while(true)
                {
                    TimeUnit.SECONDS.sleep(1);
                    String info = "客户端发送信息,第 "+ ++i +"条";
                    buffer.clear();
                    buffer.put(info.getBytes("GBK"));
                    buffer.flip(); //切换
                    while(buffer.hasRemaining()){
                        System.out.println(buffer);
                        socketChannel.write(buffer);
                    }
                }
            }
        }
        catch (IOException | InterruptedException e)
        {
            e.printStackTrace();
        }
        finally{
            try{
                if(socketChannel!=null){
                    socketChannel.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

	public static void main(String[] args) {
		SocketClientNIO.client();
	}
}

网络通讯程序的服务器端的实现详解:

网络通讯服务器程序的核心逻辑:
服务器首先创建了一个非阻塞的ServerSocketChannel,并将其注册到Selector上去监听ACCEPT事件(即连接事件)。
在一个无限循环中,它会调用selector.select()来等待注册的事件发生,并处理这些事件。对于每个ACCEPT事件,它会接受新的连接,并将其设置为非阻塞模式。
在实际应用中,可以在接受连接后注册更多的事件(如读、写事件),并在事件处理代码中实现网络通信的业务处理逻辑。

选择器selector使用步骤
创建选择器selector
通过调用Selector.open()方法创建一个Selector。
向选择器selector注册通道
注册之前,先设置通道为非阻塞的,channel.configureBlocking(false);然后再调用SelectableChannel.register(Selector sel,int ops)方法将channel注册到Selector中;其中ops的参数作用是设置选择器对通道的监听事件,ops参数的事件类型有四种(可以通过SelectionKey的四个常量表示):
(1)读取操作:SelectionKey.OP_READ,数值为1.
(2)写入操作:SelectionKey.OP_WRITE,数值为4.
(3)socket连接操作:SelectionKey.OP_CONNECT,数值为8.
(4)socket接受操作:SelectionKey .OP_ACCEPT,数值为16.
若注册时不止监听一个事件,可以使用“| 位或”操作符连接。

选择键SelectionKey
表示SelectableChannel在Selector中的注册的标志,每次向选择器注册通道的时候就会选择一个事件(以上四种事件类型)即选择键,选择键包含两个表示位整数值的操作集(分别为interst集合和ready集合),操作集的每一位都表示该键的通道所支持的一类可选择操作。
在这里插入图片描述

下面我们提供三个服务器应用程序的版本。

  1. 服务器版本一,采用阻塞式IO实现的网络通讯服务器端程序(特点是简单)的源代码:
package nio;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;

public class SocketServerIO {
    public static void server(){
        ServerSocket serverSocket = null;
        InputStream in = null;
        try
        {
            serverSocket = new ServerSocket(8080);
            System.out.println("服务器开启,等待接收客户端连接");
            int recvMsgSize = 0;
            byte[] recvBuf = new byte[1024];
            while(true){
                Socket client = serverSocket.accept();
                SocketAddress clientAddr = client.getRemoteSocketAddress();
                System.out.println("接收到客户端,连接IP: "+clientAddr);
                in = client.getInputStream();
                while((recvMsgSize=in.read(recvBuf))!=-1){
                    byte[] temp = new byte[recvMsgSize];
                    System.arraycopy(recvBuf, 0, temp, 0, recvMsgSize);
                    System.out.println("接收报文:"+new String(temp,"GBK"));
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally{
            try{
                if(serverSocket!=null){
                    serverSocket.close();
                }
                if(in!=null){
                    in.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

	public static void main(String[] args) {
		SocketServerIO.server();
	}

}

现在我们来调试一下这一对服务端和客户端网络通讯程序。
首先,编译后执行服务端应用程序,开启服务器服务,以接受客户端的请求;
然后,编译执行客户端的应用程序。下面是服务端的测试效果:
在这里插入图片描述

  1. 服务器版本二,利用NIO实现的非阻塞模式的网络通讯服务器端
    本例程的Buffer采用非直接缓冲区:
    // 创建一个缓冲区
    private static ByteBuffer buffer = ByteBuffer.allocate(1024);
    服务器源代码如下:
package nio;
/***
 * @author QiuGen
 * @description  NIO网络通讯服务器
 * *** 本例程的Buffer采用非直接缓冲区
 * @date 2024/8/28
 * ***/
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class SocketServer {
    private static final int TIMEOUT = 3000;
    // 创建一个缓冲区
    private static ByteBuffer buffer = ByteBuffer.allocate(1024);
    
	public static void handleRead(SelectionKey key) throws IOException{
        // 获取当前key的通道
        SocketChannel socketChannel = (SocketChannel) key.channel();

        // 从通道中读取数据到缓冲区
        int len = socketChannel.read(buffer);
        String inf = null;
        byte[] tmpBuf = new byte[1024];
        while ( len > 0 ) {
            buffer.flip(); //切换
            while(buffer.hasRemaining()){
            	buffer.get(tmpBuf, 0, len);
            	inf = new String(tmpBuf, "GBK");
                System.out.print("接收报文: "+inf);
            }
            System.out.println();
            buffer.clear(); //初始化缓冲区
            len = socketChannel.read(buffer);
        }
	}
	
    public static void handleWrite(SelectionKey key) throws IOException{
        //ByteBuffer buf = (ByteBuffer)key.attachment();
    	buffer.flip(); //切换
        SocketChannel sc = (SocketChannel) key.channel();
        while(buffer.hasRemaining()){
            sc.write(buffer);
        }
        buffer.compact();
    }
	
	public static void main(String[] args) throws IOException {
        // 创建一个服务器套接字通道
        ServerSocketChannel socketChannel = ServerSocketChannel.open();

        // 将服务器套接字通道绑定到指定端口
        socketChannel.bind(new InetSocketAddress(8080));

        // 将服务器套接字通道设置为非阻塞模式
        socketChannel.configureBlocking(false);

        // 创建一个选择器
        Selector selector = Selector.open();

        // 将服务器套接字通道注册到选择器上,监听连接事件
        socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("SocketServerNIO非直接缓冲区,服务端启动***");

        while (true) {
        	//等待选择器Selector上注册的事件
            if(selector.select(TIMEOUT) == 0){
                System.out.println("服务器空闲,等待客户端连接***");
                continue;
            }
            
            // 获取所有发生的SelectionKey
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            // 遍历所有SelectionKey
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                // 获取当前SelectionKey
                SelectionKey key = iterator.next();

                // 判断当前键的通道是否准备好接收socket连接
                if (key.isAcceptable()) { // 处理客户端连接事件
                    // 接受客户端连接
                    SocketChannel sc = socketChannel.accept();

                    // 将客户端连接通道设置为非阻塞模式
                    sc.configureBlocking(false);

                    // 将客户端连接通道注册到选择器上,监听读事件
                    sc.register(selector, SelectionKey.OP_READ);
                    // 判断当前key的通道是否准备好读取操作
                } 
                if (key.isReadable()) { //处理读事件
                	handleRead(key);
                }
                if(key.isWritable() && key.isValid()){ //处理写事件
                    handleWrite(key); 
                }

                // 移除当前事件
                iterator.remove();
            }
        }
	}
}

与客户端连调,测试结果如下:
在这里插入图片描述

  1. 服务器版本三,利用NIO实现的非阻塞模式的网络通讯服务器端应用程序源码:
    本例程的Buffer采用直接缓冲区:
    ByteBuffer.allocateDirect(BUF_SIZE);
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class SocketServerNIO {
    private static final int BUF_SIZE=1024;
    private static final int PORT = 8080;
    private static final int TIMEOUT = 3000;
    
    public static void handleAccept(SelectionKey key) throws IOException{
        ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
        SocketChannel sc = ssChannel.accept();
        sc.configureBlocking(false);
        sc.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocateDirect(BUF_SIZE));
    }
 
    public static void handleRead(SelectionKey key) throws IOException{
        SocketChannel sc = (SocketChannel)key.channel();
        ByteBuffer buf = (ByteBuffer)key.attachment();
        int bytesRead = sc.read(buf);
        String inf = null;
        byte[] tmpBuf = new byte[1024];
        while(bytesRead>0){
            buf.flip();
            while(buf.hasRemaining()){
            	//System.out.print((char)buf.get());
            	buf.get(tmpBuf, 0, bytesRead);
            	inf = new String(tmpBuf, "GBK");
                System.out.print("接收报文: "+inf);
            }
            System.out.println();
            buf.clear();
            bytesRead = sc.read(buf);
        }
        if(bytesRead == -1){
            sc.close();
        }
    }
 
    public static void handleWrite(SelectionKey key) throws IOException{
        ByteBuffer buf = (ByteBuffer)key.attachment();
        buf.flip();
        SocketChannel sc = (SocketChannel) key.channel();
        while(buf.hasRemaining()){
            sc.write(buf);
        }
        buf.compact();
    }
 
    public static void server() {
        Selector selector = null;
        ServerSocketChannel ssc = null;
        try{
            selector = Selector.open();
            ssc= ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(PORT));
            ssc.configureBlocking(false);
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("SocketServerNIO,服务端启动***");
            while(true){
                if(selector.select(TIMEOUT) == 0){
                    System.out.println("服务端空闲,等待客户端连接==");
                    continue;
                }
                Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
                while(iter.hasNext()){
                    SelectionKey key = iter.next();
                    if(key.isAcceptable()){
                        handleAccept(key);
                    }
                    if(key.isReadable()){
                        handleRead(key);
                    }
                    if(key.isWritable() && key.isValid()){
                        handleWrite(key);
                    }
                    if(key.isConnectable()){
                        System.out.println("isConnectable = true");
                    }
                    iter.remove();
                }
            }
 
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try{
                if(selector!=null){
                    selector.close();
                }
                if(ssc!=null){
                    ssc.close();
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
    

	public static void main(String[] args) {
		SocketServerNIO.server();
	}

}

以同样方法进行网络通讯测试:首先编译后执行服务器端应用程序;然后编译执行上面同一个客户端应用程序发送报文。服务端测试结果如下图:
在这里插入图片描述

说明:
对于大负荷的服务器应用程序实现时,建议Buffer采用直接缓冲区方案,应当会有更优异的性能。

参考文献&博客:

  1. 参考文献之一
    攻破JAVA NIO技术壁垒
  2. 参考文献之二
    Java NIO详解[通俗易懂]
  3. 参考文献之三
    Java NIO全面详解(看这篇就够了)

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

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

相关文章

完全自由的栏目设计

亮点功能&#xff1a; 可以将任一栏目拖动到其它栏目下 被拖动的栏目其包含的子栏目和文章将一起拖过去。 快来试试吧&#xff01;

原来这么多行业都可以转行大模型,大模型从入门到精通,非常详细收藏我这一篇就够了

转行到大模型&#xff08;Large Model&#xff09;领域已经成为当前科技发展的一大趋势。所谓“大模型”&#xff0c;通常指的是那些包含数亿甚至数十亿参数的深度学习模型&#xff0c;例如自然语言处理中的GPT系列、BERT等模型&#xff0c;以及计算机视觉领域的EfficientNet、…

[Pyplot]设置图中字体为TimesNewRoman

一、简介 本文介绍了如何在linux环境下在python中使用matplotlib.pyplot 绘制图表时&#xff0c;令其中的文字字体为Times New Roman。 二、设置步骤 1. Linux下安装Times New Roman字体 $ sudo apt install ttf-mscorefonts-installer # 安装字体 $ sudo fc-cache # 使新安…

Python与Biome-BGC:生态模型分析的未来趋势

近年来&#xff0c;Python编程语言受到越来越多科研人员的喜爱&#xff0c;在多个编程语言排行榜中持续夺冠。同时&#xff0c;伴随着深度学习的快速发展&#xff0c;人工智能技术在各个领域中的应用越来越广泛。机器学习是人工智能的基础&#xff0c;因此&#xff0c;掌握常用…

扩博智能× Milvus:图像检索助力零售商品图像高效标注

大家好&#xff0c;我是上海扩博智能技术有限公司的Frank&#xff0c;负责算法工程相关的工作。很高兴能在 Milvus 社区和大家分享我们在图像检索方面的经验。 01 扩博智能公司简介 扩博智能 Clobotics 成立于 2016 年&#xff0c;总部位于上海长宁。我们聚焦计算机视觉和机器学…

SOMEIP_ETS_071: Union_Length_too_long

测试目的&#xff1a; 验证当设备&#xff08;DUT&#xff09;接收到一个联合&#xff08;union&#xff09;长度超出实际联合长度的SOME/IP消息时&#xff0c;是否能够返回错误消息。 描述 本测试用例旨在检查DUT在处理一个echoUNION方法的SOME/IP消息时&#xff0c;如果消…

基于DashScope+Streamlit构建你的机器学习助手(入门级)

前言 在LLM&#xff08;大语言模型&#xff09;盛行的今天&#xff0c;博主越来越感觉到AI&#xff08;人工智能&#xff09;的潜力被“无限”激发了。它为什么会突然间完成“鱼跃龙门”呢&#xff1f; 博主认为基础设施&#xff08;也可以称为算力&#xff09;的完善和“天才…

Java-异常处理try catch finally throw和throws

在 Java 中,异常处理机制是通过 try, catch, finally, throw和 throws 这几个关键字来实现的。以下 是这些关键字的基本用途和它们之间的区别: public class ExceptionHandlingExample {public static void main(String[] args) {try {processSomething();} catch (Exceptio…

【视频讲解】SMOTEBoost、RBBoost和RUSBoost不平衡数据集的集成分类酵母数据集、治癌候选药物|数据分享...

全文链接&#xff1a;https://tecdat.cn/?p37502 分析师&#xff1a;Zilin Wu 在当今的大数据时代&#xff0c;科研和实际应用中常常面临着海量数据的处理挑战。在本项目中&#xff0c;我们拥有上万条数据&#xff0c;这既是宝贵的资源&#xff0c;也带来了诸多难题。一方面&a…

RFFT:数据与代码已开源,京东推出广告图生成新方法 | ECCV 2024

论文将多模态可靠反馈网络&#xff08;RFNet&#xff09;结合到一个循环生成图片过程中&#xff0c;可以增加可用的广告图片数量。为了进一步提高生产效率&#xff0c;利用RFNet反馈进行创新的一致条件正则化&#xff0c;对扩散模型进行微调&#xff08;RFFT&#xff09;&#…

行业机遇!程序员:如何选择适合自己的就业方向?

随着科技的不断进步和发展&#xff0c;程序员的就业前景也越来越广阔。而在这个快速发展的行业中&#xff0c; 在各个领域都有着广泛的应用&#xff0c;信息技术的迅猛发展使得程序员在现代社会中占据了举足轻重的地位。从软件开发到网络安全&#xff0c;再到人工智能&#xf…

超越Text2Video-Zero|无需额外训练,条件生成、专门生成和指令引导的视频编辑全搞定!

论文链接&#xff1a;https://arxiv.org/pdf/2407.21475 github链接&#xff1a; https://densechen.github.io/zss/ 亮点直击 本文提出了一种新颖的zero-shot视频采样算法&#xff0c;该算法能够直接从预训练的图像扩散模型中采样高质量的视频片段。 本文提出了一个依赖噪声模…

青岛实训day33(8/21)

1、配置一主二从mysql 1. mycat对mysql8不完全支持 2. mysql8主从问题不大get_pub_key1 3. gtids事务复制 4. 删除/etc/my.cnf 5. 同步data文件需要先停用mysql服务,删除data目录中的auto.cnf 6. gtid模式以及经典模式都需要锁表 flush tables with read lock;unlock tables;…

解决渠道低价问题可以这样做

在品牌渠道的发展之路上&#xff0c;经销商低价、乱价、窜货以及非经销商的不受管控往往会引发渠道混乱&#xff0c;这已然成为众多品牌难以回避的难题。那么&#xff0c;面对这些各异的渠道问题&#xff0c;究竟该如何施展出不同的治理妙招呢&#xff1f;难道仅有单一的处罚手…

priority_queue模拟

一、什么是priority_queue? priority_queue是C标准库中的一个容器适配器&#xff0c;用于实现优先队列&#xff08;priority queue&#xff09;的数据结构。优先队列是一种特殊的队列&#xff0c;其中的元素按照一定的优先级进行排序&#xff0c;每次取出的元素都是优先级最高…

OpenAI融资谈判 估值或超1000亿美元

&#x1f989; AI新闻 &#x1f680; OpenAI融资谈判 估值或超1000亿美元 摘要&#xff1a;OpenAI正在进行一轮融资谈判&#xff0c;预计估值将超过1000亿美元&#xff0c;主导投资方为Thrive Capital&#xff0c;将投资10亿美元。今年早些时候&#xff0c;OpenAI估值已超过8…

vue按钮弹框

在Vue中实现按钮点击后弹出对话框&#xff08;弹框&#xff09;的功能&#xff0c;通常可以使用一些Vue的UI组件库&#xff0c;如Element UI、Vuetify、BootstrapVue等&#xff0c;这些库提供了丰富的组件&#xff0c;包括对话框&#xff08;Dialog&#xff09;、模态框&#x…

一般中小型企业网站用哪种类型的SSL证书?

对于一般中小型企业网站&#xff0c;常用的SSL证书类型主要包括域名验证型SSL证书&#xff08;DV SSL证书&#xff09;和组织验证型SSL证书&#xff08;OV SSL证书&#xff09;。 域名验证型SSL证书&#xff08;DV SSL证书&#xff09; 特点&#xff1a; 验证简单&#xff1…

android 将新建的底部导航的demo,修改首页默认显示的字符串为helloworld。

1、先上个图&#xff0c;demo建好了以后&#xff0c;默认显示一个字符串&#xff1a; 2、这个demo的结构&#xff1a; activity_main.xml中用navGraph与其关联。 3、增加方法&#xff0c;给text赋值&#xff1a; package com.example.helloworld.ui.homeimport androidx.lifec…

三级_网络技术_53_应用题

一、 请根据下图所示网络结构回答下列问题。 1.设备1应选用__________网络设备。 2.若对整个网络实施保护&#xff0c;防火墙应加在图中位置1~3的__________位置上。 3.如果采用了入侵检测设备对进出网络的流量进行检测&#xff0c;并且探测器是在交换机1上通过端口镜像方式…