preface
As we all know, establishing socket connection is a very performance consuming thing when we make network connection. Especially in the case of distributed, using thread pool to maintain multiple client connections is a very thread consuming behavior. We have to solve one of the above problems through Netty's network connection technology
Netty
Netty is a NIO client server framework:
-
It can quickly and easily develop network applications, such as protocol servers and clients.
-
It greatly simplifies and simplifies network programming, such as TCP and UDP socket servers.
NIO is a non blocking IO, which has the following characteristics
-
A single thread can connect multiple clients.
-
The selector can manage multiple channels in a single thread, and all new channels must be registered with the selector.
-
A SelectionKey key represents the registration relationship between a specific channel object and a specific selector object.
-
The select() operation of the selector may cause blocking, but the blocking time can be set, and the selector can be awakened with wakeup(), so NIO is non blocking IO.
Netty model selector pattern
Compared with ordinary NIO, it has improved its performance by adopting:
-
NIO adopts multithreading and can use multiple selector s at the same time
-
By binding multiple ports, a selector can register multiple serversocketservers at the same time
-
There can only be one selector in a single thread to realize Channel matching and reuse
Semi package problem
TCP/IP may unpack when sending messages, which makes the receiver unable to know when the received data is a complete data. In traditional BIO, blocking occurs when data cannot be read, but NIO does not. In order to solve the half package problem of NIO, Netty proposed reactor mode on the basis of Selector model, so as to solve the problem that the client request is incomplete on the server.
netty model reactor mode
- The semi package problem is solved on the basis of selector.
In the above figure, it can be simply described as "boss takes over and let work do": manReactor is used to receive requests (handshake verification with the client), while subReactor is used to process requests (not directly connect with the client).
SpringBoot uses Netty to implement remote calls
maven dependency
<!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.2</version> <optional>true</optional> </dependency> <!--netty--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.17.Final</version> </dependency>
Server part
NettyServer.java: service startup listener
@Slf4j public class NettyServer { public void start() { InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8082); //new a main thread group EventLoopGroup bossGroup = new NioEventLoopGroup(1); //new a worker thread group EventLoopGroup workGroup = new NioEventLoopGroup(200); ServerBootstrap bootstrap = new ServerBootstrap() .group(bossGroup, workGroup) .channel(NioServerSocketChannel.class) .childHandler(new ServerChannelInitializer()) .localAddress(socketAddress) //Set queue size .option(ChannelOption.SO_BACKLOG, 1024) // When there is no data communication within two hours, TCP will automatically send an activity detection data message .childOption(ChannelOption.SO_KEEPALIVE, true); //Bind the port and start receiving incoming connections try { ChannelFuture future = bootstrap.bind(socketAddress).sync(); log.info("Server start listening port: {}", socketAddress.getPort()); future.channel().closeFuture().sync(); } catch (InterruptedException e) { log.error("Server startup failed", e); } finally { //Close main thread group bossGroup.shutdownGracefully(); //Close worker thread group workGroup.shutdownGracefully(); } } }
ServerChannelInitializer.java: netty service initializer
/** * netty Service initializer **/ public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //Add codec socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast(new NettyServerHandler()); } }
NettyServerHandler.java: netty server processor
/** * netty Server processor **/ @Slf4j public class NettyServerHandler extends ChannelInboundHandlerAdapter { /** * Client connection triggers */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { log.info("Channel active......"); } /** * When the client sends a message, it will trigger */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { log.info("The server received a message: {}", msg.toString()); ctx.write("You too"); ctx.flush(); } /** * Abnormal trigger occurred */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
RpcServerApp.java: SpringBoot startup class
/** * Startup class * */ @Slf4j @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class RpcServerApp extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(RpcServerApp.class); } /** * How to start the project * * @param args */ public static void main(String[] args) { SpringApplication.run(RpcServerApp.class, args); //Turn on Netty service NettyServer nettyServer =new NettyServer (); nettyServer.start(); log.info("======Service started========"); } }
Client part
NettyClientUtil.java: NettyClient tool class
/** * Netty client **/ @Slf4j public class NettyClientUtil { public static ResponseResult helloNetty(String msg) { NettyClientHandler nettyClientHandler = new NettyClientHandler(); EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap() .group(group) //The function of this parameter is to prohibit the use of Nagle algorithm for real-time transmission of small data .option(ChannelOption.TCP_NODELAY, true) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast("decoder", new StringDecoder()); socketChannel.pipeline().addLast("encoder", new StringEncoder()); socketChannel.pipeline().addLast(nettyClientHandler); } }); try { ChannelFuture future = bootstrap.connect("127.0.0.1", 8082).sync(); log.info("Client sent successfully...."); //send message future.channel().writeAndFlush(msg); // Wait for the connection to be closed future.channel().closeFuture().sync(); return nettyClientHandler.getResponseResult(); } catch (Exception e) { log.error("client Netty fail", e); throw new BusinessException(CouponTypeEnum.OPERATE_ERROR); } finally { //Thread exit in an elegant way group.shutdownGracefully(); } } }
NettyClientHandler.java: client processor
/** * Client processor **/ @Slf4j @Setter @Getter public class NettyClientHandler extends ChannelInboundHandlerAdapter { private ResponseResult responseResult; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { log.info("client Active ....."); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { log.info("Client received message: {}", msg.toString()); this.responseResult = ResponseResult.success(msg.toString(), CouponTypeEnum.OPERATE_SUCCESS.getCouponTypeDesc()); ctx.close(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
verification
Test interface
@RestController @Slf4j public class UserController { @PostMapping("/helloNetty") @MethodLogPrint public ResponseResult helloNetty(@RequestParam String msg) { return NettyClientUtil.helloNetty(msg); } }
Access test interface
Server printing information
Client print information
Author: Xiyuan's wonderful ideas
Share the answers to this interview and the collected interview questions that must be asked by large manufacturers:
return NettyClientUtil.helloNetty(msg); }
}
Access test interface [External chain picture transfer...(img-p980MOVn-1623617592124)] Server printing information [External chain picture transfer...(img-K6besFit-1623617592126)] Client print information [External chain picture transfer...(img-lmPBltyE-1623617592127)] > Author: Xiyuan's wonderful ideas # Share the answers to this interview and the collected interview questions that must be asked by large manufacturers: [External chain picture transfer...(img-AMLE7k5o-1623617592128)] **[Data collection method: you can download it for free by stamping here](https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB)**