Netty/NIO实践
来源:互联网 发布:高中免费教学视频软件 编辑:程序博客网 时间:2024/06/09 18:18
Netty的异步事件驱动模型主要涉及到下面几个核心的概念:
Channel:表示一个与socket关联的通道
ChannelPipeline: 管道,一个Channel拥有一个ChannelPipeline,ChannelPipeline维护着一个处理链(严格的说是两 个:upstream、downstream),
处理链是由很多处理句柄ChannelHandler所构成,每个ChannelHandler处理完以 后会传递给链中的下一个处理句柄继续处理。
ChannelHandler:处理句柄,用户可以定义自己的处理句柄来处理每个请求,或发出请求前进行预处理,典型的有编码/解码器:decoder、encoder。
ChannelEvent:事件,是整个模型的处理对象,当产生或触发(fire)一个事件时,该事件会沿着ChannelPipeline处理链依次被处理。
ChannelFuture: 异步结果,这个是异步事件处理的关键,当一个事件被处理时,可以直接以ChannelFuture的形式直接返回,不用在当前操作中被阻塞。
Channel:表示一个与socket关联的通道
ChannelPipeline: 管道,一个Channel拥有一个ChannelPipeline,ChannelPipeline维护着一个处理链(严格的说是两 个:upstream、downstream),
处理链是由很多处理句柄ChannelHandler所构成,每个ChannelHandler处理完以 后会传递给链中的下一个处理句柄继续处理。
ChannelHandler:处理句柄,用户可以定义自己的处理句柄来处理每个请求,或发出请求前进行预处理,典型的有编码/解码器:decoder、encoder。
ChannelEvent:事件,是整个模型的处理对象,当产生或触发(fire)一个事件时,该事件会沿着ChannelPipeline处理链依次被处理。
ChannelFuture: 异步结果,这个是异步事件处理的关键,当一个事件被处理时,可以直接以ChannelFuture的形式直接返回,不用在当前操作中被阻塞。
可以通过 ChannelFuture得到最终的执行结果,具体的做法是在ChannelFuture添加监听器listener,当操作最终被执行完 后,listener会被触发,
我们可以在listener的回调函数中预定义我们的业务代码。
Netty应用实例:
1. netty版本
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>5.0.0.Alpha2</version> </dependency>
2. 服务器端:
package com.xx.xx.web.nettypro.server;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelHandler;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 javax.annotation.PostConstruct;/** * Created by winy. */@ChannelHandler.Sharablepublic class EpayServer { // 服务绑定端口 private int port; public EpayServer(int port) { this.port = port; } public static void main(String[] args) throws InterruptedException { new EpayServer(5555).start(); } /** * 此处用的是main启动,在项目中时,start方法上可以用spring注解:@PostConstruct,然后把该类EpayServer交给spring管理即可 * 该注解的作用是spring装载bean的时候,在加载完EpayServer构造函数后执行 * @throws InterruptedException */ public void start() throws InterruptedException { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { // 服务端业务处理 final EpayServerHandler epayServerHandler = new EpayServerHandler(); ServerBootstrap serverBootstrap = new ServerBootstrap(); // 配置 serverBootstrap.group(eventLoopGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(epayServerHandler); } }); // 异步 ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { eventLoopGroup.shutdownGracefully().sync(); } }}
3. 服务器端handler
package com.xx.xx.web.nettypro.server;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;import io.netty.util.CharsetUtil;/** * Netty5: 取消了进站、出站的划分,统一为继承ChannelHandlerAdapter,原来的ChannelInboundHandlerAdapter,ChannelOutboundHandlerAdapter被废弃 * Created by winy */@ChannelHandler.Sharablepublic class EpayServerHandler extends ChannelHandlerAdapter { /** * 服务端接收到消息后执行 * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf byteBuf = (ByteBuf)msg; System.out.println("服务器接收到的信息====" + byteBuf.toString(CharsetUtil.UTF_8)); // 客户端请求服务器的请求信息 一般包含报文头+报文体 // 报文头为固定长度 // 报文体协定用&拼接 String msgServer = "服务器发送的消息:1"; byte[] bytes = msgServer.getBytes(); ByteBuf firstMessage = Unpooled.buffer(bytes.length); firstMessage.writeBytes(bytes); ctx.writeAndFlush(firstMessage); } /** * 客户端读完(客户端channelRead方法执行完后)数据后执行 * @param ctx * @throws Exception */ @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } /** * 异常的场合调用 * @param ctx * @param cause * @throws Exception */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}
4. 客户端
package com.xx.xx.web.nettypro.client;import io.netty.bootstrap.Bootstrap;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.NioSocketChannel;/** * Created by winy. */public class EpayClient { private String host; private int port; public EpayClient(String host,int port) { this.host = host; this.port = port; } public static void main(String[] args) { new EpayClient("服务器端ip",5555).start(); } public void start() { EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new EpayClientHandler()); } }); // 此处为异步调用 若需要同步,可使用await() ChannelFuture channelFuture = bootstrap.connect(host,port).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { try { eventLoopGroup.shutdownGracefully().sync(); } catch (InterruptedException e) { e.printStackTrace(); } } }}
5、客户端handler
package com.xx.xx.web.nettypro.client;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;/** * Created by winy */public class EpayClientHandler extends ChannelHandlerAdapter { /** * 连接服务器成功后执行发送信息 * 向服务器发送报文 * @param ctx * @throws Exception */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 客户端请求服务器的请求信息 一般包含报文头+报文体 // 报文头为固定长度 // 报文体协定用&拼接 String msgClient = "客户端信息1"; byte[] bytes = msgClient.getBytes(); ByteBuf firstMessage = Unpooled.buffer(bytes.length); firstMessage.writeBytes(bytes); ctx.writeAndFlush(firstMessage); } /** * 服务端返回消息后执行 * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //服务端返回消息后 ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "UTF-8"); System.out.println("client1 接收到的信息=" + body); } /** * 异常的场合调用 * @param ctx * @param cause * @throws Exception */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}
注:
1. 本实例测试过多个客户端的情况,当有多个客户端连接的场合,server和server handler 需要使用注解:@ChannelHandler.Sharable
2. 经测试此处客户端连接为短连接,而不是传输层TCP/IP协议的长连接,即一次连接完成就会断开!
文中如有不对之处,望大家指正!
0 0
- Netty/NIO实践
- Netty学习 netty nio编程
- Netty实践
- NIO-netty-入门学习
- java NIO: MINA, Netty
- Java NIO netty 简介
- java nio netty
- Java NIO 与 Netty
- Netty/NIO 概念
- NIO框架------Netty
- 多线程NIO模仿Netty
- netty nio线程模型
- Netty系列-NIO入门
- NIO流行框架 Netty
- netty可靠性(相对于nio)
- Netty学习-01-Nio
- Netty入门--NIO
- NIO Netty使用入门
- iOS开发-开发百度地图2-iOS SDK 3.0.0-定位及geo检索服务
- liunx基础
- Mybatis动态拼接SQL
- SQL连接查询
- synchronized与线程管理
- Netty/NIO实践
- C语言内置宏
- 神经网络资料整理
- 微擎 拼团支付提示URL 未注册
- 解决JSP中文乱码问题
- 正确使用 Volatile 变量
- shell编程基础
- 设计模式六大原则(2):里氏替换原则
- href="javascript:;"