一、前言
Netty是一个基于Java的开源网络应用框架,它提供了高性能、异步事件驱动的网络编程能力。Netty旨在帮助开发者构建高性能、高可靠性的网络应用程序。
Netty提供了简洁的API和丰富的功能,它可以轻松处理各种网络通信协议,如TCP、UDP、HTTP、WebSocket等。它的设计理念是基于事件驱动和回调机制,而不是传统的线程模型,这使得它可以实现高并发、低延迟的网络通信。
Netty可以方便地处理复杂的网络通信逻辑,例如请求-响应模式、长连接、心跳检测等。它提供了灵活的编解码器和处理器,可以对网络数据进行高效的编解码和处理。同时Netty还提供了可靠的错误机制和事件机制,方便开发者进行异常处理和扩展。
二、特点
1.高性能
Ne服务器托管网tty基于事件驱动的异步模型,通过使用非阻塞的I/O操作和多线程处理请求,实现了高性能的网络通信。
2.高可靠性
Netty提供了一套强大的错误处理进制,包括异步处理、断线重连、心跳检测等,可以有效地处理网络中的各种异常情况,提高应用程序的可靠性。
3.高可扩展性
Netty的设计模式和组件化架构使得它非常易于扩展和定制。开发人员可以根据自己的需求,选择合适的组件和模块,构建出符合自己业务需求的网络应用程序。
4.支持多种协议
Netty支持多种常用的网络协议,包括TCP、HTTP、UDP、WebSocket等,可以满足不同场景下的网络通信需求。
三、集成SpringBoot
1.添加依赖
io.netty
netty-all
2.编写Netty消息处理器
package com.example.bootdemo.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
/**
* @author qx
* @date 2023/12/18
* @desc 处理客户端的消息
*/
@Slf4j
public class MessageHandler extends ChannelInboundHandlerAdapter {
/**
* 读取客户端发来的消息
*
* @param ctx
* @param msg 消息
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 因为我们在netty初始化中设置了字节数组的编解码器 所以这里获取到byte数组
byte[] result = (byte[]) msg;
log.info("接收到的消息:{}", Arrays.toString(result));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
log.info("新的客户端连接:{}", ctx.channel().remoteAddress().toString());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
log.info("客户端断开连接:{}", ctx.channel().remoteAddress().toString());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("netty连接异常:{}", cause.getMessage());
}
}
ChannelHandlerContext 代表 ChannelHandler 和ChannelPipeline 之间的关联,并在 ChannelHandler 添加到 ChannelPipeline 时创建一个实例。ChannelHandlerContext 的主要功能是管理通过同一服务器托管网个 ChannelPipeline 关联的 ChannelHandler 之间的交互。
3.编写Netty初始化处理
package com.example.bootdemo.netty;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import org.springframework.stereotype.Component;
/**
* @author qx
* @date 2023/12/18
* @desc Netty初始化器
*/
@Component
public class NettyInitializer extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 添加字节数组的编解码器
pipeline.addLast(new ByteArrayDecoder());
pipeline.addLast(new ByteArrayEncoder());
// 基于分隔符的解码器 0xAA开头 0xCC结尾 提供分隔符解析报文 128表示单条消息的最大长度,解码器查找分隔符的时候,达到该长度没有找到会抛出异常。
pipeline.addLast(new DelimiterBasedFrameDecoder(128, Unpooled.copiedBuffer(new byte[]{(byte) 0xAA}), Unpooled.copiedBuffer(new byte[]{(byte) 0xCC})));
// 添加自定义处理器
pipeline.addLast("handler", new MessageHandler());
}
}
4.编写Netty服务
我们首先在application.properties配置中添加两个Netty相关配置。
#netty服务监听端口
netty.port=8888
#主线程组数量
netty.bossThread=1
package com.example.bootdemo.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author qx
* @date 2023/12/18
* @desc Netty服务
*/
@Slf4j
@Component
public class NettyServer {
@Autowired
private NettyInitializer nettyInitializer;
@Getter
private ServerBootstrap serverBootstrap;
@Value("${netty.port}")
private int port;
@Value("${netty.bossThread}")
private int bossThread;
/**
* 启动netty服务器
*/
public void start() {
this.init();
this.serverBootstrap.bind(this.port);
log.info("netty start");
}
/**
* netty初始化配置
*/
private void init() {
// 创建两个线程组,bossGroup为接收请求的线程组,一般1-2个就行
NioEventLoopGroup bossGroup = new NioEventLoopGroup(this.bossThread);
// 实际工作的线程组
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
this.serverBootstrap = new ServerBootstrap();
this.serverBootstrap.group(bossGroup, workerGroup) // 两个线程组加入进来
.channel(NioServerSocketChannel.class) // 配置为nio类型
.childHandler(this.nettyInitializer); // 加入自己的初始化器
}
}
5.启动Netty
package com.example.bootdemo.netty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* @author qx
* @date 2023/12/18
* @desc 监听Spring容器启动完成,完成后启动Netty服务器
*/
@Component
public class NettyListener implements ApplicationRunner {
@Autowired
private NettyServer nettyServer;
@Override
public void run(ApplicationArguments args) throws Exception {
nettyServer.start();
}
}
6.启动程序
我们可以在启动日志中发现我们已经成功启动了netty。
2023-12-18 22:41:57.395 INFO 7848 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-12-18 22:41:57.397 INFO 7848 --- [ main] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed
2023-12-18 22:41:57.429 INFO 7848 --- [ main] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)
2023-12-18 22:41:57.477 INFO 7848 --- [ main] s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references
2023-12-18 22:41:57.675 INFO 7848 --- [ main] c.example.bootdemo.BootDemoApplication : Started BootDemoApplication in 5.624 seconds (JVM running for 8.665)
2023-12-18 22:41:58.895 INFO 7848 --- [ main] com.example.bootdemo.netty.NettyServer : netty start
四、客户端测试
我们可以下载Windows下的网络调试工具NetAssist,它对于需要编写各种通信协议的TCP服务端、客户端以及UDP通信程序来说是很方便的。
NetAssist的下载地址为:NetAssist.exe(http://www.cmsoft.cn/download/cmsoft/netassist.zip)
具体的使用方法可以百度下,也是很简单的。
具体我们只需要修改远程主机地址为本机地址和远程主机端口为我们在配置文件中监听的端口,然后点击连接就可以了。
在控制台上我们可以看到新的客户端连接成功的日志。
2023-12-18 22:51:53.456 INFO 7848 --- [ntLoopGroup-3-2] c.example.bootdemo.netty.MessageHandler : 新的客户端连接:/127.0.0.1:50104
然后在发送设置里面设置ASCII或者HEX的格式发送数据就可以了。
现在我们发送AA开头 CC结尾的数据,此前我们在初始化器中设置了开头和结尾的分隔符解码器。
点击发送之后我们可以在控制台日志上接收到字节数组数据。
2023-12-18 22:54:00.997 INFO 7848 --- [ntLoopGroup-3-2] c.example.bootdemo.netty.MessageHandler : 接收到的消息:[-86, 14, 13, -52]
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
数据中心的运维压力到底有多大?过去,IT圈里流传着这样一句话:一入运维深似海,从此下班是路人。随着人工智能、大数据、云计算等技术的成熟应用,数据中心走向集约化、规模化的趋势,数据中心的IT设备越来越繁杂,同时超过10万台乃至100万台服务器的超大规模数据中心越…