Detailed explanation of Netty's Socket programming - building server and client and data transmission

Scenes

Netty builds the HelloWorld server in IDEA and introduces the Netty execution process and important components:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108592418

The HelloWorld for building Netty has been implemented above. The following describes how to use Netty for Socket programming, and build a server to communicate with a client to transmit data.

Note:

Blog:
https://blog.csdn.net/badao_liumang_qizhi
Pay attention to the public account
domineering programmer
Get programming-related eBooks, tutorial pushes, and free downloads.

accomplish

Socket server construction

Create a new package under src, create a new Socket class under the package as the server, and create a new main method

package com.badao.nettySocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class SocketServer {
    public static void main(String[] args) throws  Exception
    {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try{
            //Server startup class-Netty The class provided to start the server
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //The parameters are two event groups, the former is used to receive the request and the latter is used to process
            //childHandler Set the handler that will be processed after the request arrives
            serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
                    .childHandler(new SocketServerInitializer());
            //bind port
            ChannelFuture channelFuture = serverBootstrap.bind(70).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            //close event group
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

Like the process of the above blog, a Socket server initializer SocketServerInitializer() is also required on the server side.

So the new class SocketServerInitializer is used as the initializer of the server.

package com.badao.nettySocket;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class SocketServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
        pipeline.addLast(new LengthFieldPrepender(4));
        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
        pipeline.addLast(new SocketServerHandler());
    }
}

In the initializer, it only needs to inherit from ChannelInitializer and the generic type is SocketChannel.

Then you need to override its initChannel method to initialize the channel.

Add some Netty's own processors to the method, mainly for encoding and decoding format settings.

Then finally add a custom handler to process the request.

So create a new custom server-side processing class SockerServerHandler

package com.badao.nettySocket;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class SocketServerHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("The server receives from"+ctx.channel().remoteAddress()+"of"+msg);
        ctx.channel().writeAndFlush("data sent by the server:(Public number: Domineering programmer)");
    }

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

In the processor, you need to inherit SimpleChannelInboundHandler, and the type of the generic is the type String that transmits the data

Then rewrite its channelRead0 method, which is the specific processing method.

In the method accept data from the client and send data to the client.

Then rewrite the exceptionCaught method to catch the exception and output it, and close the connection once an exception occurs.

Socket client construction

Consistent with building a Socket server, building a Socket client is also the same process.

Create a new SocketClient as a client class and add a main method

package com.badao.nettySocket;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class SocketClient {
    public static void main(String[] args) throws  Exception {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {

            Bootstrap bootstrap = new Bootstrap();

            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new SocketClientInitializer());
            //bind port
            ChannelFuture channelFuture = bootstrap.connect("localhost", 70);
            channelFuture.channel().closeFuture().sync();
        } finally {
            //close event group
            eventLoopGroup.shutdownGracefully();

        }
    }
}

 

In the main method, connect the port 70 bound to the server above. Note that the startup class here uses Bootstrap, and

The client uses the handler method, note that it is different from the server.

Then the client's initializer is also used in the client, so create a new SocketClientInitializer

package com.badao.nettySocket;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class SocketClientInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
        pipeline.addLast(new LengthFieldPrepender(4));
        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
        pipeline.addLast(new SocketClientHandler());
    }
}

 

The added handler is the same as that of the server, and a custom handler, SocketClientHandler, is also added.

So create a new class SocketClientHandler

package com.badao.nettySocket;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class SocketClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("Client receives from"+ctx.channel().remoteAddress()+"of"+msg);
        ctx.channel().writeAndFlush("The data sent by the client to the server: (Public Number: Domineering Programmer)");
    }

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


}

 

So far the server and client have been built.

Run the main method of SocketServer and the main method of SocketClient in turn. If no error is reported, the construction is successful.

But at this time, although the client and the server have established a connection, there is no interactive transmission of data and output.

This is because the client or server did not make a request.

So in the client's handler SocketClientHandler

Override the channelActive method, which will be executed after the channel is activated, that is, the connection is established

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush("Client sends message");
    }

 

Send a string message to the server in this method.

Then the channelRead0 method in the processor of the server will be activated and executed, and then output the data and send the data to the client.

Then channelRead0 in the client's processor will also be activated and executed, then the client will output the data received from the server and send data to the server.

So the client and server keep sending data.

Run the main method of the server and the client in turn, and view the output

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 


 

Tags: Netty

Posted by cashflowtips on Tue, 17 May 2022 14:15:06 +0300