SpringBoot 2.7 集成 Netty 4 模拟服务端与客户端通讯入门教程

news2024/10/3 2:24:44

文章目录

    • 1 摘要
    • 2 核心 Maven 依赖
    • 3 核心代码
      • 3.1 服务端事务处理器 (DemoNettyServerHandler)
      • 3.2 服务端连接类(InitNettyServer)
      • 3.3 客户端事务处理器(DemoNettyClientHandler)
      • 3.4 客户端连接类(DemoNettyClient)
    • 4 测试
      • 4.1 测试流程
      • 4.2 测试结果
      • 4.3 测试结论
    • 5 推荐参考资料
    • 6 Github 源码

1 摘要

Netty 作为一款 NIO 底层通讯框架,在高并发场景有着广泛的应用,众多消息中间件内部也是基于 Netty 进行开发。本文将介绍基于 SpringBoot 2.7 集成 Netty 来模拟服务端与客户端进行通讯。

2 核心 Maven 依赖

demo-netty-server/pom.xml
        <!-- Netty -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>${netty.version}</version>
        </dependency>

netty 版本:

<netty.version>4.1.96.Final</netty.version>

3 核心代码

3.1 服务端事务处理器 (DemoNettyServerHandler)

demo-netty-server/src/main/java/com/ljq/demo/springboot/netty/server/handler/DemoNettyServerHandler.java
package com.ljq.demo.springboot.netty.server.handler;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @Description: Netty 服务处理器
 * @Author: junqiang.lu
 * @Date: 2023/8/18
 */
@Slf4j
@Component
// 标记该类实例可以被多个 channel 共享
@ChannelHandler.Sharable
public class DemoNettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 每个传入的消息都会调用该方法
     *
     * @param ctx
     * @param msg
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf byteBuf = (ByteBuf) msg;
        byte[] body = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(body);
        log.info("服务端接收到数据:{}", new String(body));
        byte[] responseBytes = "hi,客户端,我是服务端".getBytes();
        ctx.writeAndFlush(Unpooled.wrappedBuffer(responseBytes));
    }

    /**
     * 在读取期间,有异常抛出时会调用
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 打印异常栈跟踪
        log.error("netty server error",cause);
        //关闭该channel
        ctx.close();
    }

}

3.2 服务端连接类(InitNettyServer)

demo-netty-server/src/main/java/com/ljq/demo/springboot/netty/server/init/InitNettyServer.java
package com.ljq.demo.springboot.netty.server.init;

import com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetSocketAddress;

/**
 * @Description: 初始化 netty 服务端
 * @Author: junqiang.lu
 * @Date: 2023/8/18
 */
@Slf4j
@Component
public class InitNettyServer implements ApplicationRunner {


    @Value("${netty.port:9120}")
    private Integer nettyPort;


    @Resource
    private DemoNettyServerHandler nettyServerHandler;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        this.start();
    }

    /**
     * 启动服务
     *
     * @throws InterruptedException
     */
    public void start() throws InterruptedException {
        // 连接管理线程池
        EventLoopGroup mainGroup = new NioEventLoopGroup(1);
        // 工作线程池
        EventLoopGroup workGroup = new NioEventLoopGroup(4);
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(mainGroup, workGroup)
                    // 指定 nio 通道
                    .channel(NioServerSocketChannel.class)
                    // 指定 socket 地址和端口
                    .localAddress(new InetSocketAddress(nettyPort))
                    // 添加子通道 handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                    .addLast(nettyServerHandler);
                        }
                    });
            // 异步绑定服务器,调用sync()方法阻塞等待直到绑定完成
            ChannelFuture channelFuture = bootstrap.bind().sync();
            log.info("---------- [init] netty server start ----------");
            // 获取Channel的CloseFuture,并且阻塞当前线程直到它完成
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 关闭 EventLoopGroup,释放资源
            mainGroup.shutdownGracefully().sync();
        }
    }


}

注意事项: 为什么要定义两个 EventLoopGroup ? 实际上这个 EventLoopGroup 相当于一个线程组,如果只定义一个,则这个线程组既负责服务端与客户端的连接管理,也负责服务端的事务处理,这就大大降低了服务端的吞吐量,定义两个 EventLoopGroup 可以极大地提高系统的并发性能。

3.3 客户端事务处理器(DemoNettyClientHandler)

demo-netty-server/src/main/java/com/ljq/demo/springboot/netty/server/handler/DemoNettyClientHandler.java
package com.ljq.demo.springboot.netty.server.handler;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @Description: netty 客户端处理器
 * @Author: junqiang.lu
 * @Date: 2023/8/18
 */
@Slf4j
@Component
// 标记该类实例可以被多个 channel 共享
@ChannelHandler.Sharable
public class DemoNettyClientHandler extends ChannelInboundHandlerAdapter {

    /**
     * 接收消息
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf= (ByteBuf)msg;
        byte[] body=new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(body);
        log.info("接收到来自服务端的消息:{}",new String(body));
        // 释放消息
        ReferenceCountUtil.release(msg);
    }

    /**
     * 和服务器建立连接时触发
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端连接到服务器!!!");
        // 向服务端发送上线消息
        byte[] bytes = "hi,服务端,我是客户端!".getBytes();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
        ctx.writeAndFlush(byteBuf);
    }

    /**
     * 有异常时触发
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("客户端异常", cause);
        super.exceptionCaught(ctx, cause);
    }
}

3.4 客户端连接类(DemoNettyClient)

demo-netty-server/src/main/java/com/ljq/demo/springboot/netty/server/client/DemoNettyClient.java
package com.ljq.demo.springboot.netty.server.client;

import com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * @Description: Netty 客户端
 * @Author: junqiang.lu
 * @Date: 2023/8/22
 */
@Slf4j
public class DemoNettyClient {

    private final String host;

    private final int port;

    private final EventLoopGroup mainGroup;

    private final Bootstrap bootstrap;

    private Channel channel;

    public DemoNettyClient(String host, int port) {
        this.host = host;
        this.port = port;
        this.mainGroup = new NioEventLoopGroup();
        this.bootstrap = new Bootstrap();

    }

    public Channel getChannel() {
        return this.channel;
    }

    /**
     * 创建连接
     */
    public void connect() throws InterruptedException {
        bootstrap.group(mainGroup)
                .channel(NioSocketChannel.class)
                .remoteAddress(new InetSocketAddress(host, port))
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new StringEncoder())
                                .addLast(new ByteArrayEncoder())
                                .addLast(new DemoNettyClientHandler());
                    }
                });
        ChannelFuture future = bootstrap.connect().sync();
        this.channel = future.channel();
    }

    /**
     * 发送消息
     *
     * @param message
     */
    public void sendMessage(String message) {
        log.info("客户端待发送消息:{}", message);
        Channel channel = this.getChannel();
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
        channel.writeAndFlush(byteBuf);
    }

    public void close() throws InterruptedException {
        log.info("关闭客户端");
        mainGroup.shutdownGracefully().sync();
    }


    public static void main(String[] args) throws InterruptedException {
        String serverHost = "127.0.0.1";
        int serverPort = 9120;
        String message = "ahahaha啊哈哈哈啊哈";
        DemoNettyClient nettyClient = new DemoNettyClient(serverHost, serverPort);
        nettyClient.connect();
        for (int i = 0; i < 10; i++) {
            nettyClient.sendMessage(message + i);
        }
        log.info("--------开始休眠 5 秒------------");
        Thread.sleep(5000L);
        for (int i = 0; i < 5; i++) {
            nettyClient.sendMessage(i + message);
            Thread.sleep(100L);
        }
        nettyClient.close();
    }

}

4 测试

4.1 测试流程

先启动 SpringBoot 应用程序,此时服务端已经启动完成

再执行客户端连接类(DemoNettyClient) 中的 main 方法

4.2 测试结果

客户端日志:

2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈0
2023-08-23 11:27:11 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 48| 客户端连接到服务器!!!
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈1
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈2
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈3
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈4
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈5
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈6
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈7
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈8
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:ahahaha啊哈哈哈啊哈9
2023-08-23 11:27:11 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 96| --------开始休眠 5 秒------------
2023-08-23 11:27:11 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 35| 接收到来自服务端的消息:hi,客户端,我是服务端
2023-08-23 11:27:16 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:0ahahaha啊哈哈哈啊哈
2023-08-23 11:27:16 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 35| 接收到来自服务端的消息:hi,客户端,我是服务端
2023-08-23 11:27:16 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:1ahahaha啊哈哈哈啊哈
2023-08-23 11:27:16 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 35| 接收到来自服务端的消息:hi,客户端,我是服务端
2023-08-23 11:27:16 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:2ahahaha啊哈哈哈啊哈
2023-08-23 11:27:16 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 35| 接收到来自服务端的消息:hi,客户端,我是服务端
2023-08-23 11:27:17 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:3ahahaha啊哈哈哈啊哈
2023-08-23 11:27:17 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 35| 接收到来自服务端的消息:hi,客户端,我是服务端
2023-08-23 11:27:17 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 74| 客户端待发送消息:4ahahaha啊哈哈哈啊哈
2023-08-23 11:27:17 | INFO  | nioEventLoopGroup-2-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyClientHandler 35| 接收到来自服务端的消息:hi,客户端,我是服务端
2023-08-23 11:27:17 | INFO  | main | com.ljq.demo.springboot.netty.server.client.DemoNettyClient 82| 关闭客户端
Disconnected from the target VM, address: '127.0.0.1:56274', transport: 'socket'

服务端日志:

2023-08-23 11:27:11 | INFO  | nioEventLoopGroup-3-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler 33| 服务端接收到数据:hi,服务端,我是客户端!ahahaha啊哈哈哈啊哈0ahahaha啊哈哈哈啊哈1ahahaha啊哈哈哈啊哈2ahahaha啊哈哈哈啊哈3ahahaha啊哈哈哈啊哈4ahahaha啊哈哈哈啊哈5ahahaha啊哈哈哈啊哈6ahahaha啊哈哈哈啊哈7ahahaha啊哈哈哈啊哈8ahahaha啊哈哈哈啊哈9
2023-08-23 11:27:16 | INFO  | nioEventLoopGroup-3-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler 33| 服务端接收到数据:0ahahaha啊哈哈哈啊哈
2023-08-23 11:27:16 | INFO  | nioEventLoopGroup-3-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler 33| 服务端接收到数据:1ahahaha啊哈哈哈啊哈
2023-08-23 11:27:16 | INFO  | nioEventLoopGroup-3-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler 33| 服务端接收到数据:2ahahaha啊哈哈哈啊哈
2023-08-23 11:27:17 | INFO  | nioEventLoopGroup-3-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler 33| 服务端接收到数据:3ahahaha啊哈哈哈啊哈
2023-08-23 11:27:17 | INFO  | nioEventLoopGroup-3-1 | com.ljq.demo.springboot.netty.server.handler.DemoNettyServerHandler 33| 服务端接收到数据:4ahahaha啊哈哈哈啊哈

4.3 测试结论

  • (1)从日志中可以看出客户端与服务端已经通讯成功
  • (2)在第一个客户端循环发送消息中,客户端发了10次,然而服务端一次性接收到了所有消息,并不是发送一次接收一次
  • (3)在第二个客户端循环发送消息过程中,客户端每间隔100毫秒发送一条消息,此时服务端是一条一条接收的

关于第(2)点,这是 Netty 通讯过程中的粘包问题,欲知如何解决,且听下回分解。

关于第(3)点,由于添加了时间间隔,Netty 会认为一条消息发送完成,因此就能发送一条接收一条。

5 推荐参考资料

[Netty入门] 最简单的Netty应用程序实例

Netty4:一个简单的消息传递的demo(分析和解析)

6 Github 源码

Gtihub 源码地址 : https://github.com/Flying9001/springBootDemo/tree/master/demo-netty-server

个人公众号:404Code,分享半个互联网人的技术与思考,感兴趣的可以关注.
404Code

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

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

相关文章

Datax、Datax-web 安装部署

Datax安装&#xff08;Windows&#xff09; 1、源码地址&#xff1a;GitHub - alibaba/DataX: DataX是阿里云DataWorks数据集成的开源版本。 2、下载安装包并解压&#xff08;安装前需有jdk、python开发环境&#xff09;&#xff1a;https://github.com/alibaba/DataX/archiv…

游戏开发服务器选型的横向对比

来源一个某乎的作者&#xff0c;貌似来自台湾 上篇介绍了go版本的游戏服务器&#xff0c;这篇介绍下其它语言版本&#xff1a; SkynetkbengineNoahGameFramePomeloPinusET使用的语言C/LuaCCNodejsTypeScriptC#概述云风前辈开源的框架mmo框架server一个快速的、可扩展的、分布…

【Prometheus】概述及部署

目录 Prometheus 概述 Prometheus 的生态组件 Prometheus 的工作模式 Prometheus 的工作流程 Prometheus 的局限性 部署 Prometheus Prometheust Server 端安装和相关配置 部署 Exporters 监控 MySQL 配置示例 监控 Nginx 配置示例 部署 Grafana 进行展示 部署 Pro…

Java如何调用接口API并返回数据(两种方法)

Java如何调用接口API并返回数据&#xff08;两种方法&#xff09; java处理请求接口后返回的json数据-直接处理json字符串 处理思路&#xff1a; 将返回的数据接收到一个String对象中&#xff08;有时候需要自己选择性的取舍接收&#xff09; 再将string转换为JSONObject对象 …

Shiro学习总结

第一章 入门概述 1.概念 shiro是一个Java安全框架&#xff0c;可以完成&#xff1a;认证、授权、加密、会话管理、与web集成、缓存… 2.优势 ● 易于使用&#xff0c;构建简单 ● 功能全面 ● 灵活&#xff0c;可以在任何应用程序环境中工作&#xff0c;并且不需要依赖它们…

log4框架

1.log4cplus基本元素 Layouts &#xff1a;控制输出消息的格式。 Appenders &#xff1a;输出位置。 Logger &#xff1a;日志对象。 Priorities &#xff1a;优先权&#xff0c;包括TRACE, DEBUG, INFO, WARNING, ERROR, FATAL。 2.log4cplus基本结构 3. 使用步骤&am…

2023年7月最新道路矢量数据(全国/分省/分城市)

2023年7月最新道路矢量数据&#xff08;全国/分省/分城市&#xff09; 道路数据是我们在各项研究中经常使用的数据&#xff01;道路数据虽然很常用&#xff0c;但是却基本没有能下载最近年份道路数据的网站&#xff0c;所以很多人不知道如何获到道路数据。 本次我们为大家推…

【80天学习完《深入理解计算机系统》】第九天 3.2 数据传送指令【mov】【栈和堆】【leaq】【一元操作】【二元操作】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

智慧充电桩物联网方案架构

智慧充电桩物联网采用“云-管-边-端”的边缘计算物联网架构&#xff0c;融合5G、AI、Wi-Fi 6等技术&#xff0c;实现充电基础设施由数字化向智能化演进。智慧充电桩物联网方案架构设计&#xff0c;如下图所示&#xff1a; 云端&#xff1a; 物联网平台具备广泛协议的南向接入…

.NET 最便捷的Log4Net日志记录器

最便捷的Log4Net使用方法 LOG4NET 配置日志记录器开始引用nuget LOG4NET 配置日志记录器 Apache log4net 库是一个帮助程序员将日志语句输出到各种的工具 的输出目标。log4net是优秀的Apachelog4j™框架的移植 Microsoft.NET 运行时。我们保持了与原始log4j相似的框架 同时利…

【javaweb】学习日记Day5 - 请求响应 分层解耦 IOC DI 三层架构

目录 一、请求响应 1、请求 &#xff08;1&#xff09;简单参数 ① GET请求 ② POST请求 ③ 假如形参与请求参数不一致 &#xff08;2&#xff09;实体参数 ① 简单实体对象 ② 复杂实体对象 &#xff08;3&#xff09;数组参数 &#xff08;4&#xff09;集合参数 …

研究生定向培养学徒对象及说明

研究生定向培养学徒开始招募啦&#xff0c;招募对象可以 1、免费学习 2、全真企业项目实战 3、拥有就业推荐机会 4、提供副业机会 研究生定向培养学徒报名时间&#xff1a; 2023年8月22日-2023年9月10日 研究生定向培养学徒招募对象&#xff1a; 1.毕业年度研究…

如何在地平线J5上部署RTA-VRTE v2.2应用程序

在地平线J5上部署RTA-VRTE v2.2应用程序流程图: 虽然在J5上使用ifconfig 命令看不到can0和can1被启动 登陆系统后ifconfig -a仍然能看到can0和can1。

Python(八十四)字符串的切片操作

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

Linux TCP协议——三次握手,四次挥手

一、TCP协议介绍 TCP协议是可靠的、面向连接的、基于字节流的传输层通信协议。 TCP的头部结构&#xff1a; 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;&#xff08;tcp是传输层的协议&#xff0c;端与端之间的数据传输&#xff0c;在TCP和UDP协议当中不会体现出I…

基于paddleocr的文档识别

1、版面分析 使用轻量模型PP-PicoDet检测模型实现版面各种类别的检测。 数据集&#xff1a; 英文&#xff1a;publaynet数据集的训练集合中包含35万张图像&#xff0c;验证集合中包含1.1万张图像。总共包含5个类别。 中文&#xff1a;CDLA据集的训练集合中包含5000张图像&a…

Vue3:通过路由写多个页面,通过不同的路径可以进入不同的页面

前言 Vue3&#xff1a;想通过路由写2个页面&#xff0c;不同的路径可以进入不同的页面 实现步骤 1、创建Vue3项目 通过脚手架创建一个Vue3的项目&#xff0c;然后在此基础上对文件进行增删改&#xff0c;修改成自己需要的项目框架 2、views文件夹 对应 页面文件 如果需要…

网络编程——网络基础知识

目录 一、网络历史两个重要名词1.1 阿帕网1.2 TCP/IP协议 二、局域网和广域网三、IP地址3.1 基本概念3.2 划分(IPV4)3.3 特殊IP地址3.4 子网掩码3.5 重新组网 四、网络模型4.1 网络的体系结构&#xff1a;4.2 OSI与TCP/IP模型4.2.1 OSI模型4.2.2 TCP/IP模型4.2.3 OSI和TCP/IP模…

C++,类的特殊函数练习

设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream> using namespace std;cla…

OpenAI的Superalignment策略:计算为王

卷友们好&#xff0c;我是rumor。 对于怎么实现AGI这个玄学的目标&#xff0c;感觉大家都是差不多的状态&#xff1a;咱也不知道怎么做&#xff0c;但就是觉得现在的LLM技术还远远不够。 所以之前看到OpenAI说要用模型去做对齐研究[1]&#xff0c;以及最近发话要4年内做出Super…