Spring架构篇--2.4 远程通信基础--Socket通信

news2024/10/7 18:22:52

前言:通信中我们常常建立socket 通过其tcp完成通信;

1 Socket 介绍:

所谓socket 通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过”套接字”向网络发出请求或者应答网络请求;socket是基于应用服务与TCP/IP通信之间的一个抽象,他将TCP/IP协议里面复杂的通信逻辑进行分装,对用户来说,只要通过一组简单的API就可以实现网络的连接;
在这里插入图片描述
服务端初始化ServerSocket,然后对指定的端口进行绑定,接着对端口及进行监听,通过调用accept方法阻塞,此时,如果客户端有一个socket连接到服务端,那么服务端通过监听和accept方法可以与客户端进行连接。服务端和客户端通过socket获得输入输出流进行数据传输;

2 Socket 客户端与服务端通信:

2.1 BIO 通信:
1)服务端:建立 ServerSocket 并监听端口,当有连接进入时,获取数据进行处理:

package com.gupaoedu.springcloud.example.demo.socketdemo.server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerSocketDemo {

    public static void main(String[] args) {
    	// 声明服务端 ServerSocket 
        ServerSocket serverSocket=  null;
        while (true){
        	// 不断轮训
            try {
            	// 监听 8080 端口
                serverSocket = new ServerSocket(8080);
                // 连接阻塞,直到有新的连接进入
                Socket socket = serverSocket.accept();
                System.out.println("socket.getPort() = " + socket.getPort());

                // 获取客户端信息-- io 阻塞阻塞
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String str = bufferedReader.readLine();
                System.out.println("收到客户端信息 : " + str+System.currentTimeMillis());
                // 写给客户端信息
                BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bufferedWriter.write("服务器端回复客户端信息\n");
                bufferedWriter.flush();
                bufferedReader.close();
                bufferedWriter.close(); 

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

2)客户端:建立Socket 连接:

package com.gupaoedu.springcloud.example.demo.socketdemo.client;

import java.io.*;
import java.net.Socket;

public class SocketClientDemo {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost",8080);
            // 写给客户端信息--io阻塞
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("客户端:客户端写入信息\n");
            bufferedWriter.flush();
			// 接收服务端信息--io阻塞
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String str = bufferedReader.readLine();
            System.out.println("收到服务器端信息 : " + str+System.currentTimeMillis());
            bufferedWriter.close();
            bufferedReader.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3)因为是阻塞式的io 当多个客户端都连接到服务端时,同一时刻服务端只能接收一个客户端的请求,其它客户端的请求是被阻塞的,显然服务端的这种处理效率是非常低下的;
既然是服务端io阻塞导致了,那么是否可以使用线程池,每次接入一个客户端,就可以为其分配一个线程进行处理,处理完毕线程归还到线程池中;
在这里插入图片描述
4)线程任务处理:
服务端:

package com.gupaoedu.springcloud.example.demo.socketdemo.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerSocketDemo {

    static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8080);
            while (true) {
                Socket socket = serverSocket.accept();// 连接阻塞
                System.out.println("socket.getPort() = " + socket.getPort());
                executorService.execute(new ServerTask(socket));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

线程任务处理:

package com.gupaoedu.springcloud.example.demo.socketdemo.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class ServerTask implements Runnable{
    private  Socket socket;

    public ServerTask(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            // 获取客户端信息 io阻塞
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String str = bufferedReader.readLine();
            System.out.println("收到客户端信息 : " + str + System.currentTimeMillis());
            // 写给客户端信息
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("服务器端回复客户端信息\n");
            bufferedWriter.flush();
            bufferedReader.close();
            bufferedWriter.close();
        } catch (Exception ex) {

        }
    }
}

此时服务端处理请求的性能,取决于线程池的大小,显然线程池不能一直增大;那么怎么才能进一步提高服务器处理性能,既然服务端因为io 阻塞导致了必须处理一个客户端后在去处理下一个客户端,那么是否能让这个io 不阻塞;

2.2 NIO 通信:非阻塞IO(NIO);使得连接不阻塞;输入输出流不阻塞:
1)服务端:

package com.gupaoedu.springcloud.example.demo.niosocket.server;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

public class NioServer {
    public static void main(String[] args) {
        // Channel / Buffer  / Selector
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);// 设置非阻塞
            serverSocketChannel.socket().bind(new InetSocketAddress(8080));
            while (true){
                // 监听客户端请求
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (null != socketChannel){// 因为非阻塞,所以当没有客户端连接是获取到的socket 为null
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 设置缓冲区大小为1kb
                    System.out.println("socket.getLocalAddress() = " + socketChannel.getLocalAddress());
                    socketChannel.read(byteBuffer);// 获取客户端信息并将数据读取到缓冲区,如果客户端io阻塞,此处服务端也会阻塞 
                    System.out.println("byteBuffer.array() = " +new String( byteBuffer.array()));

                    // 获取写出流
                    byteBuffer.flip();// 写入流反转
                    socketChannel.write(byteBuffer);
                }else{
                    Thread.sleep(1000);
                    // 1s 之后再次尝试去获得客户端请求
                    System.out.println("\"连接未就绪\" = " + "连接未就绪");
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }

    }
}

2)客户端:

package com.gupaoedu.springcloud.example.demo.niosocket.cliet;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;

public class NioClient {
    public static void main(String[] args) {
        try{
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress(8080));
            if (socketChannel.isConnectionPending()){
                // 如果连接还没有建立好那么先建立连接
                socketChannel.finishConnect();
            }
            // 建立缓冲区大小
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 向缓冲区写入数据
            byteBuffer.put("I am socketChannel client".getBytes(StandardCharsets.UTF_8));
            byteBuffer.flip();
            socketChannel.write(byteBuffer);

            // 获取服务端数据
            byteBuffer.clear();
            // 获取服务端数据
            int i = socketChannel.read(byteBuffer);
            if (i>0){
                System.out.println("客户端收取到服务端的信息byteBuffer.array() = " +new String( byteBuffer.array()));
            }else {
                System.out.println("\"没有收到服务端数据\" = " + "没有收到服务端数据");
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }


    }
}

3)实现了非阻塞的连接和非阻塞的IO ,显然并不是所有只要连接了服务端口的客户端就会立刻与服务端通信,这样就好造成cpu 资源的无端占用,那么我们怎么知道那些客户端和服务端已经将通信准备好了,可以直接进行通信;

select 模型:
在这里插入图片描述
4)多路复用体现在可以只用一个线程,将与服务端建立连接的所有管道进行管理,并且通过轮询/事件 可以知道那个通道已经完成就绪,可以进行io通信;
4.1)服务端:

package com.gupaoedu.springcloud.example.demo.selectorsocket.server;

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.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class SelectorNioServer {
    static Selector selector;

    public static void main(String[] args) {
        // Channel / Buffer  / Selector

        try {
            selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);// 设置非阻塞
            serverSocketChannel.socket().bind(new InetSocketAddress(8080));
            // 连接事件注册到多路复用
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                // 当有事件到达时会被唤醒,否则会一直进行阻塞
                selector.select();
                // 获取多个事件
                Set<SelectionKey> selectionKeySet = selector.selectedKeys();

                Iterator<SelectionKey> iterator = selectionKeySet.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    if (selectionKey.isAcceptable()) {
                        // 有客户端连接事件
                        handleAcceptEvent(selectionKey);

                    } else if (selectionKey.isReadable()) {
                        // 有客户端写事件--》服务端进行读取
                        handleReadEvent(selectionKey);
                    } else if (selectionKey.isWritable()) {
                        System.out.println("\"server write\" = " + "server write");
                    }
                    iterator.remove();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    /**
     * 客户端有写入事件
     *
     * @param selectionKey
     */
    private static void handleReadEvent(SelectionKey selectionKey) {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        try {
            socketChannel.read(byteBuffer);
            System.out.println("server receive byteBuffer.array() = " + new String(byteBuffer.array()));
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    /**
     * 有客户端连接事件
     *
     * @param selectionKey
     */
    private static void handleAcceptEvent(SelectionKey selectionKey) {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        try {
            SocketChannel socketChannel = serverSocketChannel.accept();
            // 设置非阻塞
            socketChannel.configureBlocking(false);
            // 服务端协会数据
            socketChannel.write(ByteBuffer.wrap("I am server".getBytes(StandardCharsets.UTF_8)));
            socketChannel.register(selector, SelectionKey.OP_READ);
//            socketChannel.register(selector,SelectionKey.OP_WRITE);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}

4.2)客户端:

package com.gupaoedu.springcloud.example.demo.selectorsocket.client;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class SelectorNioClient1 {
    static Selector selector;
    public static void main(String[] args) {
        try{
            selector = Selector.open();
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress(8080));
            // 连接事件注册到多路复用
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            while (true) {
                // 当有事件到达时会被唤醒,否则会一直进行阻塞
                selector.select();
                // 获取多个事件
                Set<SelectionKey> selectionKeySet = selector.selectedKeys();

                Iterator<SelectionKey> iterator = selectionKeySet.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    if (selectionKey.isConnectable()) {
                        // 客户端与服务端的连接可用
                        handleConnectEvent(selectionKey);

                    } else if (selectionKey.isReadable()) {
                        // 客户端读取事件
                        handleReadEvent(selectionKey);
                    } else if (selectionKey.isWritable()){
                        System.out.println("\"write\" = " + "write");
                    }
                    iterator.remove();
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }


    }

    private static void handleReadEvent(SelectionKey selectionKey) {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        try {
            socketChannel.read(byteBuffer);
            System.out.println("client receive byteBuffer.array() = " +new String( byteBuffer.array()));
        }catch (Exception ex){
            ex.printStackTrace();
        }

    }

    private static void handleConnectEvent(SelectionKey selectionKey) {
        try{
            SocketChannel socketChannel =  (SocketChannel)selectionKey.channel();
            if (socketChannel.isConnectionPending()){
                // 如果连接还没有建立好那么先建立连接
                socketChannel.finishConnect();
            }
            socketChannel.configureBlocking(false);
            socketChannel.write(ByteBuffer.wrap(" I am Client2".getBytes(StandardCharsets.UTF_8)));
            socketChannel.register(selector,SelectionKey.OP_READ);
        }catch (Exception ex){

        }
    }
}

2.3 AIO 通信:通过信号量回调的方式真正实现异步

服务端:

package org.lgx.bluegrass.bluegrasscoree.util.selectorsocket.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;

/**
 * @Description TODO
 * @Date 2023/2/17 17:19
 * @Author lgx
 * @Version 1.0
 */
public class AioServer {
    public static void main(String[] args) throws IOException {
        AsynchronousServerSocketChannel ssc = AsynchronousServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(8080));
        ssc.accept(null, new AcceptHandler(ssc));
        System.in.read();
    }

    private static void closeChannel(AsynchronousSocketChannel sc) {
        try {
            System.out.printf("[%s] %s close\n", Thread.currentThread().getName(), sc.getRemoteAddress());
            sc.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
        private final AsynchronousSocketChannel sc;

        public ReadHandler(AsynchronousSocketChannel sc) {
            this.sc = sc;
        }

        @Override
        public void completed(Integer result, ByteBuffer attachment) {
            try {
                if (result == -1) {
                    closeChannel(sc);
                    return;
                }
                System.out.printf("[%s] %s read\n", Thread.currentThread().getName(), sc.getRemoteAddress());
                attachment.flip();
                System.out.println(Charset.defaultCharset().decode(attachment));
                attachment.clear();
                // 处理完第一个 read 时,需要再次调用 read 方法来处理下一个 read 事件
                sc.read(attachment, attachment, this);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            closeChannel(sc);
            exc.printStackTrace();
        }
    }

    private static class WriteHandler implements CompletionHandler<Integer, ByteBuffer> {
        private final AsynchronousSocketChannel sc;

        private WriteHandler(AsynchronousSocketChannel sc) {
            this.sc = sc;
        }

        @Override
        public void completed(Integer result, ByteBuffer attachment) {
            // 如果作为附件的 buffer 还有内容,需要再次 write 写出剩余内容
            if (attachment.hasRemaining()) {
                sc.write(attachment);
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            exc.printStackTrace();
            closeChannel(sc);
        }
    }

    private static class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, Object> {
        private final AsynchronousServerSocketChannel ssc;

        public AcceptHandler(AsynchronousServerSocketChannel ssc) {
            this.ssc = ssc;
        }

        @Override
        public void completed(AsynchronousSocketChannel sc, Object attachment) {
            try {
                System.out.printf("[%s] %s connected\n", Thread.currentThread().getName(), sc.getRemoteAddress());
            } catch (IOException e) {
                e.printStackTrace();
            }
            ByteBuffer buffer = ByteBuffer.allocate(16);
            // 读事件由 ReadHandler 处理
            sc.read(buffer, buffer, new ReadHandler(sc));
            // 写事件由 WriteHandler 处理
            sc.write(Charset.defaultCharset().encode("server hello!"), ByteBuffer.allocate(16), new WriteHandler(sc));
            // 处理完第一个 accpet 时,需要再次调用 accept 方法来处理下一个 accept 事件
            ssc.accept(null, this);
        }

        @Override
        public void failed(Throwable exc, Object attachment) {
            exc.printStackTrace();
        }
    }
}


3 总结:
通过bio 建立的socket 连接,并发的效率取决于线程池线程的大小;通过nio 使用select 轮询的方式可以实现非阻塞,这样大大提供了效率;通过aio 信号量回调的方式,真正实现非阻塞;

参考:
1 Java socket详解;

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

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

相关文章

四色菊皇家大学-BCG U2T产品宣传活动

BCG U2T产品的宣传和介绍。 2023年2月16日&#xff0c;四色菊皇家大学艺术文化中心&#xff0c;高等教育、科学、研究和创新部长Dnuch Tantodtit博士主持了BCG U2T产品的市场推广项目。四色菊皇家大学校长Saksit Anganaphanayakorn博士&#xff0c;以及U2T项目的管理人员、教职…

Ubuntu16.04使用apache创建个人用户主页并添加口令认证

文章目录一.安装apache二、apache文件和目录简述2.1 网站数据目录2.2 Apache配置文件三、创建个人用户主页3.1 开启个人用户主页功能3.2 建立目录和首页面3.3 开启模块3.4 测试四、添加口令认证4.1 生成密码数据库4.2 修改配置文件一.安装apache 创建虚拟机&#xff0c;保持默…

代码随想录【Day21】| 530. 二叉搜索树的最小绝对差、501. 二叉搜索树中的众数、236. 二叉树的最近公共祖先

530. 二叉搜索树的最小绝对差 题目链接 题目描述&#xff1a; 给你一棵所有节点为非负值的二叉搜索树&#xff0c;请你计算树中任意两节点的差的绝对值的最小值。 示例&#xff1a; 提示&#xff1a;树中至少有 2 个节点。 难点&#xff1a; 解答错误&#xff01;仅考虑了…

2023年软件测试工程师怎样跳槽,才能越跳越值钱?

2023年就业难&#xff1f;可那个转行干软件测试的小哥哥才刚拿到2W薪资的offer&#xff0c;紧接着又跳槽去了大厂 作为软件测试工程师怎样跳槽才能越跳越值钱呢&#xff1f; 把控好跳槽频次 我们在编写简历的时候&#xff0c;总想尽可能展示出自己的技能&#xff0c;但是简历上…

【基础算法】数的范围

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…

尚医通 (二十一)预约下单

目录一、预约下单功能(一)1、需求2、搭建订单模块3、封装Feign调用获取就诊人接口4、封装Feign调用获取排班下单信息接口二、预约下单功能(二)1、实现生成订单接口三、预约下单功能(三)四、预约下单功能(四)1、生成订单后处理逻辑-封装短信接口2、生成订单后处理逻辑-更新排班数…

Allegro误删器件位号如何快速刷新回来操作指导

Allegro误删器件位号如何快速刷新回来操作指导 在用Allegro做PCB设计的时候,有时会因为误操作,把需要的丝印位号删除了,如果想把位号复原回来,可以把当前器件删除,再重新放置即可。 下面介绍在不删除器件的情况下也能快速刷新回来的方法 如下图 误操作前 误操作后,位号…

Vue3+Ts+Vite开发插件并发布到npm

依赖版本信息如下&#xff1a; "vue": "^3.2.45""typescript": "~4.7.4""vite": "^4.0.0""less": "^4.1.3""terser": "^5.16.4"npm: 8.1.0node: 16.13.0 目标&#xf…

Spring AOP(AOP概念、组成、Spring AOP实现及实现原理)

文章目录1. Spring AOP 是什么2. 为什么要用 AOP3. 怎么学 Spring AOP4. AOP 组成5. Spring AOP 实现5.1 添加 Spring AOP 框架支持5.2 定义切面和切点5.3 实现通知方法5.4 使⽤ AOP 统计 UserController 每个⽅法的执⾏时间 StopWatch5.4 切点表达式说明 AspectJ6. Spring AOP…

【SPSS】基础图形的绘制(条形图、折线图、饼图、箱图)详细操作过程

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Qt-FFmpeg开发-实现录屏功能(10)

#音视频/FFmpeg #Qt Qt-FFmpeg开发-实现录屏功能&#x1f4ac; 文章目录Qt-FFmpeg开发-实现录屏功能&#x1f4ac;1、概述&#x1f4a5;2、实现效果&#x1f4a8;3、FFmpeg录屏代码流程&#x1f441;️‍&#x1f5e8;️4、主要代码&#x1f919;5、完整源代码&#x1f90f;更…

Doris单机部署

文章目录1. 前言2. 安装3. 启动4. 使用1. 前言 Apache Doris 是一款现代 MPP (Massively Parallel Processing大规模并行处理) 的分布式 SQL 分析数据库&#xff0c;所谓分析数据库就是将其数据集分布在许多机器或节点上&#xff0c;以处理大量数据&#xff0c;采用 Apache 2.0…

几十亿工单表,查询优化案例

前言: 之前在某大型保险公司担任技术经理&#xff0c;负责优化话务系统模块&#xff0c;由于系统已经运行10年之久&#xff0c;尤其在话务系统中&#xff0c;沉积了几十亿的话务信息表&#xff0c;业务人员反馈&#xff0c;话务系统历史数据查询部分已经完全查询不动&#xff0…

Spring Cloud Nacos源码讲解(二)- Nacos客户端服务注册源码分析

Nacos客户端服务注册源码分析 服务注册信息 ​ 我们从Nacos-Client开始说起&#xff0c;那么说到客户端就涉及到服务注册&#xff0c;我们先了解一下Nacos客户端都会将什么信息传递给服务器&#xff0c;我们直接从Nacos Client项目的NamingTest说起 public class NamingTest…

less、sass、webpack(前端工程化)

目录 一、Less 1.配置less环境 1.先要安装node&#xff1a;在cmd中&#xff1a;node -v检查是否安装node 2.安装less :cnpm install -g less 3.检查less是否安装成功&#xff1a;lessc -v 4.安装成功后&#xff0c;在工作区创建xx.less文件 5.在控制台编译less,命令&…

Spring Cloud——流监控Dashboard

一、编写三个module 1. springcloud-consumer-hystrix-dashboard 1.导入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId><version>1.4.6.RELEASE</version>…

【服务器数据恢复】raid5磁盘阵列硬盘离线的数据恢复案例

服务器数据恢复环境&#xff1a; 某公司一台服务器组建了一组raid5磁盘阵列&#xff0c;作为共享存储池使用。该服务器存储数据库文件和普通文件。 服务器故障&检测&#xff1a; RAID5磁盘阵列的硬盘掉线导致服务器操作系统识别不到D分区。管理员重启了服务器&#xff0c;服…

如何发布新闻稿,包含编写新闻稿、发布渠道

发布新闻稿是一种重要的传播方式&#xff0c;它可以让公众了解你的新闻&#xff0c;并提高新闻的知名度和可信度。在这篇文章中&#xff0c;我将详细介绍如何发布新闻稿&#xff0c;包括选择发布渠道、编写新闻稿、发布新闻稿和推广新闻稿等方面的内容。1、选择发布渠道在发布新…

VirtualBox压缩VDI文件 VDI文件瘦身方法(cenos7)

virtualbox虚拟机运行久了之后就会发现&#xff0c;磁盘镜像vdi文件越来越大。即使你把虚拟机中的大文件删除&#xff0c;这个vdi文件占用的空间还是不变。也就是说动态扩展的vdi文件只会大&#xff0c;不会小。那么大的文件对于备份和分享都不是很方便&#xff0c;所以有必要的…

Arduino-抢答器

抢答器实验实验器件&#xff1a;■ 按键开关&#xff1a;4 个■ 红色LED灯&#xff1a;1 个■ 黄色LED灯&#xff1a;1 个■ 绿色LED灯&#xff1a;1 个■ 220欧电阻&#xff1a;7 个■ 面包板&#xff1a;1 个■ 多彩杜邦线&#xff1a;若干实验连线将代码上传到开发板。程序代…