Hello World for Netty server code

public class EchoServer { private final int port; public EchoServer(int port) { this.port = port; } public static void main(String[]args)throws Exception{ new EchoServer(8888).start(); } public void start() throws Exception{ final EchoServerHandler handler = new EchoServerHandler(); EventLoopGroup group = new NioEventLoopGroup(); try{ ServerBootstrap b = new ServerBootstrap(); b.group(group).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(handler); }}); ChannelFuture f = b.bind().sync(); f.channel().closeFuture().sync(); }finally { group.shutdownGracefully().sync(); }}}Copy the code
  1. Initialize EventLoopGroup

  1. Configure the bootstrap class ServerBootstrap as a tool to bootstrap channel creation

  • Initialize the group used to process connection requests (namely acceptors) and the childGroup used to process events (namely clients)

The Hello Word version of the code uses the same NioEventLoop, which is usually assigned separately in practice

  • Configure the type of channel to establish
  • Set the port to which the server listens
  • Configure the service’s own message handler, held through childHandler
  1. Create and initialize a channel

Adding ChannelInitializer at the end of the pipe adds a ServerBootstrapAcceptor (which is InboundHandler) to the pipe after the pipe is registered. It holds references to childGroup (Client) and childHandler, and the ChannelInitializer InboundHandler is removed from the channel once it has completed its mission.

ServerBootstrapAcceptor initially executes the call (subsequent read message call) when the client establishes a connection. The entry is doReadMessages. After reading the message, A read event is triggered along the InBoundHandler from Head to ServerBootstrapAcceptor, at which point a childGroup is registered to this channel, that is, the childGroup is used to process the read message each time

Public final void channelRegistered(ChannelHandlerContext CTX) throws Exception {// The ChannelPipeline is triggered after the channel registration is complete = ctx.pipeline(); boolean success =false; try { initChannel((C) ctx.channel()); ServerBootstrapAcceptor Pipeline.remove (this); ServerBootstrapAcceptor pipeline.remove(this); / / delete ChannelInitializer itself CTX. FireChannelRegistered (); // Continue passing the channel registration completion event success = along the pipetrue;
        } catch (Throwable t) {
            logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);
        } finally {
            if(pipeline.context(this) ! = null) { pipeline.remove(this); }if(! success) { ctx.close(); }}}Copy the code

The partial class structure of the new NioServerSocketChannel is as follows:

  • The unaddressed channel interface, for example, provides I/O operations for users, such as read, write, connect, and bind. The unaddressed channel interface, itself, does not expose data to users. In addition, it maintains a pipeline internally, which is used to connect various handlers to process data. In essence, a pipeline is a two-way linked list that maintains the relationship between handlers. It will hold the Channel reference of Netty itself, so that IO can be operated in the pipeline.The channel() method is Netty's own channel

    public DefaultChannelPipeline(AbstractChannel channel) {
        if (channel == null) {
            throw new NullPointerException("channel"); } this.channel = channel; //Netty's own channel tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; }Copy the code
  • Another channel, the CH property held by AbstractNioChannel, is initialized by the JDK in NioServerSocketChannel, the ServerSocketChannel object. Netty internalAny value retrieved from a javachannel() call is a JDK channel, whereas unsafe itself performs register, bind, connect, write, and read operations through ServerSocketChannel
  1. Perform channel registration

  1. Perform channel binding

What conclusions can be drawn from the Hello World version of the server?

Netty NIO registers channels and binds listener ports through the JDK’s OWN NIO. How are select and channel used in Java NIO?

Attached custom handler code

public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        System.out.printf("Server get:"+in.toString(CharsetUtil.UTF_8)); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { // Flush the message currently temporarily stored in the ChannelOutboundBuffer to the remote channel on the next flush or writeAndFlush and close the channel ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}Copy the code

Netty client code hello world

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 group = new NioEventLoopGroup(); try{ Bootstrap b = new Bootstrap(); B.group (group).channel(niosocketchannel.class)// specify the NIO transport mode. RemoteAddress (new InetSocketAddress(host,port))// specify the remoteAddress Handler (new ChannelInitializer<SocketChannel>() {// Add handler @override protected void to channel pipeline initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); //channelHander to pipeline}}); ChannelFuture f = b.connect().sync(); // Connect to the remote node, block until connection is complete system.out.println ("wait"); f.channel().closeFuture().sync(); // block until connection is closed system.out.println ("over");
        }finally {
            System.out.println("shutdown"); group.shutdownGracefully().sync(); }} public static void main(String[]args) throws Exception{new EchoClient("localhost",8888).start(); }}Copy the code

As you can see from the code itself, the differences with server lie in the following two parts:

  1. Bootstrap: functions similar to ServerBootstrap. It uses the builder mode to build parameters required by the client, including the remoteAddress remoteAddress to be connected and a customized handler
  2. Conncet: Channel creation and registration are similar to those on the server side, The server adds a ServerBootstrapAcceptor and executes JDK connect after initializing the Channel

Note that no local address is actually specified here

Attached with custom handler code

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello world",CharsetUtil.UTF_8));
    }

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

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("Client get:"+msg.toString(CharsetUtil.UTF_8)); }}Copy the code