Netty篇(入门编程)

目录

一、Hello World

1. 目标

2. 服务器端

3. 客户端

4. 流程梳理

💡 提示

5. 运行结果截图

二、Netty执行流程

1. 流程分析

2. 代码案例

2.1. 引入依赖

2.2. 服务端

服务端

服务端处理器

2.3. 客户端

客户端

客户端处理器

2.4. 代码截图


一、Hello World

1. 目标

开发一个简单的服务器端和客户端

  • 客户端向服务器端发送 hello, world
  • 服务器仅接收,不返回

加入依赖

<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.39.Final</version>
</dependency>

2. 服务器端

new ServerBootstrap().group(new NioEventLoopGroup()) // 1 .channel(NioServerSocketChannel.class) // 2.childHandler(new ChannelInitializer<NioSocketChannel>() { // 3protected void initChannel(NioSocketChannel ch) {ch.pipeline().addLast(new StringDecoder()); // 5ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() { // 6@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println(msg);}});}}).bind(8080); // 4

代码解读

  • 1 处,创建 NioEventLoopGroup,可以简单理解为 线程池 + Selector 后面会详细展开
  • 2 处,选择服务 Scoket 实现类,其中 NioServerSocketChannel 表示基于 NIO 的服务器端实现,其它实现

还有

  • 3 处,为啥方法叫 childHandler,是接下来添加的处理器都是给 SocketChannel 用的,而不是给

ServerSocketChannel。

ChannelInitializer 处理器(仅执行一次),它的作用是待客户端 SocketChannel 建立连接后,执行

initChannel 以便添加更多的处理器

  • 4 处,ServerSocketChannel 绑定的监听端口
  • 5 处,SocketChannel 的处理器,解码 ByteBuf => String
  • 6 处,SocketChannel 的业务处理器,使用上一个处理器的处理结果

3. 客户端

new Bootstrap().group(new NioEventLoopGroup()) // 1.channel(NioSocketChannel.class) // 2.handler(new ChannelInitializer<Channel>() { // 3@Overrideprotected void initChannel(Channel ch) {ch.pipeline().addLast(new StringEncoder()); // 8}}).connect("127.0.0.1", 8080) // 4.sync() // 5.channel() // 6.writeAndFlush(new Date() + ": hello world!"); // 7

代码解读

  • 1 处,创建 NioEventLoopGroup,同 Server
  • 2 处,选择客户 Socket 实现类,NioSocketChannel 表示基于 NIO 的客户端实现,其它实现还有

  • 3 处,添加 SocketChannel 的处理器,ChannelInitializer 处理器(仅执行一次),它的作用是待客户端

SocketChannel 建立连接后,执行 initChannel 以便添加更多的处理器

  • 4 处,指定要连接的服务器和端口
  • 5 处,Netty 中很多方法都是异步的,如 connect,这时需要使用 sync 方法等待 connect 建立连接完毕
  • 6 处,获取 channel 对象,它即为通道抽象,可以进行数据读写操作
  • 7 处,写入消息并清空缓冲区
  • 8 处,消息会经过通道 handler 处理,这里是将 String => ByteBuf 发出
  • 数据经过网络传输,到达服务器端,服务器端 5 和 6 处的 handler 先后被触发,走完一个流程

4. 流程梳理

💡 提示

一开始需要树立正确的观念

  • 把 channel 理解为数据的通道
  • 把 msg 理解为流动的数据,最开始输入是 ByteBuf,但经过 pipeline 的加工,会变成其它类型对象,最后

输出又变成 ByteBuf

  • 把 handler 理解为数据的处理工序
    • 工序有多道,合在一起就是 pipeline,pipeline 负责发布事件(读、读取完成...)传播给每个

handler, handler 对自己感兴趣的事件进行处理(重写了相应事件处理方法)

    • handler 分 Inbound 和 Outbound 两类
  • 把 EeventLoop 理解为处理数据的工人
    • 工人可以管理多个 channel 的 io 操作,并且一旦工人负责了某个 channel,就要负责到底(绑定)
    • 工人既可以执行 io 操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个 channel

的待处理任务,任务分为普通任务、定时任务

    • 工人按照 pipeline 顺序,依次按照 handler 的规划(代码)处理数据,可以为每道工序指定不同的工

5. 运行结果截图

二、Netty执行流程

1. 流程分析

  • Netty 抽象出两组线程池BossGroup专门负责接收客户端的连接, WorkerGroup专门负责网络的读写
  • BossGroup和WorkerGroup类型都是NioEventLoopGroup
  • NioEventLoopGroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是

NioEventLoop

  • NioEventLoop表示一个不断循环的执行处理任务的线程,每个NioEventLoop都有一个 selector ,

用于监听绑定在其上的 socket 的网络通讯 用于监听绑定在其上的 socket 的网络通讯

  • NioEventLoopGroup可以有多个线程,即可以含有多个NioEventLoop
  • 每个BossNioEventLoop 循环执行的步骤有3步轮询 accept事件,处理 accept事件, 与client建立连

接 , 生成 NioSocketChannel ,并将其注册到某 个worker 的NIOEventLoop上的selector处理任务队

列的任务,即runAllTasks

  • 每个Worker NIOEventLoop循环执行的步骤

轮询 read, write 事件,处理 i/o 事件,即read , write事件,在对应 NioSocketChannel处理,处理

任务队列的任务 ,即runAllTasks

  • 每个Worker 的NIOEventLoop处理业务时,会使用 pipeline(管道), pipeline中包含了channel ,

即通过 pipeline可以获取到对应通道,  管道中维护了很多的处理器

2. 代码案例

2.1. 引入依赖

    <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.19.1</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.42.Final</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.1</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>

2.2. 服务端

服务端
public class NettyServer {public static void main(String[] args) {//创建bossgroupEventLoopGroup bossGroup = new NioEventLoopGroup();//创建workerGroupEventLoopGroup workerGroup = new NioEventLoopGroup();try {//创建服务器启动对象ServerBootstrap bootstrap = new ServerBootstrap();//设置启动的数学bootstrap.group(bossGroup, workerGroup)//设置老板组合工作组.channel(NioServerSocketChannel.class)//设置通道类型.option(ChannelOption.SO_BACKLOG, 128)//设置线程队列的连接数.childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态//设置工作组的通道初始化,设置处理器的管道线.childHandler(new ChannelInitializer<SocketChannel>() {//初始化通道的方法protected void initChannel(SocketChannel channel) throws Exception {System.out.println("客户端 socketChannel 初始化" + channel);//处理器管道线中添加处理器channel.pipeline().addLast(new NettyServerHandler());}});System.out.println("服务器启动...");//绑定服务端口,返回异步通道返回对象ChannelFuture channelFuture = bootstrap.bind(6668).sync();//添加监听channelFuture.addListener(new ChannelFutureListener() {//监听操作完成public void operationComplete(ChannelFuture channelFuture) throws Exception {if (channelFuture.isSuccess()) {System.out.println("监听端口6668成功");} else {System.out.println("监听端口6668失败");}}});//设置异步通道关闭事件channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
服务端处理器
public class NettyServerHandler extends ChannelInboundHandlerAdapter{/**读事件,客户端发送数据会触发该方法1. ChannelHandlerContext ctx:上下文对象, 含有 管道pipeline , 通道channel, 地址2. Object msg: 就是客户端发送的数据 默认Object*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {Channel channel = ctx.channel();System.out.println("服务器读取线程 "+Thread.currentThread().getName()+" channel="+channel);System.out.println("server ctx="+ctx);ByteBuf buf = (ByteBuf) msg;System.out.println("客户端发送消息是:"+buf.toString(CharsetUtil.UTF_8));System.out.println("客户端地址:"+channel.remoteAddress());}/**读完毕触发*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {//写并且清缓冲区,一般讲,我们对这个发送的数据进行编码ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端", CharsetUtil.UTF_8));}/*处理异常, 一般是需要关闭通道*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}

2.3. 客户端

客户端
public class NettyClient {public static void main(String[] args) {//创建事件循环组EventLoopGroup group = new NioEventLoopGroup();try {//重建客户端启动类Bootstrap bootstrap = new Bootstrap();bootstrap.group(group)//设置循环组.channel(NioSocketChannel.class)//设置通道//设置通道初始化.handler(new ChannelInitializer<SocketChannel>() {//初始化通道protected void initChannel(SocketChannel channel) throws Exception {//设置管道线上的处理器channel.pipeline().addLast(new NettyClientHandler());}});System.out.println("客户端 ok");//请求连接,返回异步结果对象ChannelFuture future = bootstrap.connect("127.0.0.1", 6668).sync();//设置异步通道关闭事件future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();}finally {group.shutdownGracefully();}}
}
客户端处理器
public class NettyClientHandler extends ChannelInboundHandlerAdapter {/*通道就绪就会触发该方法*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client:" +ctx);ctx.writeAndFlush(Unpooled.copiedBuffer("hello server", CharsetUtil.UTF_8));}/*通道内有读取事件时候触发*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;System.out.println("服务器回复的消息:"+buf.toString(CharsetUtil.UTF_8));System.out.println("服务器地址:"+ctx.channel().remoteAddress());}/*异常*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

2.4. 代码截图

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

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

相关文章

从0开始学习机器学习--Day14--如何优化神经网络的代价函数

在上一篇文章中&#xff0c;解析了神经网络处理分类问题的过程&#xff0c;类似的&#xff0c;在处理多元分类问题时&#xff0c;神经网络会按照类型分成多个输出层的神经元来表示&#xff0c;如下&#xff1a; 处理4个分类问题时的神经网络 我们可以看到&#xff0c;相较于之…

除草机器人算法以及技术详解!

算法详解 图像识别与目标检测算法 Yolo算法&#xff1a;这是目标检测领域的一种常用算法&#xff0c;通过卷积神经网络对输入图像进行处理&#xff0c;将图像划分为多个网格&#xff0c;每个网格生成预测框&#xff0c;并通过非极大值抑制&#xff08;NMS&#xff09;筛选出最…

Android MavenCentral 仓库更新问题

MavenCentral 仓库更新问题 前言正文一、Maven central repository的账户迁移二、获取加密账户信息三、问题和解决方式① 问题1② 解决1③ 问题2④ 解决2 前言 在去年的3、4月份的时候我发布了一个开源库EasyView&#xff0c;在MavenCentral上&#xff0c;可以说当时发布的时候…

腾讯为什么支持开源?

今天看到一条新闻&#xff0c;感觉腾讯在 AI 大模型方面确实挺厉害的&#xff0c;符合它低调务实的风格&#xff0c;在不知不觉中一天竟然开源了两个核心的&#xff0c;重要的 AI 大模型。 据新闻报道&#xff0c;11月 5 日&#xff0c;腾讯混元宣布最新的 MoE 模型“混元 Larg…

学习了,踩到一个坑!

前言 踩坑了啊&#xff0c;最近踩了一个 lombok 的坑&#xff0c;有点意思&#xff0c;给你分享一波。 我之前写过一个公共的服务接口&#xff0c;这个接口已经有好几个系统对接并稳定运行了很长一段时间了&#xff0c;长到这个接口都已经交接给别的同事一年多了。 因为是基…

『Django』APIView基于类的用法

点赞 关注 收藏 学会了 本文简介 上一篇文章介绍了如何使用APIView创建各种请求方法&#xff0c;介绍的是通过函数的方式写接口。 本文要介绍 Django 提供的基于类&#xff08;Class&#xff09;来实现的 APIView 用法&#xff0c;代码写起来更简单。 APIView基于类的基…

CentOS系统查看CPU、内存、操作系统等信息

Linux系统提供了一系列命令可以用来查看系统硬件信息&#xff0c;如CPU的物理个数、核数、逻辑CPU数量、内存信息和操作系统版本。 查看物理CPU、核数和逻辑CPU 在多核、多线程的系统中&#xff0c;了解物理CPU个数、每个物理CPU的核数和逻辑CPU个数至关重要。超线程技术进一步…

DNS配置

1.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 2.配置从DNS服务器&#xff0c;对主dns服务器进行数据备份。 options {listen-on port 53 { 192.168.111.130; };directory "/var/named";allow-query { any;};zone "openlab.com&qu…

【WebRTC】WebRTC的简单使用

目录 1.下载2.官网上的使用3.本地的使用 参考&#xff1a; 【webRTC】一、windows编译webrtc Windows下WebRTC编译 1.下载 下载时需要注意更新python的版本和网络连接&#xff0c;可以先试试ping google。比较关键的步骤是 cd webrtc-checkout set https_proxy127.0.0.1:123…

使用axois自定义基础路径,自动拼接前端服务器地址怎么办

请求路径&#xff1a; http://localhost:5173/http://pcapi-xiaotuxian-front-devtest.itheima.net/home/category/head 很明显多拼接了路径地址 查看基础路径文件发现&#xff1a; //axios基础封装 import axios from axiosconst httpInstance axios.create({baseURL: /h…

第J5周:DenseNet+SE-Net实战

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 任务&#xff1a; ●1. 在DenseNet系列算法中插入SE-Net通道注意力机制&#xff0c;并完成猴痘病识别 ●2. 改进思路是否可以迁移到其他地方呢 ●3. 测试集acc…

力扣最热一百题——杨辉三角

目录 题目链接&#xff1a;118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 题目描述 示例 提示: 解法一&#xff1a;利用特性构建杨辉三角 1. 结果存储结构&#xff1a; 2. 初始化和循环遍历每一层&#xff1a; 3. 构建每一层&#xff1a; 4. 填充中间的元素&…

道品科技智慧农业中的自动气象检测站

随着科技的进步&#xff0c;智慧农业已经成为现代农业发展的重要方向。农业自动气象检测站作为智慧农业的一个关键组成部分&#xff0c;发挥着不可或缺的作用。本文将从工作原理、功能特点、应用场景以及主要作用等方面对农业自动气象检测站进行深入探讨。 ## 一、工作原理 农…

Android——多线程、线程通信、handler机制

Android——多线程、线程通信、handler机制 模拟网络请求&#xff0c;会阻塞主线程 private String getStringForNet() {StringBuilder stringBuilder new StringBuilder();for (int i 0; i < 100; i) {stringBuilder.append("字符串" i);}try {Thread.sleep(…

练习LabVIEW第三十三题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第三十三题&#xff1a; 用labview编写一个判断素数的程序 开始编写&#xff1a; LabVIEW判断素数&#xff0c;首先要搞…

我要精通前端-布局方式理解总结

一、浮动 1、传统网页布局的三种方式 ​CSS 提供了三种传统布局方式(简单说,就是盒子如何进行排列顺序)&#xff1a; 1.普通流&#xff08;标准流&#xff09; 2.浮动 3.定位 这三种布局方式都是用来摆放盒子的&#xff0c;盒子摆放到合适位置&#xff0c;布局自然就完成了…

C-DTL698电表 转 IEC61850 协议项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 准备工作 4 配置VFBOX网关 5 用IEC61850协议转发数据 6 网关使用多个逻辑设备和逻辑节点的方法 7 其他说明 8 案例总结 1 案例说明 设置网关采集DLT698电表数据数据把采集的数据转成IEC61850协议转发给其他系统。 2 VFBOX网关…

斗破QT编程入门系列之二:GUI应用程序设计基础:UI文件(四星斗师)

斗破Qt目录&#xff1a; 斗破Qt编程入门系列之前言&#xff1a;认识Qt&#xff1a;Qt的获取与安装&#xff08;四星斗师&#xff09; 斗破QT编程入门系列之一&#xff1a;认识Qt&#xff1a;初步使用&#xff08;四星斗师&#xff09; 斗破QT编程入门系列之二&#xff1a;认识…

机器学习4_支持向量机_核函数——MOOC

核函数的定义 引入了映射 后 最小化&#xff1a; 或 限制条件&#xff1a; &#xff08;1&#xff09; &#xff08;2&#xff09; 具体研究 引入 核函数&#xff08;Kernel Function&#xff09; Vladimir Naumovich Vapnik 指出&#xff0c;可以不用知道 的具体…

论文《基于卷积神经网络的手术机器人控制系统设计》文献阅读分析报告

论文报告&#xff1a;基于卷积神经网络的手术机器人控制系统设计 摘要 本研究针对传统手术机器人控制系统精准度不足的问题&#xff0c;提出了一种基于卷积神经网络的手术机器人控制系统设计。研究设计了控制系统的总体结构&#xff0c;并选用PCI插槽上直接内插CAN适配卡作为上…