Netty学习——实战篇3 BIO与NIO零拷贝 和 Netty入门实战

1 BIO拷贝

        BIOServer.java

public class BIOServer {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(8000);
        while(true){
            Socket socket = serverSocket.accept();
            DataInputStream inputStream = new DataInputStream(socket.getInputStream());
            try {
                byte[] bytes = new byte[4096];
                while(true){
                    int read = inputStream.read(bytes, 0, bytes.length);
                    if(-1 == read){
                        break;
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

        BIOClient.java

        

public class BIOClient {
    public static void main(String[] args) throws Exception{
        Socket socket = new Socket("localhost", 8000);
        String fileName = "";
        InputStream inputStream = new FileInputStream(fileName);
        DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
        byte[] bytes = new byte[4096];
        long readCount;
        long total = 0L;
        long beginTime = System.currentTimeMillis();
        while((readCount = inputStream.read(bytes)) >= 0){
            total += readCount;
            outputStream.write(bytes);
        }
        System.out.println("发送总字节数:" + total + ",耗时:" + (System.currentTimeMillis() - beginTime));
        outputStream.close();
        socket.close();
        inputStream.close();
    }
}

2 NIO零拷贝

NIOServer.java

public class NIOServer {
    public static void main(String[] args) throws Exception{
        //1 创建InetSocketAddress,并设置端口号 8000
        InetSocketAddress inetSocketAddress = new InetSocketAddress(8000);

        //2 创建ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //3 创建ServerSocket
        ServerSocket serverSocket = serverSocketChannel.socket();
        //4 ServerSocket绑定address
        serverSocket.bind(inetSocketAddress);
        //5 创建Buffer
        ByteBuffer buffer = ByteBuffer.allocate(4096);
        //6 等待客户端连接
        while(true){
            SocketChannel socketChannel = serverSocketChannel.accept();
            int readCount = 0;
            //7 循环读取
            while( -1 != readCount ){
                try {
                    readCount = socketChannel.read(buffer);
                }catch (Exception ex){
                    break;
                    //ex.printStackTrace();
                }
                //8 复位
                buffer.rewind();
            }
        }




    }
}

NIOClient.java

public class NIOClient {
    public static void main(String[] args) throws Exception{
        //1 创建 SocketChannel
        SocketChannel socketChannel = SocketChannel.open();
        String fileName = "";
        //2 socketchannel 连接服务器
        socketChannel.connect(new InetSocketAddress("localhost",8000));
        //3 得到一个文件channel
        FileChannel fileChannel = new FileInputStream(fileName).getChannel();
        long beginTime = System.currentTimeMillis();
        //4 发送
        long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);
        System.out.println("发送总字节数是:" + transferCount + ",总耗时:" + (System.currentTimeMillis() - beginTime));
        //5 关闭通道
        fileChannel.close();
    }
}

3 Netty入门实战

3.1 NettyServer.java

@Slf4j
public class NettyServer {
    public static void main(String[] args) {
        //1 创建bossGroup和workerGroup
        /*
            说明:
                1、创建两个线程组 bossGroup和workerGroup
                2、bossGroup只处理连接请求,workerGroup负责处理客户端业务
                3、两个都是无限循环
                4、bossGroup和workerGroup含有的子线程个数,默认是CPU 核数 * 2
         */
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //2 创建服务端的启动对象,配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            //3 使用链式变成来进行设置
            bootstrap.group(bossGroup,workerGroup) //3.1 设置两个线程组
                    .channel(NioServerSocketChannel.class)  //3.2 使用NIOServerSocketChannel作为服务端的通道
                    .option(ChannelOption.SO_BACKLOG,128) //3.3 设置线程队列得到链接个数
                    .childOption(ChannelOption.SO_KEEPALIVE,true) //3.4 设置保持活动连接状态
                    .handler(new ChannelInitializer<SocketChannel>() {   //3.5 创建一个通道初始化对象(匿名对象)
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("客户socketchannel hashcode=" + ch.hashCode());
                            ch.pipeline().addLast(new MyNettyServerHandler());
                        }
                    });

            //4 绑定一个端口并且同步,生成一个ChannelFuture对象,启动服务器
            ChannelFuture channelFuture = bootstrap.bind(8000).sync();
            //5 为channelfuture注册监听器,监听关心的事件
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if(channelFuture.isSuccess()){
                        log.info("监听端口8000成功");
                    }else {
                        log.info("监听端口8000失败");
                    }
                }
            });
            //6 对关闭通道事件进行监听
            channelFuture.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭 bossGroup 和 workerGroup
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

3.2 MyNettyServerHandler.java

@Slf4j
public class MyNettyServerHandler extends ChannelInboundHandlerAdapter {
    //读取实际的数据
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("ctx:{}",ctx);
        log.info("channel:{}",ctx.channel());
        ByteBuf buf = (ByteBuf) msg;
        log.info("向客户端发送的信息是:{}", buf.toString(CharsetUtil.UTF_8));
        log.info("客户端地址是:{}",ctx.channel().remoteAddress());
    }

    //数据读取完毕,将数据写入缓存,并刷新
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~(>^ω^<)喵1",CharsetUtil.UTF_8));
    }

    //异常处理,一般是关闭通道
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.channel().close();
    }
}

3.3  NettyClient.java

@Slf4j
public class NettyClient {
    public static void main(String[] args) throws Exception{
        //1 创建一个事件循环组
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            //2 创建客户端启动对象
            Bootstrap bootstrap = new Bootstrap();
            //3 设置相关参数
            bootstrap.group(eventLoopGroup)  //3.1 设置线程组
                    .channel(SocketChannel.class) //3.2 设置客户端通道的实现类
                    .handler(new ChannelInitializer<SocketChannel>() {  //3.4 设置自定义handler
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new MyNettyClientHandler());
                        }

                    });
            log.info("客户端就绪");
            //4 启动客户端,连接服务器
            ChannelFuture channelFuture = bootstrap.connect("localhost", 8000);
            //5 监听 关闭通道事件
            channelFuture.channel().closeFuture().sync();
        }finally {
            //6 关闭线程组
            eventLoopGroup.shutdownGracefully();
        }
    }
}

3.4  MyNettyClientHandler.java

@Slf4j
public class MyNettyClientHandler extends ChannelInboundHandlerAdapter {

    //当通道就绪就会触发该方法
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端:{}",ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 服务端: (>^ω^<)喵", CharsetUtil.UTF_8));
    }

    //当通道有读取事件时,会触发该方法
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        log.info("服务器回复的信息是:{}",buf.toString(CharsetUtil.UTF_8));
    }

    //发生异常时会触发该方法,关闭通道
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
    }
}

        分别启动 NettyServer.java 和 NettyClient.java,运行结果如下图:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用美化方法设计嵌入的子窗体(三)

使用美化方法设计嵌入的子窗体 分析效果图的实现 效果图&#xff1a; 新建 Windows 窗体 新窗体命名&#xff1a;FrmAddProduct.cs修改窗体的 Text 属性&#xff1a;新增商品修改窗体的位置&#xff1a;StartPosition&#xff1a;CenterScreen窗体的无边框设计&#xff1a…

拼多多容器文件修改自动上传

拼多多开放平台php环境是官方的linux容器&#xff0c;不能自己搭建ftp上传文件&#xff0c;每每有文件更新都挺麻烦。 有些功能测试不想每次都打包全部代码上去重新发布一次程序生成新的容器&#xff0c;那样太过麻烦和效率低。 一开始搞了一个php的文件管理工具上去&#xf…

电压比较器LM339介绍和仿真

电压比较器LM339介绍和仿真 &#x1f4d1;LM339相关特性 工作电源电压范围宽&#xff0c;单电源、双电源均可工作&#xff0c;单电源&#xff1a; 2&#xff5e;36V&#xff0c;双电源&#xff1a;1&#xff5e;18V&#xff1b;消耗电流小&#xff0c; Icc1.3mA&#xff1b;输…

《Kubernets证书篇:基于Kylin V10+ARM架构CPU修改K8S 1.26.15版本证书时间限制》

一、背景 Kubernetes 默认的证书有效期只有1年&#xff0c;因此需要每年手动更新一次节点上面的证书&#xff0c;特别麻烦而且更新过程中可能会出现问题&#xff0c;因此我们要对 Kubernetes 的 SSL 证书有效期进行修改&#xff0c;这里将证书的时间限制修改为100年。 环境信息…

【日常记录】【JS】styled-components库的原理,模板字符串调用函数

文章目录 1、引言2、模板字符串调用函数3、实现 1、引言 在react 中&#xff0c;styled-components 是最流行的 css in js 模式的库 2、模板字符串调用函数 let stu {name: 呆呆狗,age: 30,address: 中国}let str fn你好${stu.name}今年${stu.age}岁,来自${stu.address}这样会…

MySql 安装,小白也可以学会成功安装的保姆级教程

MySql 安装 文章目录 MySql 安装1.Mysql下载1.1 访问下载链接1.2 选择合适版本1.3 下载安装包 2.MySql安装3.安装成功检测验证3.1 mysql自带控制台验证3.2 win系统控制台进入验证 4. mysql 配置path5. navicat 连接 mysql 1.Mysql下载 1.1 访问下载链接 MySQL Downloads 这里…

计算机网络----第十六天

OSPF基础 RIP的缺陷&#xff1a; 最大16跳不可达&#xff1b; 收敛速度慢&#xff1b; 协议会产生路由自环 每发一次路由更新&#xff0c;就将自己的全部路由信息发送出去&#xff1b; OSPF&#xff1a; 含义&#xff1a;ospf&#xff08;最短路径优先&#xff09;&…

【Github】一个用于Active Directory的自助密码更改工具

在众多企业的日常运营中&#xff0c;Active Directory&#xff08;AD&#xff09;扮演着核心角色&#xff0c;负责管理和维护员工账户。然而&#xff0c;密码重置作为IT支持团队的常规工作之一&#xff0c;往往既耗时又繁琐。虽然一些商业解决方案和通过Windows服务器上RDS服务…

航芯通用MCU技术常见问题 | F4专题

日常工作中&#xff0c;我们的销售或技术工程师经常会收到来自用户的问题&#xff0c;其中一些问题是比较常见的&#xff0c;所以为满足日常用户对航芯产品使用及服务的了解&#xff0c;航芯特此推出“通用MCU技术常见问题”专题&#xff0c;分为F0专题及F4专题&#xff0c;欢迎…

内网穿透是什么意思?快解析如何实现内网穿透

在家里或者公司&#xff0c;我们常常会使用路由器来连接网络&#xff0c;以便我们能够上网学习和工作&#xff0c;但有时候使用起来真的不方便。有的时候我们在外面&#xff0c;想访问家里或者公司内部的设备&#xff0c;就会碰到一个问题&#xff1a;我们无法直接通过公网IP访…

【LeetCode: 3117. 划分数组得到最小的值之和 + 动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【C语言】<结构体>C中的自定义类型之struct

&#xff1c;结构体&#xff1e; 1. 结构体类型的声明1.1 结构体回顾1.1.1 结构体的声明1.1.2 结构体变量的创建和初始化 1.2 结构体的特殊声明1.3 结构体的自引用 2. 结构体内存对齐2.1 对齐规则2.2 为什么存在内存对齐&#xff1f;2.3 修改默认对齐数 3. 结构体传参4. 结构体…

SD-WAN提升企业网络体验

在现代企业中&#xff0c;网络体验已成为提升工作效率与业务质量的关键因素。SD-WAN技术的出现&#xff0c;以其独特的优势&#xff0c;为企业提供了优化网络连接、加速数据传输、提升服务质量和应用访问体验&#xff0c;以及增强网络稳定性的解决方案。接下来&#xff0c;我们…

Vue3(四):Pinia

一、Pinia介绍 Pinia是一个专门为Vue.js设计的状态管理库&#xff0c;它提供了一种简单和直观的方式来管理应用程序的状态。在使用Pinia时&#xff0c;可以轻松地创建定义状态的存储&#xff0c;然后将其与Vue组件绑定&#xff0c;使它们能够使用该状态。和上一个博客提到的Vu…

外网如何访问内网数据库?

在当今信息时代&#xff0c;随着互联网的快速发展&#xff0c;很多企业和个人都面临着外网访问内网数据库的需求。外网访问内网数据库可以实现远程操作&#xff0c;方便用户在任何地点使用移动设备进行数据管理和查询。本文将介绍一种名为【天联】的组网产品&#xff0c;它是一…

Sublime Text下载,安装,安装插件管理器,下载汉化插件

SublimeTest官网 © Sublime Text中文网 下载安装 一路点击安装即可 安装插件管理器 管理器官网安装 - 包控制 (packagecontrol.io) 手动安装将3 位置点击网址下载 再打开SublimeTest 点击 选择第一个Browse Packages..... 将会跳转到文件夹中 进入上一个文件夹 在进入…

使用剧本批量部署rsync服务端实战

目录 1、实战部署 编写剧本 执行剧本测试&#xff01;&#xff01;&#xff01; 2、部署方式对比 1、实战部署 编写剧本 执行剧本测试&#xff01;&#xff01;&#xff01; 2、部署方式对比 ansible模块实战-部署rsync服务端-CSDN博客 ansible临时命令和playbook区别 …

UE5 C++ TimeLine 时间轴练习

一. Actor引入头文件 #include "Components/TimelineComponent.h" 声明CurveFloat 和 TimelineComponent UPROPERTY(EditAnywhere,BlueprintReadWrite,Category "MyCurve")UCurveFloat* MyCurveFloat;UPROPERTY(EditAnywhere, BlueprintReadWrite, Cate…

北漂程序员整理:2024年阿里云服务器租用优惠价格表

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

逻辑卷和磁盘配额

文章目录 一、逻辑卷二、磁盘配额 一、逻辑卷 为什么会出现技术&#xff1f; 分区的缺点&#xff1a; 没有备份功能无法扩容性能取决于硬盘本身 相关概念 LVM 是 Logical Volume Manager 的简称&#xff0c;译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。…