李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
03.Netty入门Demo
Leefs
2022-06-07 PM
1137℃
0条
[TOC] ### 一、目标 开发一个简单的服务器端和客户端 * 客户端向服务器端发送 hello, world * 服务器仅接收,不返回 **引入依赖** ```xml
io.netty
netty-all
4.1.39.Final
``` ### 二、实现代码 #### 2.1 服务器端 ```java new ServerBootstrap() .group(new NioEventLoopGroup()) // 1 .channel(NioServerSocketChannel.class) // 2 .childHandler(new ChannelInitializer
() { // 3 protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); // 5 ch.pipeline().addLast(new SimpleChannelInboundHandler
() { // 6 @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { System.out.println(msg); } }); } }) .bind(8080); // 4 ``` **说明** * 1 处,创建 NioEventLoopGroup,可以简单理解为 `线程池 + Selector` 后面会详细展开 * 2 处,选择服务 Scoket 实现类,其中 NioServerSocketChannel 表示基于 NIO 的服务器端实现,其它实现还有 ![03.Netty入门Demo01.png](https://lilinchao.com/usr/uploads/2022/06/358424277.png) + 3 处,为啥方法叫 childHandler,是接下来添加的处理器都是给 SocketChannel 用的,而不是给 ServerSocketChannel。ChannelInitializer 处理器(仅执行一次),它的作用是待客户端 SocketChannel 建立连接后,执行 initChannel 以便添加更多的处理器 + 4 处,ServerSocketChannel 绑定的监听端口 + 5 处,SocketChannel 的处理器,解码 ByteBuf => String + 6 处,SocketChannel 的业务处理器,使用上一个处理器的处理结果 #### 2.2 客户端 ```java new Bootstrap() .group(new NioEventLoopGroup()) // 1 .channel(NioSocketChannel.class) // 2 .handler(new ChannelInitializer
() { // 3 @Override protected 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 的客户端实现,其它实现还有 ![03.Netty入门Demo02.png](https://lilinchao.com/usr/uploads/2022/06/4113813368.png) + 3 处,添加 SocketChannel 的处理器,ChannelInitializer 处理器(仅执行一次),它的作用是待客户端 SocketChannel 建立连接后,执行 initChannel 以便添加更多的处理器 + 4 处,指定要连接的服务器和端口 + 5 处,Netty 中很多方法都是异步的,如 connect,这时需要使用 sync 方法等待 connect 建立连接完毕 + 6 处,获取 channel 对象,它即为通道抽象,可以进行数据读写操作 + 7 处,写入消息并清空缓冲区 + 8 处,消息会经过通道 handler 处理,这里是将 String => ByteBuf 发出 + 数据经过网络传输,到达服务器端,服务器端 5 和 6 处的 handler 先后被触发,走完一个流程 #### 2.3 流程梳理 ![](http://114.255.136.222:9202/server/index.php?s=/api/attachment/visitFile/sign/62c855b0af1bd95fd4f24d28e8f61f17) **提示** > 一开始需要树立正确的观念 > > * 把 channel 理解为数据的通道 > * 把 msg 理解为流动的数据,最开始输入是 ByteBuf,但经过 pipeline 的加工,会变成其它类型对象,最后输出又变成 ByteBuf > * 把 handler 理解为数据的处理工序 > * 工序有多道,合在一起就是 pipeline,pipeline 负责发布事件(读、读取完成...)传播给每个 handler, handler 对自己感兴趣的事件进行处理(重写了相应事件处理方法) > * handler 分 Inbound 和 Outbound 两类 > * 把 eventLoop 理解为处理数据的工人 > * 工人可以管理多个 channel 的 io 操作,并且一旦工人负责了某个 channel,就要负责到底(绑定) > * 工人既可以执行 io 操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个 channel 的待处理任务,任务分为普通任务、定时任务 > * 工人按照 pipeline 顺序,依次按照 handler 的规划(代码)处理数据,可以为每道工序指定不同的工人 ### 三、完整代码 + **服务端** ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.logging.LoggingHandler; /** * @author lilinchao * @date 2022/6/6 * @description Netty 服务端 **/ public class HelloServer { public static void main(String[] args) { //1.启动器,负责组装netty组件,启动服务器 new ServerBootstrap() //2.添加了一个group组,创建一个EventLoopGroup 包括 BossEventLoop和 WorkerEventLoop(selector thread) .group(new NioEventLoopGroup()) //3.选择服务器的 ServerSocketChannel 实现 //指定Channel的类型:EpollServerSocketChannel,KQueueServerSocketChannel,NioServerSocketChannel .channel(NioServerSocketChannel.class)// Netty对原生的ServerSocketChannel做了封装 //4.添加处理器(过滤器) //boss负责处理连接 worker(child) 负责处理读写,决定了 worker(child) 能执行哪些操作(handler) .childHandler( //5.channel 代表和客户端进行数据读写的通道 Initializer 初始化,初始channel通道 // 本身也是一个handler,负责添加别的handler 在创建时只是添加了初始化器,并未执行初始化器的内容, // 也就是initChannel方法,创建了连接后才执行的初始化器的初始化方法 new ChannelInitializer
() { // 具体添加了哪些handler就在initChannel中添加 @Override //在连接建立后被初始化 protected void initChannel(NioSocketChannel ch) throws Exception { //6.添加具体handler为nioSocketChannel上加处理器类 // 解码 ,客户端发过来的都是ByteBuf , 要将ByteBuf转换为字符串 // 在连接建立后的初始化时会执行addLast()方法,但是不会执行处理器,处理器是在收发数据时才执行 ch.pipeline().addLast(new LoggingHandler()); ch.pipeline().addLast(new StringDecoder()); // 将 ByteBuf 转换为字符串 ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){ // 自定义 handler /** * 读事件 * 触发了读事件以后要执行的操作。类似于之前的channel.isReadable() * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 打印上一步转换好的字符串 System.out.println(msg); } }); } }).bind(8080); //7.绑定监听端口 } } ``` + **客户端** ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.string.StringEncoder; import java.net.InetSocketAddress; /** * @author lilinchao * @date 2022/6/6 * @description Netty 客户端 **/ public class HelloClient { public static void main(String[] args) throws InterruptedException { //1.启动类 new Bootstrap() //2.添加EventLoop .group(new NioEventLoopGroup()) //3.选择客户端 channel实现 .channel(NioSocketChannel.class) //4.添加处理器 .handler(new ChannelInitializer
() { // 在连接建立后被调用 @Override protected void initChannel(NioSocketChannel ch) throws Exception { ch.pipeline().addLast(new StringEncoder()); } }) //5.连接到服务器 .connect(new InetSocketAddress("localhost",8080)) .sync() .channel() //6.向服务器发送数据 .writeAndFlush("hello,world"); } } ``` *附参考原文:* *《黑马程序员Netty教程》*
标签:
Netty
,
NIO
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2137.html
上一篇
【转载】02.Netty线程模型
下一篇
【转载】04.Netty组件EventLoop介绍
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
查找
数据结构
机器学习
Zookeeper
高并发
Http
SpringCloudAlibaba
Python
数据结构和算法
Spark Core
Kibana
pytorch
人工智能
并发编程
Ubuntu
JavaScript
DataX
SpringCloud
VUE
BurpSuite
ajax
Azkaban
JavaWEB项目搭建
排序
哈希表
Elastisearch
JavaSE
二叉树
DataWarehouse
递归
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭