溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

netty的maven怎么配置

發(fā)布時間:2022-01-06 15:21:15 來源:億速云 閱讀:256 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“netty的maven怎么配置”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“netty的maven怎么配置”吧!

    Netty被廣泛使用在各種場景,如Dubbo服務(wù)的遠程通信、Hadoop的shuffle過程、游戲領(lǐng)域的client和server通訊等等。Netty可以非常方便的定義各種私有協(xié)議棧,是網(wǎng)絡(luò)編程的利器。Netty是對NIO的封裝,Netty沒有封裝AIO是因為Linux的AIO也是用epoll來實現(xiàn)的,性能并非有太大提升,且Netty的reactor模型并不適合封裝AIO,故而Netty放棄了對AIO的支持。物聯(lián)網(wǎng)的興起,大量設(shè)備需要互聯(lián),Netty必然是其中的利器。

    傳統(tǒng)的NIO編程模型中需要用輪詢器selector去輪詢每個通道是否有讀寫事件發(fā)生,且ByteBuffer api晦澀難懂,維護起來非常復(fù)雜,業(yè)務(wù)很難解耦,Netty幫我們屏蔽了NIO的細節(jié),且做很多性能優(yōu)化。下面我們就來看看Netty中的一些細節(jié)。

 說明:以下例子netty版本號為4.1.52.Final,maven配置如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>org.netty</groupId>
	<artifactId>netty-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>netty-demo</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>io.netty</groupId>
			<artifactId>netty-all</artifactId>
			<version>4.1.52.Final</version>
		</dependency>
	</dependencies>
</project>

一、client端和server端的啟動

    1、server端

    ServerBootstrap里的group方法有兩個入?yún)⒍际荖ioEventLoopGroup,是兩個線程池,分別表示接受請求的線程和處理請求的線程,這就是reactor模型的體現(xiàn),每個客戶端連接進來,server端便有一個channel與之對應(yīng),childHandler方法便是給channel綁定一堆處理器,這里綁定了三個入站處理器。ctx.fireChannelRead(msg)表示通知下層處理器處理,若不調(diào)用該方法,讀事件將終止傳播到下游處理器。

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<NioSocketChannel>() {
					@Override
					protected void initChannel(NioSocketChannel ch) throws Exception {
						ch.pipeline().addLast(new StringDecoder()).addLast(new SimpleChannelInboundHandler<Object>() {
							@Override
							protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
								System.out.println("Handler1:" + msg);
								ctx.fireChannelRead(msg);
							}
						}).addLast(new SimpleChannelInboundHandler<Object>() {
							@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端

    客戶端以字符串的方式編碼,每隔三秒寫一條數(shù)據(jù)到服務(wù)端

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<Channel>() {
			@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處理細節(jié)全部屏蔽,業(yè)務(wù)開發(fā)時只需要定義不用入站和出站處理器處理對應(yīng)的業(yè)務(wù),實現(xiàn)了業(yè)務(wù)和通訊的解耦。

二、數(shù)據(jù)處理通道pipeline和通道處理器channelHandler

    1、channelHandler

netty的maven怎么配置

   繼承于ChannelHandler有兩大接口,ChannelInboundHandler和ChannelOutBoundHandler,分別代表入站和出站接口,對于如站處理器,當(dāng)有消息進來時channelRead(ChannelHandlerContext ctx, Object msg) 方法會觸發(fā),對于出站處理器,當(dāng)向外寫出數(shù)據(jù)時write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)會被觸發(fā)。 ChannelInboundHandlerAdapter和ChanneloutBoundHandlerAdapter則是對兩類接口的通用實現(xiàn)。里面都是一些非常簡單的實現(xiàn),僅僅將讀寫事件在pipeline中傳遞下去。

    2、pipeline的事件傳播順序

   對于入站處理器,執(zhí)?順序與addLast添加的順序保持?致,前面打印的例子中已經(jīng)驗證了這一點,對于出站處理器,執(zhí)行順序與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<Channel>() {
			@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

    這里就驗證了出站處理器,執(zhí)行順序與addLast添加的順序相反。

    pipeline實際上是維持了一個雙向鏈表,為什么會出現(xiàn)這種現(xiàn)象呢?我們在AbstractChannelHandlerContext找到了答案,findContextInbound方法是拿next節(jié)點,而findContextOutbound是拿前一個節(jié)點

 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;
    }

三、處理器的生命周期

    當(dāng)連接建立時,handlerAdded->channelRegistered->channelActive->channelRead->channelReadComplete

    當(dāng)連接關(guān)閉時,channelInactive->channelUnregistered->handlerRemoved

    說明:channelRead和channelReadComplete每次讀完一次完整的數(shù)據(jù)包時,這兩個方法都會被調(diào)用

四、拆包粘包解決

    TCP協(xié)議是一個流式協(xié)議,所以在傳輸數(shù)據(jù)時,并不會按照我們的業(yè)務(wù)來傳輸一個完整的包,可能出現(xiàn)多個包一起發(fā)送,這時候接收端就要進行拆包,也可以出現(xiàn)把一個完整的包拆成多個小包來傳輸,這時候接收端需要把多個包合并成一個完整包來解析。那么netty有哪些方案呢?

    1、定長拆包器FixedLengthFrameDecoder

    每個數(shù)據(jù)包都固定長度,比方說每個數(shù)據(jù)包都是50,適用與簡單的場景

    2、行拆包器LineBasedFrameDecoder

    用換行符來進行拆包

    3、分隔符拆包器 DelimiterBasedFrameDecoder

    這個是分割符拆包器類似,只不過可以自定義特殊符號進行拆包,例如# @等符號,使用的時候必須確保正式報文中沒有這些特殊符號

    4、長度域拆包器 LengthFieldBasedFrameDecoder

    這是一種最通用的拆包器,幾乎所有的二進制自定義協(xié)議都可以基于這種拆包器來進行拆包,只要協(xié)議頭中定義一個長度域即可,比方說用4字節(jié)存儲消息body的長度

到此,相信大家對“netty的maven怎么配置”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI