Netty初次使用

Netty初次使用

简介

Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。

使用
服务端的建立:

1 创建ServerBootstrap实例。ServerBootstrap是Netty服务端的启动辅助类,它提供了一系列的方法用于设置服务端启动相关的参数。底层通过门面模式对各种能力进行抽象和封装,尽量不需要用户跟过多的底层API打交道,降低用户的开发难度。

2 设置并绑定Reactor线程池。Netty的Reactor线程池是EventLoopGroup,它实际就是EventLoop的数组。EventLoop的职责是处理所有注册到本线程多路复用器Selector上的Channel,Selector的轮询操作由绑定的EventLoop线程run方法驱动,在一个循环体内循环执行。值得说明的是,EventLoop的职责不仅仅是处理网络I/O事件,用户自定义的Task和定时任务Task也统一由EventLoop负责处理,这样线程模型就实现了统一。从调度层面看,也不存在在EventLoop线程中再启动其它类型的线程用于异步执行其它的任务,这样就避免了多线程并发操作和锁竞争,提升了I/O线程的处理和调度性能。

3 设置并绑定服务端Channel。作为NIO服务端,需要创建ServerSocketChannel,Netty对原生的NIO类库进行了封装,对应实现是NioServerSocketChannel。对于用户而言,不需要关心服务端Channel的底层实现细节和工作原理,只需要指定具体使用哪种服务端Channel即可。因此,Netty的ServerBootstrap方法提供了channel方法用于指定服务端Channel的类型。Netty通过工厂类,利用反射创建NioServerSocketChannel对象。由于服务端监听端口往往只需要在系统启动时才会调用,因此反射对性能的影响并不大。

4 链路建立的时候创建并初始化ChannelPipeline。ChannelPipeline并不是NIO服务端必需的,它本质就是一个负责处理网络事件的职责链,负责管理和执行ChannelHandler。网络事件以事件流的形式在ChannelPipeline中流转,由ChannelPipeline根据ChannelHandler的执行策略调度ChannelHandler的执行。

5 初始化ChannelPipeline完成之后,添加并设置ChannelHandler。ChannelHandler是Netty提供给用户定制和扩展的关键接口。利用ChannelHandler用户可以完成大多数的功能定制,例如消息编解码、心跳、安全认证、TSL/SSL认证、流量控制和流量整形等。Netty同时也提供了大量的系统ChannelHandler供用户使用,比较实用的系统ChannelHandler总结如下:

  • 系统编解码框架-ByteToMessageCodec;

  • 通用基于长度的半包解码器-LengthFieldBasedFrameDecoder;

  • 码流日志打印Handler-LoggingHandler;

  • SSL安全认证Handler-SslHandler;

  • 链路空闲检测Handler-IdleStateHandler;

  • 流量整形Handler-ChannelTrafficShapingHandler;

  • Base64编解码-Base64Decoder和Base64Encoder。

6 绑定并启动监听端口。在绑定监听端口之前系统会做一系列的初始化和检测工作,完成之后,会启动监听端口,并将ServerSocketChannel注册到Selector上监听客户端连接

7 Selector轮询。由Reactor线程NioEventLoop负责调度和执行Selector轮询操作,选择准备就绪的Channel集合

8 当轮询到准备就绪的Channel之后,就由Reactor线程NioEventLoop执行ChannelPipeline的相应方法,最终调度并执行ChannelHandler

9 执行Netty系统ChannelHandler和用户添加定制的ChannelHandler。ChannelPipeline根据网络事件的类型,调度并执行ChannelHandler

简单实例:

服务端:

package mynetty;

import java.nio.channels.SocketChannel;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
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.nio.NioServerSocketChannel;

public class Server {
	int port;
	public Server(int port) {
			this.port = port;
	}
	
	public void start() throws InterruptedException {
		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();//用于服务器端接受客户端的连接
		ServerBootstrap serverBootstrap = new ServerBootstrap();//用于网络事件的处理
		serverBootstrap.group(eventLoopGroup) //绑定线性池
								.channel(NioServerSocketChannel.class) //指定使用的channel
								.localAddress(this.port)
								.childHandler(new ChannelInitializer<Channel>() { //绑定客户端连接后触发的操作

									@Override
									protected void initChannel(Channel arg0) throws Exception {
										System.out
												.println("等待连接。。。。。。。");
										arg0.pipeline().addLast(new ServerHandler());//客户端触发操作
									}
									
								});
		ChannelFuture cf = serverBootstrap.bind().sync();//服务端异步创建绑定
		System.out.println("服务器开始在端口"+this.port+"监听");
		cf.channel().closeFuture().sync(); //关闭服务器通道
		
	}
	  public static void main(String[] args) throws Exception {
			  	Server server = new Server(3391);
			  	server.start();
	  }
}

服务端对客户端的处理:

package mynetty;

import io.netty.buffer.Unpooled;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter{
	
	/*
	 * (non-Javadoc)
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 * 当收到对方发来的数据后,就会触发,参数msg就是发来的信息,可以是基础类型,也可以是序列化的复杂对象。
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		ctx.write(msg);
	}
	
	
	/*
	 * (non-Javadoc)
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelReadComplete(io.netty.channel.ChannelHandlerContext)
	 * channelRead执行后触发
	 */
	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
	}
		
	
}

客户端:

package mynetty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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.nio.NioSocketChannel;

public class Client {

	String hoString;
	int port;
	public Client(String hoString,int port) {
			this.hoString = hoString;
			this.port = port;
	}
	
	public void start() throws InterruptedException {
		EventLoopGroup  eventLoopGroup = new NioEventLoopGroup();
		Bootstrap bootstrap = new Bootstrap();
		bootstrap.group(eventLoopGroup) //绑定线程池
					.channel(NioSocketChannel.class) //使用NioSocketChannel来作为连接用的channel类
					.remoteAddress(this.hoString,this.port) //绑定端口和host信息
					.handler(new ChannelInitializer<Channel>() {  //绑定连接初始化器

						@Override
						protected void initChannel(Channel arg0) throws Exception {
							arg0.pipeline().addLast(new ClientHandler());
							
						}
					});
		
	System.out.println("创建客户端。。。。");
	ChannelFuture cf = bootstrap.connect().sync(); //异步连接服务器
	System.out.println("创建成功");
	cf.channel().closeFuture().sync(); //异步关闭连接通道
	}
	
	
	public static void main(String[] args) throws InterruptedException {
			Client client = new Client("127.0.0.1",3391);
			client.start();
	}

}

客户端处理:

package mynetty;

import java.nio.charset.Charset;


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

public class ClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
	
	
	/*
	 * (non-Javadoc)
	 * @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, java.lang.Object)
	 * 接收到服务器数据后被调用
	 */
	@Override
	protected void channelRead0(ChannelHandlerContext arg0, ByteBuf arg1) throws Exception {
		System.out.println("客户端进行读取");
		ByteBuf buf = arg1.readBytes(arg1.readableBytes());
		System.out.println(buf.toString(Charset.forName("utf-8")));
		
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see io.netty.channel.ChannelInboundHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext)
	 * 连接到服务器后被调用
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		
		System.out.println("客户端创建成功");
		ctx.writeAndFlush(Unpooled.copiedBuffer("Hello",CharsetUtil.UTF_8));
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		super.exceptionCaught(ctx, cause);
	}

	
		
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值