netty框架学习
netty框架学习
公司的项目使用netty服务框架实现了充电桩与后台的交互,自己不是很了解,特别在网上查了点资料,同时记录一下.
Netty是一个NIO网络编程框架,快速开发高性能、高可靠性的网络服务器/客户端程序。 极大地简化了TCP和UDP等网络编程。是一个异步事件驱动的网络框架。
重点是NIO、快速、高性能 这是网上的说法,就是比较好用…
特别看了看项目中咋用的: 建了一个nettyServer的类,作为服务端
import java.nio.charset.Charset;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
@Component
public class NettyServer {
private static Logger logger = LoggerFactory.getLogger(NettyServer.class);
@Resource
private NettyServerHandler nettyServerHandler;
private ServerBootstrap sb = new ServerBootstrap();
// bossGroup用户监听和连接TCP
private EventLoopGroup bossGroup = new NioEventLoopGroup();
// workGroup用于数据I/O操作
private EventLoopGroup workGroup = new NioEventLoopGroup();
private ChannelFuture cf;
public void runServer() {
int port = 10010;
try {
sb.group(bossGroup, workGroup);
// NioServerSocketChannel 为AbstractBootstrap中的channel,用于监听、链接
sb.channel(NioServerSocketChannel.class)
// option 为父类AbstractBootstrap 的操作参数,bind()操作初始化的时候
// SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数,多个客户端连接的时候,
// 服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小
.option(ChannelOption.SO_BACKLOG, 5120)
// 这两个参数用于操作接收缓冲区和发送缓冲区的大小,缓冲区用于暂时保存数据直到处理成功
.option(ChannelOption.SO_RCVBUF, 4096)
.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(512, 2048, 65536));
// 该参数用于设置tcp连接,当设置该选项后,连接会测试链接的状态,
// 当设置该参数后如果在两小时内没有数据的通信,tcp会自动发送一个 活动探测数据报文
sb.childOption(ChannelOption.SO_KEEPALIVE, true);
sb.childOption(ChannelOption.SO_SNDBUF, 4096);
// 该参数的使用与Nagle算法有关,是将晓得数据包组装成更大的帧然后进行发送,而不是输入一次发送一次
// 当设置为true的时候关闭Nagle算法,提高了数据发送的及时性,false时更适合文件传输
sb.childOption(ChannelOption.TCP_NODELAY, true);
sb.handler(new LoggingHandler(LogLevel.DEBUG));
// childHandler 设置子类的handeler, TCP数据的编解码、读写操作
// AbstractBootstrap中NioServerSocketChannel的hanlder在bind()时创建
sb.childHandler(new ChannelInitializer < SocketChannel >() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline cp = channel.pipeline();
cp.addLast(new NettyProtocolDecoder());
cp.addLast(nettyServerHandler);
cp.addLast(new StringDecoder(Charset.forName("UTF-8")));
}
});
cf = sb.bind(port).sync();
cf.channel().closeFuture().sync();
}
catch (Exception e) {
e.printStackTrace();
logger.info("[INFO:runServer]NettyServer : The Netty Server Error As Starting....");
}
finally {
workGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
主要用到了:
Bootstrap:ServerBootstrap是监听服务端端口的启动器
Channel:关联jdk原生socket的组件,常用的是NioServerSocketChannel和NioSocketChannel,NioServerSocketChannel负责监听一个tcp端口,有连接进来通过boss reactor创建一个NioSocketChannel将其绑定到worker reactor,然后worker reactor负责这个NioSocketChannel的读写等io事件。
EventLoop:netty最核心的几大组件之一,就是我们常说的reactor,人为划分为boss reactor和worker reactor。通过EventLoopGroup(Bootstrap启动时会设置EventLoopGroup)生成,最常用的是nio的NioEventLoop,就如同EventLoop的名字,EventLoop内部有一个无限循环,维护了一个selector,处理所有注册到selector上的io操作,在这里实现了一个线程维护多条连接的工作。
ChannelPipeline:netty最核心的几大组件之一,ChannelHandler的容器,netty处理io操作的通道,与ChannelHandler组成责任链。write、read、connect等所有的io操作都会通过这个ChannelPipeline,依次通过ChannelPipeline上面的ChannelHandler处理.
然后通过@Resource注入一个nettyServerHandler,此 对象实现我们对连接客户端的处理逻辑:
import java.net.InetSocketAddress;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.ReferenceCountUtil;
@Component
//@Sharable 注解用来说明ChannelHandler可以在多个channel直接共享使用
@Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler < byte[] > {
private static Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
@Resource
private NettyMemoryManager nettyMemoryManager;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = insocket.getAddress().getHostAddress();
Integer port = insocket.getPort();
String key = clientIp + ":" + port;
nettyMemoryManager.setClientChannelToMap(key, ctx.channel()); // 将连接放入map中
logger.info(
"[INFO:channelActive] ClientIp:port " + key + "," + ctx.channel().remoteAddress() + " has been online");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, byte[] data) throws Exception {
}
public void channelWrite(String clientIp, Integer port, byte[] data) throws Exception {
}
public boolean channelWrite(String key, byte[] data) throws Exception {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
}
}
如果有多个客户端连接netty服务,就可以通过ChannelHandlerContext 对象获取客户端的IP,并将IP作为key,channel作为value存放到缓存中,当下次连接过来时就可以直接判断后取出对应channel的数据进行处理.
了解的还是有点浅,还要继续学习.
本文地址:https://blog.csdn.net/weixin_40423516/article/details/112007637
下一篇: 浅谈如何提高PHP代码的质量
推荐阅读
-
Java swing框架实现的贪吃蛇游戏完整示例
-
详解如何解决SSM框架前台传参数到后台乱码的问题
-
html5的websockets全双工通信详解学习示例
-
Springboot中集成Swagger2框架的方法
-
Spring学习笔记之bean的基础知识
-
iOS中使用JSPatch框架使Objective-C与JavaScript代码交互
-
Android开发学习笔记之通过API接口将LaTex数学函数表达式转化为图片形式
-
PHP网页游戏学习之Xnova(ogame)源码解读(十三)
-
PHP网页游戏学习之Xnova(ogame)源码解读(十五)
-
PHP网页游戏学习之Xnova(ogame)源码解读(十六)