Netty入门——基于NIO实现机器客服案例

news2024/11/25 4:57:19

Netty简单案例

  • 前言
    • 环境准备
  • 前置知识
    • 网络传输的几种实现方式
      • BIO——同步阻塞IO
      • NIO——同步非阻塞IO
      • AIO——异步非阻塞IO
      • 适用范围
    • Netty
      • 简介
      • 特点
      • 核心组件
      • 使用场景
      • 运行简图
  • 案例
    • 简介
    • 关键代码
      • 客户端
      • 服务器端
  • 运行状况
  • 总结

前言

最近学完了Netty,在这里关于Netty中实现NIO做一些小总结,并附上一个小案例,最好读者有一点Netty的基础。这里附上git的地址,看一下netty的各种案例运行一下。github

环境准备

Maven 3.X、JDK15

前置知识

网络传输的几种实现方式

建议看一下之前的一篇文章《Java网络编程之阻塞式IO与非阻塞IO》中关于阻塞和非阻塞IO在Java中的使用。

BIO——同步阻塞IO

阻塞式的IO,服务器以轮询的方式,不断查看是否有新的连接。当然其性能可以使用线程池得到略微改善。

NIO——同步非阻塞IO

通过Selector以及Channel的组合使用,实现了多路复用,虽然实现了服务器的异步处理,但是客户端必须要在服务器响应到达才能发起下一个请求,即客户端需要某线程持续监听是否有响应发送回来。大体流程如下:
在这里插入图片描述

AIO——异步非阻塞IO

该模式不仅服务器实现了异步、客户端也实现了异步,能够在请求没有到达之前,继续向服务器发送数据。这里之后补充。

适用范围

  • NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,JDK1.4开始支持。

  • AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如HTTP服务器等,充分调用OS参与并发操作,JDK7开始支持

Netty

简介

Netty是高性能的水平扩展的分布式架构

特点

健壮、安全、高可用、高性能、更新快、易用

核心组件

  • channel:传入、传出的数据载体
  • 回调:给请求的响应
  • Feature:异步编程的的一个任务的开启
  • 事件和ChannelHandler:很多框架,前端后端都包含这类"发布者订阅者"设计思想

使用场景

  • 内部的RPC框架
    低延迟高吞吐量
  • 负载和性能测试
    用于负载和性能测试框架,可以通过Netty和Redis结合,来以最小的负载测试端到端的消息吞吐量。
  • 同步协议的异步客户端
    Netty为同步的协议创建异步的客户端,如Kafka、Memcached。使得在同步和异步之间来回切换,不需要更改任何上有代码。

消息推送、实时流量监控都可以使用Netty,有待大家自己探索。

运行简图

简而言之,服务器监听端口,就是新建一个ServerChannel,客户端建立连接connect也是建立一个连接,之后ServerChannel收到之后通过EventLoopGroup把该channel分配到EventLoop,如果该channel对应的任务已经存在于EventLoop中就直接执行,否则就要放入EventLoop中,等待执行。

  • EventLoopGroup
    EventLoopGroup好比线程池,EventLoop好比线程,Channel的pipeline了所有的Handler
    在这里插入图片描述

  • EventLoop的Task注册
    在这里插入图片描述

  • 连接建立示意图

    • 服务器
      在这里插入图片描述

    • 客户端
      在这里插入图片描述

案例

简介

客户通过一个终端输入查询的编号,如果问题在库中存在,人工客服返回相应的回答;若不存在,就会返回默认回复——”致电人工客服“;

如果是非法的输入,就直接模拟服务器宕机,所有的连接都断开。

注意 :这里后续作为入门案例展示,如果这里看不太懂,建议看一下git的quickstart部分。这里只展示关键代码

关键代码

客户端

    public void start() {
        Bootstrap bootstrap = new Bootstrap ( );
        // 引导类的配置,包括事件组,channel类型以及处理器
        bootstrap.group (group)
                .channel (NioSocketChannel.class)
                .handler (createInitializer ( ));

        ChannelFuture future = bootstrap.connect (new InetSocketAddress (8080));
        future.syncUninterruptibly ( );
        channel = future.channel ( );
    }
    // 注册所有的处理器
    private ChannelInitializer<Channel> createInitializer() {
        return new TerminalChatClientInitializer ( );
    }
    // 通过控制台不断地询问智能客服
    static void chat() throws IOException {
        while (true) {
            String input = getInputMsg ( );
            if (!input.equals (OVER)) {
                channel.writeAndFlush (Unpooled.copiedBuffer (input, StandardCharsets.UTF_8));
            } else {
                break;
            }
        }
    }
// 处理器代码
public class TerminalClientInHandler extends SimpleChannelInboundHandler<ByteBuf> {
	// 把响应打印出来
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        out.println (LocalDateTime.now ( ).format (DateTimeFormatter.ofPattern ("yyyy/MM/dd HH:mm:ss")));
        String resp = msg.toString (StandardCharsets.UTF_8);
        out.println (resp);
    }

	// 提示连接成功
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        out.println ("connect to server successfully : " + ctx.channel ( ).remoteAddress ( ));
    }
	// 提示连接关闭
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        out.println ("已经关闭连接");
    }
}

服务器端

    public void start() {
    	// 初始化服务器引导
        ServerBootstrap server = new ServerBootstrap ( );
        server.group (mainGroup)
                .channel (NioServerSocketChannel.class)
                .childHandler (createInitializer (channelGroup));
        // 监听8080端口
        ChannelFuture future = server.bind (8080);
        future.syncUninterruptibly ( );
        channel = future.channel ( );
    }

    private ChannelInitializer<Channel> createInitializer(ChannelGroup channelGroup) {
        return new TerminalChatServerInitializer (channelGroup);
    }

    public void destroy() {
        if (channel != null) {
            channel.close ( );
        }
        mainGroup.shutdownGracefully ( );
        subGroup.shutdownGracefully ( );
    }
	// 处理器关键代码	
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {		
    	// 打印收到的时间和消息
        String input = msg.toString (StandardCharsets.UTF_8);
        out.println (ctx.channel ().remoteAddress () + "\n" + input);
        try {
        	// 解析查询的Id,并且响应相应的答案
            int id = Integer.parseInt (input);
            String res = resMap.getOrDefault (id, "请致电人工:10086");
            ctx.writeAndFlush (Unpooled.copiedBuffer (res, StandardCharsets.UTF_8));
        } catch (Exception e) {
        	// 非法输入,模拟服务器宕机,向所有的客户端发送 服务器关闭消息
            group.writeAndFlush (Unpooled.copiedBuffer ("不明原因,服务器暂时关闭",StandardCharsets.UTF_8));
            group.close ();
        }
    }
	// 有新连接,打印客户机地址,并且加入到聊天群组
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        out.println ("client connected successfully : " + ctx.channel ( ).remoteAddress ( ));
        group.add (ctx.channel ( ));
    }
	// 某客户端下线,打印客户机地址,这里不需要手动从群组移除,Netty已经帮我们实现了该功能
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        out.println ("客户端: " + ctx.channel ( ).remoteAddress ( ).toString ( ) + "  结束");
    }

运行状况

在这里插入图片描述

总结

相对于Java原生Nio的消息读取以及消息处理来说,Netty的实现方式更加简单。

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

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

相关文章

【Shell 脚本速成】09、Shell 循环控制语句 for

目录 一、循环控制 break 语句 二、循环控制 continue 语句 三、循环控制 sleep 四、参数控制命令-shift 五、脚本退出命令 exit 总结 六、for 嵌套 6.1 for 嵌套 if 七、for 与数组 7.1 使用 for 循环遍历读出数组 7.2 使用 for 循环进行数组存值 一、循环控制 bre…

Zabbix6.0使用教程 (一)—zabbix新增功能介绍2

上一篇我们已经介绍了部分zabbix6.0的新增功能&#xff0c;这期我们将继续为家详细介绍下余下的zabbix6.0新增功能&#xff0c;大家可以往下看。 六、监控项 6.1 自动类型选择 监控项配置表单会自动建议匹配的信息类型&#xff0c;如果选定的监控项键值仅返回特定类型的数据…

迷宫逃离的问题-CoCube

ROS1云课→20迷宫不惑之A*大法&#xff08;一种虽古老但实用全局路径规划算法&#xff09; 将CoCube分别放入如下地图中的左侧&#xff0c;如何从右侧逃离&#xff1a; 需要算法&#xff1a;求解起点到终点的路径。 还需要什么&#xff1f; 参考&#xff1a; &#xff08;eng.…

目标检测算法——垃圾分类数据集汇总(附下载链接)

&#x1f384;&#x1f384;近期&#xff0c;小海带在空闲之余收集整理了一批垃圾分类数据集供大家参考。 整理不易&#xff0c;小伙伴们记得一键三连喔&#xff01;&#xff01;&#xff01;&#x1f388;&#x1f388; 目录 一、Kaggle 垃圾分类图片数据集 二、垃圾分类数据…

全国青少年软件编程等级考试Python标准解读(1_6级)

考核性质&#xff1a; 全国青少年软件编程等级考试标准&#xff08;Python语言&#xff09;由中国电子学会科普培训与应用推广中心和北京大学信息科学技术学院共同制定。由全国青少年电子信息科普创新联盟标准工作组开发&#xff0c;由中国电子学会普及工作委员会审核通过&…

央视主持人康辉再次出圈,一口气播出一个多小时不卡顿、零失误

说起中央电视台的主持人&#xff0c;曾经有好几个国字脸&#xff0c;不过随着时间的流逝&#xff0c;他们都消失在历史的长河里。如今的央视主持人队伍&#xff0c;康辉可以算得上天花板级别的人&#xff0c;他也因此俘获了一大批观众&#xff0c;成为最受欢迎的主持人。 专业科…

阿里P5的测试开发工程师,都有哪些要求?

【北京】高德 高级测试开发工程师&#xff08;面议&#xff09; 职位描述&#xff1a; 1、负责高德信息服务核心服务端系统测试和质量保障体系建设&#xff1b; 2、为复杂高德信息-本地生活系统设计并执行高质量的综合测试方案&#xff1b; 3、通过多种技术手段实现高度自…

数据库常见死锁原因及处理

目录前言什么是死锁死锁产生的四个必要条件1. 表锁死锁死锁场景解决方案建议2. 行锁死锁2.1 两个事务分别想拿到对方持有的锁&#xff0c;互相等待&#xff0c;于是产生死锁死锁场景解决方案2.2 共享锁转换为排他锁死锁场景解决方案3. INSERT ... ON DUPLICATE KEY UPDATE产生d…

[附源码]Python计算机毕业设计Django疫情防控平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Watch事件介绍_java培训

Watch事件 Java培训课程 Watch事件 一次触发 当数据有了变化时zkserver向客户端发送一个watch,它是一次性的动作&#xff0c;即触发一次就不再有效&#xff0c;类似一次性纸杯。 只监控一次。如果想继续Watch的话&#xff0c;需要客户端重新设置Watcher。因此如果你得到一个w…

【Android Studio程序开发】按钮触控---按钮控件Button

除了文本视图之外&#xff0c;按钮Button也是一种基础控件。因为Button是由TextView派生而来&#xff0c;所以文本视图 拥有的属性和方法&#xff0c;包括文本内容、文本大小、文本颜色等&#xff0c;按钮控件均能使用。不同的是&#xff0c;Button拥有默认的按钮背景&#xff…

采购管理系统有什么用,哪个好?

如今随着各行各业的采购组织管理理念的不断变换&#xff0c;利用信息化手段来管理企业采购行为已然成为一种趋势。 现代采购管理系统可以使采购组织规范采购工作的组织实施&#xff0c;建立有责任感的管理体系&#xff0c;从而提高企业经济效益和采购质量&#xff0c;增强企业…

Linux搭建 FTP服务器

Linux搭建 FTP服务器 vsftpd 是 very secure ftp daemon 的缩写&#xff0c;它是 Linux 上使用最受欢迎、使用最广泛的 FTP 服务器之一&#xff0c;它具有安全&#xff0c;速度快&#xff0c;稳定的特点&#xff0c;很多重要的 FTP 站点比如 ftp.gnu.org、ftp.freebsd.org 都是…

【JavaWeb开发-Servlet】day03-URL参数传递与MySQL数据库连接

目录 1、登录示例&#xff0c;谁用url传递参数 &#xff08;1&#xff09;创建一个Servlet类&#xff0c;名字叫做loginServlet &#xff08;2&#xff09;保留需要的部分 &#xff08;3&#xff09;删除多余代码 &#xff08;4&#xff09;编写loginServlet.class &#xff08…

ICV:2022年中国车载摄像头市场规模有望突破50亿美元大关

全球前沿科技咨询机构ICV近期发布了全球车载摄像头的市场分析报告。ICV在报告中指出&#xff0c;车载摄像头市场随着乘用车自动驾驶的发展呈现出快速增长的趋势&#xff0c;2022年中国市场在全球范围内仍保持“市场领跑者”的地位&#xff0c;并有望突破50亿美元市场规模的大关…

Win10如何安装JDK1.8,最快最详细教程

JDK全称为Java Development Kit&#xff0c;顾名思义是java开发工具包&#xff0c;是程序员使用java语言编写java程序所需的开发工具包。 JRE全称为Java Runtime Environment&#xff0c;顾名思义是java运行时的环境&#xff0c;包含了java虚拟机&#xff0c;java基础类库&…

ABAP-SAP-整合事务码,整合平台,运维工具箱

PROCESS BEFORE OUTPUT. MODULE status_0100. * PROCESS AFTER INPUT. MODULE user_command_0100. MODULE exit_command_0100 AT EXIT-COMMAND. 源码&#xff1a; **Project Name : SAP Implementation Project **Program Name : ZTOOL **Description : 运维工具箱 **Date/Aut…

比羊了个羊还火的ChatGPT,玩法全攻略讲解

大家好&#xff0c;我是洋子&#xff0c;昨天听闻了ChatGPT&#xff0c;真的非常强大&#xff0c;赶紧给大家安利一波 ChatGPT是一种由OpenAI开发的通用聊天机器人模型 该模型是基于GPT-3&#xff08;一种大型语言模型&#xff09;构建的&#xff0c;旨在提供与人类更加自然的…

Pig4Cloud之登陆验证(二)发放token

上一篇介绍了客户端认证处理&#xff0c;那是令牌颁发的前提。这篇开始&#xff0c;我们就来研究下令牌颁发。 令牌颁发 授权服务器提供令牌颁发接口&#xff08;/oauth2/token&#xff09;&#xff0c;由客户端发起请求&#xff0c;授权服务器生成访问令牌&#xff08;acces…

常见的并发线程面试题

常见的并发面试题 一.进程与线程的区别? 进程是操作系统进行资源分配的最小单元&#xff0c;线程是操作系统进行运算调度的最小单元。进程中包含了线程&#xff0c;线程属于进程。进程的内存和资源是该进程下的线程所共享的。 二.创建线程的方式以及区别? 继承Thread类&am…