Netty初步

正文索引 [隐藏]

导入依赖

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.5.Final</version>
</dependency>
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.10</version>
   <scope>test</scope>
</dependency>

创建一个Netty程序

1. ClientHandle

public class ClientHandle extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("客户端已激活");
        channelHandlerContext.writeAndFlush("Hello world");
    }

    @Override
    public void channelInactive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("客户端已关闭");
    }

    @Override
    public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        System.out.println("发送消息");

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.channel().close();
    }

}

2. Client

public class Client {
    private int port;
    private String ip;

    public Client(int port,String ip){
        this.port=port;
        this.ip=ip;
    }

    public void start(){
        EventLoopGroup eventExecutors=new NioEventLoopGroup();
        Bootstrap bootstrap=new Bootstrap();
        bootstrap.group(eventExecutors)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline channelPipeline=socketChannel.pipeline();
                        channelPipeline.addLast("decoder", new StringDecoder());
                        channelPipeline.addLast("encoder", new StringEncoder());
                        channelPipeline.addLast(new ClientHandle());
                    }
                });
        try {
            ChannelFuture channelFuture=bootstrap.connect("127.0.0.1",9999).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3. ServerHandle

public class ServerHandle extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("服务端已激活");
    }

    @Override
    public void channelInactive(ChannelHandlerContext channelHandlerContext) throws Exception {
        System.out.println("服务端已关闭");
    }

    @Override
    public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        System.out.println("接收到从客户端"+channelHandlerContext.channel().remoteAddress()+"的消息:"+o.toString());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        throwable.printStackTrace();
        channelHandlerContext.channel().close();
    }
}

4. Server

public class Server {
    private int port;
    //private String ip;

    public Server(int port){
       // this.ip=ip;
        this.port=port;
    }

    public void start(){
        EventLoopGroup listerloopGroup=new NioEventLoopGroup();
        EventLoopGroup workLoopGroup=new NioEventLoopGroup();
        ServerBootstrap serverBootstrap=new ServerBootstrap();
        serverBootstrap.group(listerloopGroup,workLoopGroup)
                .channel(NioServerSocketChannel.class)
                .localAddress(port)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline channelPipeline=socketChannel.pipeline();
                        channelPipeline.addLast("decoder", new StringDecoder());
                        channelPipeline.addLast("encoder", new StringEncoder());
                        channelPipeline.addLast(new ServerHandle());
                    }
                });
        try {
            ChannelFuture channelFuture=serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

上述程序表示了客户端连到服务端时,客户端向服务端发送一条Hello world的信息。

组件初解

  • EventLoopGroup、EventLoop、Channel
  1. EventLoopGroup为Netty的事件循环组,里面包含了多个EventLoop,服务端一般具有两个事件循环组,一个用于监听新的连接,另外一个来处理已连接的客户端,当然也可以使用一个,那么这两者都在一个事件循环组里进行。

  2. 每个EventLoop代表着一个线程,用来处理其绑定的Channel的所有事件,且每个EventLoop可以被绑定多个Channel。

  • ChannelHandlr、ChannelPipline、ChannelHandleContext
  1. 每个Channel都有一条ChannelPipline,每个ChannelPipline里面包括多个ChannelHandle(至少一个)

  2. ChannelHandle用来处理流经Channel的数据,通过ChannelHandleContext将每个ChannelHandle处理的结果连接起来

  • ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter
  1. ChannelInboundHandlerAdapter对应着入站事件(读事件、注册事件等),相反ChannelOutboundHandlerAdapter对应着出站事件(写事件等)

  2. 这两者是相对的概念,对服务器来言,服务端写入客户端称之为出站,而对于客户端来言,客户端写入服务器称为出站

  • ServerBootstrap、Bootstrap
  1. ServerBootstrap对应服务端的启动类,而Bootstrap对应着客户端的启动类

  2. 大部分的配置都在启动类上进行的,包括指明传输方式、配置ChannelHandle等

  • childHandler方法、Handle方法
  1. childHandler方法为已被接受的子Channel处理,代表着一个绑定到远程节点的套接字,也就是为每个客户端设置ChannelHandle,用来处理每个客户端==除了连接==的操作

  2. Handle方法添加的ChannelHandle由ServerChannel处理,代表着为服务端创建新的子Channel并处理,其实就是处理新的客户端连接

注意事项

  1. 传输时必须对消息进行利用解码器与编码器进行编码和解码,否则传输的消息接收不到

  2. 服务端与客户端指定的传输方式必须一致,即服务端指定传输方式为NIO,则客户端也必须使用NIO