202 lines
6.5 KiB
Java
202 lines
6.5 KiB
Java
|
|
package com.netty;
|
||
|
|
|
||
|
|
import io.netty.bootstrap.Bootstrap;
|
||
|
|
import io.netty.bootstrap.ServerBootstrap;
|
||
|
|
import io.netty.channel.ChannelFuture;
|
||
|
|
import io.netty.channel.ChannelOption;
|
||
|
|
import io.netty.channel.EventLoopGroup;
|
||
|
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||
|
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||
|
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||
|
|
import org.slf4j.Logger;
|
||
|
|
import org.slf4j.LoggerFactory;
|
||
|
|
|
||
|
|
import java.util.concurrent.CountDownLatch;
|
||
|
|
import java.util.concurrent.ExecutorService;
|
||
|
|
import java.util.concurrent.Executors;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Syslog 服务器主类,支持 TCP 和 UDP 协议
|
||
|
|
*/
|
||
|
|
public class SyslogServerBoth {
|
||
|
|
private static final Logger logger = LoggerFactory.getLogger(SyslogServer.class);
|
||
|
|
|
||
|
|
private final int tcpPort;
|
||
|
|
private final int udpPort;
|
||
|
|
|
||
|
|
// 共享的EventLoopGroup以优化资源使用
|
||
|
|
private EventLoopGroup bossGroup;
|
||
|
|
private EventLoopGroup workerGroup;
|
||
|
|
private EventLoopGroup udpGroup;
|
||
|
|
|
||
|
|
private ChannelFuture tcpChannelFuture;
|
||
|
|
private ChannelFuture udpChannelFuture;
|
||
|
|
|
||
|
|
private final ExecutorService serverExecutor = Executors.newFixedThreadPool(2);
|
||
|
|
|
||
|
|
public SyslogServerBoth(int tcpPort, int udpPort) {
|
||
|
|
this.tcpPort = tcpPort;
|
||
|
|
this.udpPort = udpPort;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void start() throws InterruptedException {
|
||
|
|
logger.info("Starting Syslog server with TCP port {} and UDP port {}", tcpPort, udpPort);
|
||
|
|
|
||
|
|
// 创建共享的EventLoopGroup
|
||
|
|
bossGroup = new NioEventLoopGroup(1);
|
||
|
|
workerGroup = new NioEventLoopGroup();
|
||
|
|
udpGroup = new NioEventLoopGroup();
|
||
|
|
|
||
|
|
final CountDownLatch latch = new CountDownLatch(2);
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 启动UDP服务器(使用独立的线程)
|
||
|
|
serverExecutor.submit(() -> {
|
||
|
|
try {
|
||
|
|
startUdpServer();
|
||
|
|
latch.countDown();
|
||
|
|
} catch (Exception e) {
|
||
|
|
logger.error("UDP server failed to start", e);
|
||
|
|
latch.countDown();
|
||
|
|
throw new RuntimeException(e);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// 启动TCP服务器(使用独立的线程)
|
||
|
|
serverExecutor.submit(() -> {
|
||
|
|
try {
|
||
|
|
startTcpServer();
|
||
|
|
latch.countDown();
|
||
|
|
} catch (Exception e) {
|
||
|
|
logger.error("TCP server failed to start", e);
|
||
|
|
latch.countDown();
|
||
|
|
throw new RuntimeException(e);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// 等待两个服务器都启动完成
|
||
|
|
latch.await();
|
||
|
|
logger.info("Both TCP and UDP Syslog servers are running");
|
||
|
|
|
||
|
|
// 注册关闭钩子
|
||
|
|
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
|
||
|
|
|
||
|
|
// 保持主线程运行
|
||
|
|
Thread.currentThread().join();
|
||
|
|
|
||
|
|
} catch (Exception e) {
|
||
|
|
logger.error("Failed to start servers", e);
|
||
|
|
shutdown();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void startTcpServer() throws InterruptedException {
|
||
|
|
ServerBootstrap b = new ServerBootstrap();
|
||
|
|
b.group(bossGroup, workerGroup)
|
||
|
|
.channel(NioServerSocketChannel.class)
|
||
|
|
.childHandler(new SyslogTcpChannelInitializer())
|
||
|
|
.option(ChannelOption.SO_BACKLOG, 128)
|
||
|
|
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||
|
|
|
||
|
|
tcpChannelFuture = b.bind(tcpPort).sync();
|
||
|
|
logger.info("TCP Syslog server started on port {}", tcpPort);
|
||
|
|
|
||
|
|
// 添加关闭监听器
|
||
|
|
tcpChannelFuture.channel().closeFuture().addListener(future -> {
|
||
|
|
if (future.isSuccess()) {
|
||
|
|
logger.info("TCP server channel closed");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private void startUdpServer() throws InterruptedException {
|
||
|
|
Bootstrap b = new Bootstrap();
|
||
|
|
b.group(udpGroup)
|
||
|
|
.channel(NioDatagramChannel.class)
|
||
|
|
.handler(new SyslogUdpChannelInitializer())
|
||
|
|
.option(ChannelOption.SO_BROADCAST, true);
|
||
|
|
|
||
|
|
udpChannelFuture = b.bind(udpPort).sync();
|
||
|
|
logger.info("UDP Syslog server started on port {}", udpPort);
|
||
|
|
|
||
|
|
// 添加关闭监听器
|
||
|
|
udpChannelFuture.channel().closeFuture().addListener(future -> {
|
||
|
|
if (future.isSuccess()) {
|
||
|
|
logger.info("UDP server channel closed");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 优雅关闭服务器
|
||
|
|
*/
|
||
|
|
public void shutdown() {
|
||
|
|
logger.info("Shutting down Syslog servers...");
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 关闭TCP服务器
|
||
|
|
if (tcpChannelFuture != null) {
|
||
|
|
tcpChannelFuture.channel().close().sync();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 关闭UDP服务器
|
||
|
|
if (udpChannelFuture != null) {
|
||
|
|
udpChannelFuture.channel().close().sync();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 关闭EventLoopGroup
|
||
|
|
if (bossGroup != null) {
|
||
|
|
bossGroup.shutdownGracefully().sync();
|
||
|
|
}
|
||
|
|
if (workerGroup != null) {
|
||
|
|
workerGroup.shutdownGracefully().sync();
|
||
|
|
}
|
||
|
|
if (udpGroup != null) {
|
||
|
|
udpGroup.shutdownGracefully().sync();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 关闭线程池
|
||
|
|
serverExecutor.shutdown();
|
||
|
|
|
||
|
|
logger.info("Syslog servers shutdown complete");
|
||
|
|
} catch (Exception e) {
|
||
|
|
logger.error("Error during shutdown", e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 检查服务器是否在运行
|
||
|
|
*/
|
||
|
|
public boolean isRunning() {
|
||
|
|
return (tcpChannelFuture != null && tcpChannelFuture.channel().isActive()) ||
|
||
|
|
(udpChannelFuture != null && udpChannelFuture.channel().isActive());
|
||
|
|
}
|
||
|
|
|
||
|
|
public static void main(String[] args) throws Exception {
|
||
|
|
int tcpPort = 514;
|
||
|
|
int udpPort = 514;
|
||
|
|
|
||
|
|
// 解析命令行参数
|
||
|
|
if (args.length >= 1) {
|
||
|
|
tcpPort = Integer.parseInt(args[0]);
|
||
|
|
}
|
||
|
|
if (args.length >= 2) {
|
||
|
|
udpPort = Integer.parseInt(args[1]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 如果两个端口相同,UDP端口自动+1避免冲突
|
||
|
|
if (tcpPort == udpPort) {
|
||
|
|
udpPort = tcpPort + 1;
|
||
|
|
logger.warn("TCP and UDP ports cannot be the same. UDP port changed to {}", udpPort);
|
||
|
|
}
|
||
|
|
|
||
|
|
SyslogServerBoth server = new SyslogServerBoth(tcpPort, udpPort);
|
||
|
|
|
||
|
|
// 注册全局异常处理器
|
||
|
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||
|
|
logger.error("Uncaught exception in thread {}", t.getName(), e);
|
||
|
|
});
|
||
|
|
|
||
|
|
server.start();
|
||
|
|
}
|
||
|
|
}
|