Netty启动流程分析

Netty 是基于 Java NIO 的异步事件驱动的网络应用框架,使用 Netty 可以快速开发网络应用,下面以一段代码来说明一下Netty的启动流程。

public void start() {
        ServerBootstrap bootstrap;
	    EventLoopGroup group;
	    MessageCollector collector;
	    Channel serverChannel;
		//启动NIO服务的辅助启动类
		bootstrap = new ServerBootstrap();
		/**
        1)用来接收进来的连接,数量如果不设置,默认为机器CPU核数的2倍,
          bossGroup里面注册的是ServerChannel,用来接收接收客户端的连接请求
          workerGroup里面注册的是Channel,即用来和客户端通信的channel
        2)NioEventLoopGroup里面会创建ioThreads个NioEventLoop,
          每个NioEventLoop内部是channel通信的逻辑,多个channel注册到一个selector, 
          NioEventLoop启动一个单实例线程池,这个单实例线程中执行一个方法,
          这个方法在while循环中通过事件驱动的方式监听来自客户端的消息,同时执行本地队列中的任务。
        */
        int ioThreads = 1;
        EventLoopGroup bossGroup = new NioEventLoopGroup(ioThreads);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        bootstrap.group(bossGroup, workerGroup)
        EchoServerHandler serverHandler = new EchoServerHandler();
		MessageEncoder encoder = new MessageEncoder();
		/**
        配置Channel
        1)传入NioServerSocketChannel这个类,Netty内部采用工厂模式来创建
        NioServerSocketChannel实例。
        2)通过childHandler这个方法将一个handlerContext加入到NioServerSocketChannel实例的
        channelPipeline中,当服务器接收到客户端的连接请求时,会创建一个NioSocketChannel, 
        并把这个NioSocketChannel分配给一个NioEventLoop,在NioEventLoop注册到一个selector上,由这个NioEventLoop来管理Channel的通信。
        3)ChannelInitializer是创建NioSocketChannel后向NioSocketChannel添加的创建ChannelPipeline的方法,主要包括4个handler:超时处理、解码器、编码器、业务处理。
        */
		bootstrap.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			public void initChannel(SocketChannel ch) throws Exception {
				//注册hander
				ChannelPipeline pipe = ch.pipeline();
				//如果客户端60秒没有任何请求,就关闭客户端连接
				pipe.addLast(new ReadTimeoutHandler(60));
				//加解码器
				pipe.addLast(new MessageDecoder());
				//编码器
				pipe.addLast(encoder);
				//将业务处理器放到最后
				pipe.addLast(serverHandler);
			}
		});
		bootstrap.option(ChannelOption.SO_BACKLOG, 100)  //客户端套接字默认接受队列的大小
				.option(ChannelOption.SO_REUSEADDR, true) //reuse addr 避免端口冲突
				.option(ChannelOption.TCP_NODELAY, true)  //关闭小流合并,保证消息的及时性
				.childOption(ChannelOption.SO_KEEPALIVE, true);  //长时间没动静的连接自动关闭
		//绑定端口,开始接收进来的连接
		serverChannel = bootstrap.bind(this.ip, this.port).channel();

		LOG.warn("server started @ {}:{}\n", ip, port);
	}


public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ctx.write(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

//消息编码器
public class MessageEncoder extends MessageToMessageEncoder<MessageOutput> {

	@Override
	protected void encode(ChannelHandlerContext ctx, MessageOutput msg, List<Object> out) throws Exception {
		ByteBuf buf = PooledByteBufAllocator.DEFAULT.directBuffer();
		writeStr(buf, msg.getRequestId());
		writeStr(buf, msg.getType());
		writeStr(buf, JSON.toJSONString(msg.getPayload()));
		out.add(buf);
	}

	private void writeStr(ByteBuf buf, String s) {
		buf.writeInt(s.length());
		buf.writeBytes(s.getBytes(Charsets.UTF8));
	}

}

//消息解码器
//使用Netty的ReplayingDecoder实现。
public class MessageDecoder extends ReplayingDecoder<MessageInput> {

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		String requestId = readStr(in);
		String type = readStr(in);
		String content = readStr(in);
		out.add(new MessageInput(type, requestId, content));
	}

	private String readStr(ByteBuf in) {
		int len = in.readInt();
		if (len < 0 || len > (1 << 20)) {
			throw new DecoderException("string too long len=" + len);
		}
		byte[] bytes = new byte[len];
		in.readBytes(bytes);
		return new String(bytes, Charsets.UTF8);
	}

}

上面是一个Netty的Server端的启动流程,通过这个可以看出使用Netty做网络通信的基本原理。下面通过一张图来详细说明:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值