Netty框架的基本使用

    Java在1.4之前,使用的都是传统的io进行操作的,基于此的socket的通信也是阻塞的;当服务端启动后,需要等待客户端发送过来一个数据才能进行后续操作;此情况下,当有大量的客户端发送请求时,会产生大量的线程,给服务器造成过大的压力。故而在Java 1.4之后引入了一个新的API——Java NIO

    

 NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
 
IO与NIO的区别

IO

NIO
                            面向流                                面向缓冲区
                            阻塞IO                                  非阻塞IO
                            基于流                                  基于通道
                               无                                   选择器
    

 NIO会向当前系统内核注册一个监听器,在客户端消息未发来之前,服务器可以处理其他事物,只有当消息过来时才会触发监听器,服务端开始处理消息。这样一来服务器就可以不用一直处于阻塞状态等待客户端的消息。

  现在开始说下封装了NIO连接内核注册监听器的操作的,只需要我们写业务代码的框架Netty

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

   2.服务端

package netty.server;

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;

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

	private final int port;
	
	public EchoServer(int port) {

		this.port = port;
	}
	
	public void start() throws Exception{
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
		
		serverBootstrap.group(eventLoopGroup)
					   .channel(NioServerSocketChannel.class)
					   .localAddress("localhost", port)
					   .childHandler(new ChannelInitializer() {

						@Override
						protected void initChannel(Channel ch) throws Exception {
							// TODO Auto-generated method stub
							ch.pipeline().addLast(new EchoServerHandler());
						}
					});
		
		// 最后绑定服务器等待直到绑定完成,调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭,因为使用sync(),所以关闭操作也会被阻塞。
		try {
			ChannelFuture channelFuture = serverBootstrap.bind().sync();
			System.out.println("开始监听,端口为:" + channelFuture.channel().localAddress());
			channelFuture.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			eventLoopGroup.shutdownGracefully().sync();
		}
	}
	
	public static void main(String[] args) throws Exception {
		new EchoServer(8888).start();
	}
}
3.服务端处理业务类

package netty.server;

import java.util.Date;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

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();
		System.out.println("服务端当前的时间:"+currentTime);
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
	}
	
	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("server 数据处理完毕");
		ctx.flush();
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		// TODO Auto-generated method stub
		cause.printStackTrace();
		
		ctx.close();
	}
}


4.客户端启动类

package netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import netty.server.EchoServer;
import netty.server.EchoServerHandler;

public class EchoClient {

private final int port;
	
	public EchoClient(int port) {

		this.port = port;
	}
	
	public void start() throws Exception{
		// 客户端引导类
		Bootstrap bootstrap = new Bootstrap();
		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
		
		bootstrap.group(eventLoopGroup)
					   .channel(NioSocketChannel.class)
					   .remoteAddress("localhost", port)
					   .handler(new ChannelInitializer() {

						@Override
						protected void initChannel(Channel ch) throws Exception {
							// TODO Auto-generated method stub
							ch.pipeline().addLast(new EchoClientHandler());
						}
					});
		
		// 链接服务器
		try {
			ChannelFuture channelFuture = bootstrap.connect().sync();
			channelFuture.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			eventLoopGroup.shutdownGracefully().sync();
		}
	}
	
	public static void main(String[] args) throws Exception {
		new EchoClient(8888).start();
	}
}

5.客户端处理业务类(回调)

package netty.client;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class EchoClientHandler extends SimpleChannelInboundHandler {

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("客户端连接服务器,开始发送数据……");
		byte[] req = "请求当前服务端时间".getBytes();//消息

		ByteBuf buffer = Unpooled.buffer(req.length);
		buffer.writeBytes(req);
		
		ctx.writeAndFlush(buffer);
	}
	
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
		// TODO Auto-generated method stub
		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);
	}

}


最后服务端的输出结果为
server 开始读取数据。。。
接收客户端数据:请求当前服务端时间
server向client发送数据。。。
服务端当前的时间:Thu Jul 20 14:45:00 CST 2017
server 数据处理完毕

客户端的输出结果

客户端连接服务器,开始发送数据……
client 读取server数据..
服务端当前时间 :Thu Jul 20 14:45:00 CST 2017

值得一提的是,当服务端注册了多个handler时,如果是InboundHandler,执行顺序为注册顺序;如果是OutboundHandler,执行顺序为注册顺序的逆序,且必须有一个InboundHandler在最后注册



 

你可能感兴趣的:(学习记录)