Netty TCP Hello 實例

TCP Server

Netty的服務之一是TCP服務。要創建Netty TCP服務,必須: 

創建一個EventLoopGroup 

創建和配置ServerBootstrap 

創建一個ChannelInitializer 

啓動服務器

 

這是一個代碼示例,顯示瞭如何創建Netty TCP服務:

EventLoopGroup group = new NioEventLoopGroup();

try{
    ServerBootstrap serverBootstrap = new ServerBootstrap();
    serverBootstrap.group(group);
    serverBootstrap.channel(NioServerSocketChannel.class);
    serverBootstrap.localAddress(new InetSocketAddress("localhost", 9999));

    serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            socketChannel.pipeline().addLast(new HelloServerHandler());
        }
    });
    ChannelFuture channelFuture = serverBootstrap.bind().sync();
    channelFuture.channel().closeFuture().sync();
} catch(Exception e){
    e.printStackTrace();
} finally {
    group.shutdownGracefully().sync();
}

 

創建一個EventLoopGroup 

創建Netty TCP服務的第一步是創建Netty EventLoopGroup。示例使用 NIO,因此創建了NioEventLoopGroup。這是創建EventLoopGroup的代碼:

EventLoopGroup group = new NioEventLoopGroup();

 

創建一個ServerBootStrap 

創建Netty TCP服務的下一步是創建和配置ServerBootStrap。使用以下行完成此操作:

ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(group);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress("localhost", 9999));

 

首先,創建一個ServerBootstrap實例。 其次,在ServerBootstrap實例上設置EventLoopGroup。 第三,在ServerBootstrap實例上設置NioServerSocketChannel類實例。這是必需的,因爲該示例使用了NioEventLoopGroup。 第四,在ServerBootstrap上設置本地IP地址/域+ TCP端口。要啓動Netty TCP服務器,這也是必需設置的。

 

創建一個ChannelInitializer 

啓動Netty TCP服務的第三步是創建ChannelInitializer並將其附加到ServerBootstrap實例。 ChannelInitializer初始化所有傳入TCP連接的套接字。 在以下行中創建並附加ChannelInitializer:

serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline().addLast(new HelloServerHandler());
    }
});

 

Netty ChannelInitializer類是一個抽象類。每當TCP服務器接受新的傳入TCP連接時,就會調用其方法initChannel()。它將新的HelloServerHandler(一個ChannelHandler)附加到每個新的SocketChannel。還可以在所有新的SocketChannel實例中重用相同的ChannelHandler,而不是每次都在此處創建新的實例。使用childHandler()方法將ChannelInitializer添加到ServerBootstrap中。之所以將其稱爲“子”處理程序,是因爲每個接受的SocketChannel被視爲接受它的服務器套接字的“子”。

 

啓動服務器 

引導Netty TCP服務的最後一步是啓動服務:

ChannelFuture channelFuture = serverBootstrap.bind().sync();

 

serverBootstrap.bind()方法返回一個ChannelFuture,可用於瞭解何時完成服務器綁定(綁定到本地地址和TCP端口)。通過在ChannelFuture上調用sync(),創建服務的主線程將等到服務啓動後再繼續。順便說一下,sync()方法還返回ChannelFuture。

 

HelloServerHandler

ChannelInitializer添加到每個SocketChannel的HelloServerHandler是處理來自客戶端連接的傳入數據的組件:

public class HelloServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf inBuffer = (ByteBuf) msg;

        String received = inBuffer.toString(CharsetUtil.UTF_8);
        System.out.println("Server received: " + received);

        ctx.write(Unpooled.copiedBuffer("Hello " + received, CharsetUtil.UTF_8));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE);
    }

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

 

每當從HelloServerHandler實例附加到的SocketChannel接收數據時,都會調用channelRead()方法。客戶端發送到服務器的任何內容,​​channelRead()都會以“ Hello” + 響應。 當沒有更多數據可從SocketChannel中讀取時,調用channelReadComplete()方法。 如果從SocketChannel接收或發送數據時引發異常,則調用exceptionCaught()方法。在這裏,決定應如何處理異常後事情,例如關閉連接或使用錯誤代碼進行響應等。

 

TCP Client

Netty也可以用於創建TCP客戶端。在本教程中,要使用Netty創建TCP客戶端,需要: 

創建一個EventLoopGroup 

創建和配置引導程序 Bootstrap

創建一個ChannelInitializer 啓動客戶端

 

EventLoopGroup group = new NioEventLoopGroup();
try{
    Bootstrap clientBootstrap = new Bootstrap();

    clientBootstrap.group(group);
    clientBootstrap.channel(NioSocketChannel.class);
    clientBootstrap.remoteAddress(new InetSocketAddress("localhost", 9999));
    clientBootstrap.handler(new ChannelInitializer<SocketChannel>() {
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            socketChannel.pipeline().addLast(new ClientHandler());
        }
    });
    ChannelFuture channelFuture = clientBootstrap.connect().sync();
    channelFuture.channel().closeFuture().sync();
} finally {
    group.shutdownGracefully().sync();
}

 

創建一個EventLoopGroup 

創建Netty TCP客戶端的第一步是創建Netty EventLoopGroup。示例使用 NIO,因此創建了NioEventLoopGroup:

EventLoopGroup group = new NioEventLoopGroup();

 

創建和配置Bootstrap

使用Netty創建TCP客戶端的第二步是創建Netty Bootstrap實例。請注意,TCP服務使用ServerBootstrap,而TCP客戶端使用Bootstrap實例:

Bootstrap clientBootstrap = new Bootstrap();

 

還必須配置Bootstrap實例:

clientBootstrap.group(group);
clientBootstrap.channel(NioSocketChannel.class);
clientBootstrap.remoteAddress(new InetSocketAddress("localhost", 9999));

 

這在Bootstrap實例上設置EventLoopGroup,指定Bootstrap實例使用NIO,並設置要連接的遠程IP地址和TCP端口。

 

創建一個ChannelInitializer 

創建Netty TCP客戶端的第三步是創建ChannelInitializer並將其附加到Bootstrap實例:

clientBootstrap.handler(new ChannelInitializer<SocketChannel>() {
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        socketChannel.pipeline().addLast(new ClientHandler());
    }
});

 

ChannelInitializer將ClientHandler實例附加到它創建的SocketChannel。每當從附加到其的SocketChannel接收到數據時,就會調用ClientHandler。 ClientHandler附加到SocketChannel的管道。

 

啓動客戶端 

創建Netty TCP客戶端的最後一步是啓動TCP客戶端:

ChannelFuture channelFuture = clientBootstrap.connect().sync();

 

此Bootstrap實例連接到遠程服務器,並等待直到連接成功爲止:

channelFuture.channel().closeFuture().sync();

 

ClientHandler 

附加到連接到遠程服務器的SocketChannel的ClientHandler包含實際的客戶端行爲:

public class ClientHandler extends SimpleChannelInboundHandler {

    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext){
        channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("Netty Rocks!", CharsetUtil.UTF_8));
    }

    @Override
    public void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf in) {
        System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
    }

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

 

至此,一個簡單的 Netty TCP 服務就完成了!

 

原文地址: https://www.zhblog.net/go/java/tutorial/java-netty-tcp-hello?t=600

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章