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