netty的maven怎么配置

本篇内容主要讲解“netty的maven怎么配置”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“netty的maven怎么配置”吧!

网站制作、成都做网站的关注点不是能为您做些什么网站,而是怎么做网站,有没有做好网站,给创新互联一个展示的机会来证明自己,这并不会花费您太多时间,或许会给您带来新的灵感和惊喜。面向用户友好,注重用户体验,一切以用户为中心。

    Netty被广泛使用在各种场景,如Dubbo服务的远程通信、Hadoop的shuffle过程、游戏领域的client和server通讯等等。Netty可以非常方便的定义各种私有协议栈,是网络编程的利器。Netty是对NIO的封装,Netty没有封装AIO是因为Linux的AIO也是用epoll来实现的,性能并非有太大提升,且Netty的reactor模型并不适合封装AIO,故而Netty放弃了对AIO的支持。物联网的兴起,大量设备需要互联,Netty必然是其中的利器。

    传统的NIO编程模型中需要用轮询器selector去轮询每个通道是否有读写事件发生,且ByteBuffer api晦涩难懂,维护起来非常复杂,业务很难解耦,Netty帮我们屏蔽了NIO的细节,且做很多性能优化。下面我们就来看看Netty中的一些细节。

 说明:以下例子netty版本号为4.1.52.Final,maven配置如下:


	4.0.0

	org.netty
	netty-demo
	0.0.1-SNAPSHOT
	jar

	netty-demo
	http://maven.apache.org

	
		UTF-8
	

	
		
			io.netty
			netty-all
			4.1.52.Final
		
	

一、client端和server端的启动

    1、server端

    ServerBootstrap里的group方法有两个入参都是NioEventLoopGroup,是两个线程池,分别表示接受请求的线程和处理请求的线程,这就是reactor模型的体现,每个客户端连接进来,server端便有一个channel与之对应,childHandler方法便是给channel绑定一堆处理器,这里绑定了三个入站处理器。ctx.fireChannelRead(msg)表示通知下层处理器处理,若不调用该方法,读事件将终止传播到下游处理器。

public class NettyDemoServer {

	public static void main(String[] args) {
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()).channel(NioServerSocketChannel.class)
				.childHandler(new ChannelInitializer() {
					@Override
					protected void initChannel(NioSocketChannel ch) throws Exception {
						ch.pipeline().addLast(new StringDecoder()).addLast(new SimpleChannelInboundHandler() {
							@Override
							protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
								System.out.println("Handler1:" + msg);
								ctx.fireChannelRead(msg);
							}
						}).addLast(new SimpleChannelInboundHandler() {
							@Override
							protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
								System.out.println("Handler2:" + msg);
								ctx.fireChannelRead(msg);
							}

						});
					}
				}).bind(8080).addListener(o -> {
					if(o.isSuccess()){
						System.out.println("启动成功");
					}
				});
	}
}

    2、client端

    客户端以字符串的方式编码,每隔三秒写一条数据到服务端

public class NettyDemoClient {

	public static void main(String[] args)  {
		Bootstrap bootstrap = new Bootstrap();
		NioEventLoopGroup group = new NioEventLoopGroup();
		bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer() {
			@Override
			protected void initChannel(Channel ch) {
				ch.pipeline().addLast(new StringEncoder());
			}
		});
		Channel channel = bootstrap.connect("localhost", 8080).channel();
		while (true) {
			channel.writeAndFlush(new Date().toLocaleString() + ":测试netty");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

    运行效果如下:

启动成功
Handler1:2020-9-11 17:23:19:测试netty
Handler2:2020-9-11 17:23:19:测试netty
Handler1:2020-9-11 17:23:23:测试netty
Handler2:2020-9-11 17:23:23:测试netty
Handler1:2020-9-11 17:23:26:测试netty
Handler2:2020-9-11 17:23:26:测试netty

    Netty将IO处理细节全部屏蔽,业务开发时只需要定义不用入站和出站处理器处理对应的业务,实现了业务和通讯的解耦。

二、数据处理通道pipeline和通道处理器channelHandler

    1、channelHandler

netty的maven怎么配置

   继承于ChannelHandler有两大接口,ChannelInboundHandler和ChannelOutBoundHandler,分别代表入站和出站接口,对于如站处理器,当有消息进来时channelRead(ChannelHandlerContext ctx, Object msg) 方法会触发,对于出站处理器,当向外写出数据时write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)会被触发。 ChannelInboundHandlerAdapter和ChanneloutBoundHandlerAdapter则是对两类接口的通用实现。里面都是一些非常简单的实现,仅仅将读写事件在pipeline中传递下去。

    2、pipeline的事件传播顺序

   对于入站处理器,执⾏顺序与addLast添加的顺序保持⼀致,前面打印的例子中已经验证了这一点,对于出站处理器,执行顺序与addLast添加的顺序相反。下面我们在client端来验证这一点,在client端添加两个出站处理器。

public class NettyDemoClient {

	public static void main(String[] args) {
		Bootstrap bootstrap = new Bootstrap();
		NioEventLoopGroup group = new NioEventLoopGroup();
		bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer() {
			@Override
			protected void initChannel(Channel ch) {
				ch.pipeline().addLast(new StringEncoder()).addLast(new OutBoundHandlerFirst()).addLast(new OutBoundHandlerSecond());
			}
		});
		Channel channel = bootstrap.connect("localhost", 8080).channel();
		while (true) {
			channel.writeAndFlush(new Date().toLocaleString() + ":测试netty");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static class OutBoundHandlerFirst extends ChannelOutboundHandlerAdapter {
		@Override
		public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
			System.out.println("OutBoundHandlerFirst");
			super.write(ctx, msg, promise);
		}
	}

	public static class OutBoundHandlerSecond extends ChannelOutboundHandlerAdapter {
		@Override
		public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
			System.out.println("OutBoundHandlerSecond");
			super.write(ctx, msg, promise);
		}
	}
}

    打印日志如下:

OutBoundHandlerSecond
OutBoundHandlerFirst
OutBoundHandlerSecond
OutBoundHandlerFirst
OutBoundHandlerSecond
OutBoundHandlerFirst
OutBoundHandlerSecond
OutBoundHandlerFirst
OutBoundHandlerSecond
OutBoundHandlerFirst

    这里就验证了出站处理器,执行顺序与addLast添加的顺序相反。

    pipeline实际上是维持了一个双向链表,为什么会出现这种现象呢?我们在AbstractChannelHandlerContext找到了答案,findContextInbound方法是拿next节点,而findContextOutbound是拿前一个节点

 private AbstractChannelHandlerContext findContextInbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound);
        return ctx;
    }

    private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.prev;
        } while (!ctx.outbound);
        return ctx;
    }

三、处理器的生命周期

    当连接建立时,handlerAdded->channelRegistered->channelActive->channelRead->channelReadComplete

    当连接关闭时,channelInactive->channelUnregistered->handlerRemoved

    说明:channelRead和channelReadComplete每次读完一次完整的数据包时,这两个方法都会被调用

四、拆包粘包解决

    TCP协议是一个流式协议,所以在传输数据时,并不会按照我们的业务来传输一个完整的包,可能出现多个包一起发送,这时候接收端就要进行拆包,也可以出现把一个完整的包拆成多个小包来传输,这时候接收端需要把多个包合并成一个完整包来解析。那么netty有哪些方案呢?

    1、定长拆包器FixedLengthFrameDecoder

    每个数据包都固定长度,比方说每个数据包都是50,适用与简单的场景

    2、行拆包器LineBasedFrameDecoder

    用换行符来进行拆包

    3、分隔符拆包器 DelimiterBasedFrameDecoder

    这个是分割符拆包器类似,只不过可以自定义特殊符号进行拆包,例如# @等符号,使用的时候必须确保正式报文中没有这些特殊符号

    4、长度域拆包器 LengthFieldBasedFrameDecoder

    这是一种最通用的拆包器,几乎所有的二进制自定义协议都可以基于这种拆包器来进行拆包,只要协议头中定义一个长度域即可,比方说用4字节存储消息body的长度

到此,相信大家对“netty的maven怎么配置”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!


本文名称:netty的maven怎么配置
文章路径:http://azwzsj.com/article/ppcejh.html