您当前的位置: 首页 > 

03RPC - netty简介及入门

杨林伟 发布时间:2019-08-05 17:10:26 ,浏览量:4

Netty 是基于Java NIO的网络应用框架.

Netty 是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议。Netty 提供了一种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性。Netty的内部实现很复杂,但是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的。网络应用程序通常需要有较高的可扩展性,无论是Netty还是其他的基于Java NIO的框架,都会提供可扩展性的解决方案。

Netty中一个关键组成部分是它的异步特性

下面来看看一个入门的案例:

1.下载netty包

下载netty包,下载地址 http://netty.io/

2.服务端启动类
/**
 * • 配置服务器功能,如线程、端口 • 实现服务器处理程序,它包含业务逻辑,决定当有一个请求连接或接收数据时该做什么
 * 
 *
 */
public class EchoServer {

	private final int port;

	public EchoServer(int port) {
		this.port = port;
	}

	public void start() throws Exception {
		EventLoopGroup eventLoopGroup = null;
		try {
			//创建ServerBootstrap实例来引导绑定和启动服务器
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			
			//创建NioEventLoopGroup对象来处理事件,如接受新连接、接收数据、写数据等等
			eventLoopGroup = new NioEventLoopGroup();
			
			//指定通道类型为NioServerSocketChannel,设置InetSocketAddress让服务器监听某个端口已等待客户端连接。
			serverBootstrap.group(eventLoopGroup).channel(NioServerSocketChannel.class).localAddress("localhost",port).childHandler(new ChannelInitializer() {
				//设置childHandler执行所有的连接请求
				@Override
				protected void initChannel(Channel ch) throws Exception {
					ch.pipeline().addLast(new EchoServerHandler());
				}
					});
			
			// 最后绑定服务器等待直到绑定完成,调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭,因为使用sync(),所以关闭操作也会被阻塞。
			ChannelFuture channelFuture = serverBootstrap.bind().sync();
			System.out.println("开始监听,端口为:" + channelFuture.channel().localAddress());
			channelFuture.channel().closeFuture().sync();
		} finally {
			eventLoopGroup.shutdownGracefully().sync();
		}
	}

	public static void main(String[] args) throws Exception {
		new EchoServer(20000).start();
	}
}
3.服务端回调方法
public class EchoServerHandler extends ChannelInboundHandlerAdapter {

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		System.out.println("server 读取数据……");
		
		//读取数据
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("接收客户端数据:" + body);
        
        //向客户端写数据
        System.out.println("server向client发送数据");
        String currentTime = new Date(System.currentTimeMillis()).toString();
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		System.out.println("server 读取数据完毕..");
        ctx.flush();//刷新后才将数据发出到SocketChannel
	}

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

4.客户端启动类
/**
 * • 连接服务器 • 写数据到服务器 • 等待接受服务器返回相同的数据 • 关闭连接
 * 
 *
 */
public class EchoClient {

	private final String host;
	private final int port;

	public EchoClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void start() throws Exception {
		EventLoopGroup nioEventLoopGroup = null;
		try {
			//创建Bootstrap对象用来引导启动客户端
			Bootstrap bootstrap = new Bootstrap();
			
			//创建EventLoopGroup对象并设置到Bootstrap中,EventLoopGroup可以理解为是一个线程池,这个线程池用来处理连接、接受数据、发送数据
			nioEventLoopGroup = new NioEventLoopGroup();
			
			//创建InetSocketAddress并设置到Bootstrap中,InetSocketAddress是指定连接的服务器地址
			bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress(host, port))
					.handler(new ChannelInitializer() {
						//添加一个ChannelHandler,客户端成功连接服务器后就会被执行
						@Override
						protected void initChannel(SocketChannel ch)
								throws Exception {
							ch.pipeline().addLast(new EchoClientHandler());
						}
					});
			
			// • 调用Bootstrap.connect()来连接服务器
			ChannelFuture f = bootstrap.connect().sync();
			
			// • 最后关闭EventLoopGroup来释放资源
			f.channel().closeFuture().sync();
		} finally {
			nioEventLoopGroup.shutdownGracefully().sync();
		}
	}

	public static void main(String[] args) throws Exception {
		new EchoClient("localhost", 20000).start();
	}
}
5.客户端回调方法
	  
	public class EchoClientHandler extends SimpleChannelInboundHandler {  
	      //客户端连接服务器后被调用
	    @Override  
	    public void channelActive(ChannelHandlerContext ctx) throws Exception {  
	    	System.out.println("客户端连接服务器,开始发送数据……");
	    	byte[] req = "QUERY TIME ORDER".getBytes();
	    	ByteBuf  firstMessage = Unpooled.buffer(req.length);
	        firstMessage.writeBytes(req);
	        ctx.writeAndFlush(firstMessage);  
	    }  
	  
	  //•	从服务器接收到数据后调用
	    @Override  
	    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {  
	    	 System.out.println("client 读取server数据..");
	         //服务端返回消息后
	         ByteBuf buf = (ByteBuf) msg;
	         byte[] req = new byte[buf.readableBytes()];
	         buf.readBytes(req);
	         String body = new String(req, "UTF-8");
	         System.out.println("服务端数据为 :" + body);
}  
	  
	  //•	发生异常时被调用
	    @Override  
	    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
	    	 System.out.println("client exceptionCaught..");
	         // 释放资源
	         ctx.close(); 
	    }  
	}  
关注
打赏
1688896170
查看更多评论

杨林伟

暂无认证

  • 4浏览

    0关注

    3183博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0819s