|
@@ -2,26 +2,28 @@ package db.netty;
|
|
|
|
|
|
import db.entity.packages.BasePackage;
|
|
|
import io.netty.bootstrap.Bootstrap;
|
|
|
+import io.netty.buffer.PooledByteBufAllocator;
|
|
|
import io.netty.channel.*;
|
|
|
+import io.netty.channel.epoll.Epoll;
|
|
|
+import io.netty.channel.epoll.EpollChannelOption;
|
|
|
+import io.netty.channel.epoll.EpollDatagramChannel;
|
|
|
+import io.netty.channel.epoll.EpollEventLoopGroup;
|
|
|
import io.netty.channel.nio.NioEventLoopGroup;
|
|
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.context.annotation.DependsOn;
|
|
|
-import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
import javax.annotation.PreDestroy;
|
|
|
import java.util.concurrent.DelayQueue;
|
|
|
-import java.util.concurrent.PriorityBlockingQueue;
|
|
|
|
|
|
@Component
|
|
|
@DependsOn("springUtils")
|
|
|
@Slf4j
|
|
|
public class NettyServer {
|
|
|
-
|
|
|
- EventLoopGroup group = new NioEventLoopGroup();
|
|
|
+ private EventLoopGroup bossGroup;
|
|
|
|
|
|
@Value("${netty.port}")
|
|
|
private Integer port;
|
|
@@ -40,6 +42,12 @@ public class NettyServer {
|
|
|
@Value("${system.sender.retry-times}")
|
|
|
private Integer retryTimes;
|
|
|
|
|
|
+ @Value("${system.udp-server.worker-thread-num}")
|
|
|
+ private Integer workThreadNum;
|
|
|
+
|
|
|
+ @Value("${system.udp-server.use-multithread}")
|
|
|
+ private Boolean useMultiThread;
|
|
|
+
|
|
|
private DelayQueue<BasePackage> sendingQueue = new DelayQueue<>();
|
|
|
|
|
|
/**
|
|
@@ -49,15 +57,25 @@ public class NettyServer {
|
|
|
*/
|
|
|
@PostConstruct
|
|
|
public void start() throws InterruptedException {
|
|
|
+ if(useMultiThread) startMT();
|
|
|
+ else startST();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * single thread
|
|
|
+ */
|
|
|
+ protected void startST() throws InterruptedException {
|
|
|
log.info("开始启动 Netty Server,host:{} port: {}", host, port);
|
|
|
Bootstrap bootstrap = new Bootstrap();
|
|
|
+ bossGroup = new NioEventLoopGroup();
|
|
|
+
|
|
|
NettyServerHandler nettyServerHandler = new NettyServerHandler();
|
|
|
nettyServerHandler.setUseSeperateThread(useSeperateThread);
|
|
|
|
|
|
Decoder decoder = new Decoder();
|
|
|
decoder.setShowRecvBytes(this.showRecvBytes);
|
|
|
|
|
|
- bootstrap.group(group)
|
|
|
+ bootstrap.group(bossGroup)
|
|
|
// 指定Channel
|
|
|
.channel(NioDatagramChannel.class)
|
|
|
|
|
@@ -72,7 +90,6 @@ public class NettyServer {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
-
|
|
|
ChannelFuture future = bootstrap.bind(host, port).sync();
|
|
|
if (future.isSuccess()) {
|
|
|
log.info("成功启动 Netty Server,host:{} port: {}", host, port);
|
|
@@ -82,6 +99,57 @@ public class NettyServer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * multithread
|
|
|
+ */
|
|
|
+ protected void startMT() throws InterruptedException {
|
|
|
+ log.info("开始启动 Netty Server,host:{} port: {}", host, port);
|
|
|
+ Bootstrap bootstrap = new Bootstrap();
|
|
|
+ NettyServerHandler nettyServerHandler = new NettyServerHandler();
|
|
|
+ nettyServerHandler.setUseSeperateThread(useSeperateThread);
|
|
|
+ Decoder decoder = new Decoder();
|
|
|
+ decoder.setShowRecvBytes(this.showRecvBytes);
|
|
|
+
|
|
|
+ // linux平台下支持SO_REUSEPORT特性以提高性能
|
|
|
+ if (Epoll.isAvailable()) {
|
|
|
+ log.info("***Netty reuse port is activated");
|
|
|
+ bootstrap.option(EpollChannelOption.SO_REUSEPORT, true);
|
|
|
+ } else {
|
|
|
+ log.info("***Netty reuse port is not supported");
|
|
|
+ }
|
|
|
+
|
|
|
+ bossGroup = new EpollEventLoopGroup(workThreadNum);
|
|
|
+ bootstrap.group(bossGroup)
|
|
|
+ // 指定Channel
|
|
|
+ .channel(EpollDatagramChannel.class)
|
|
|
+// .option(ChannelOption.SO_BROADCAST, true)
|
|
|
+ .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
|
|
|
+ .handler(new ChannelInitializer<Channel>() {
|
|
|
+ @Override
|
|
|
+ public void initChannel(final Channel ch) throws Exception {
|
|
|
+ ChannelPipeline p = ch.pipeline();
|
|
|
+ p.addLast(new Encoder(), decoder);
|
|
|
+ p.addLast(nettyServerHandler);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ ChannelFuture future;
|
|
|
+ for(int i = 0; i < workThreadNum; ++i) {
|
|
|
+// future = bootstrap.bind(host, port).await();
|
|
|
+ future = bootstrap.bind(port).await();
|
|
|
+ if(!future.isSuccess()) {
|
|
|
+ log.info("[{}]成功启动 Netty Server,host:{} port: {}", i+1, host, port);
|
|
|
+ channel = future.channel();
|
|
|
+ } else {
|
|
|
+ if (future.cause() != null) {
|
|
|
+ future.cause().printStackTrace();
|
|
|
+ }
|
|
|
+ log.error(String.format("[%d]失败启动 Netty Server,host:%s port: %d error:%s", i+1, host, port,
|
|
|
+ future.cause()!=null?future.cause():""));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@PostConstruct
|
|
|
public void startCheckSendingQueue() {
|
|
|
int i = 0;
|
|
@@ -122,7 +190,7 @@ public class NettyServer {
|
|
|
|
|
|
@PreDestroy
|
|
|
public void destroy() {
|
|
|
- group.shutdownGracefully();
|
|
|
+ bossGroup.shutdownGracefully();
|
|
|
log.info("关闭Netty");
|
|
|
}
|
|
|
}
|