Appearance
本篇将根据Netty服务端模板代码编写启动类,并实现标准启动和支持websocket协议的服务端;服务端的端口、线程数等参数将用过yml文件动态传递,yml文件将通过main方法的args数组在启动时传递。
xml
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.92.Final</version>
</dependency>
Netty启动服务模板代码
java
public class XimServer {
private final static Logger logger = LoggerFactory.getLogger(XimServer.class);
private int port;
public XimServer(int port) {
this.port = port;
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小
.option(ChannelOption.SO_REUSEADDR, true) // 允许重复使用本地地址和端口
.option(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法,简单理解成是否允许批量发送数据,开启会影响消息及时性
.option(ChannelOption.SO_KEEPALIVE, true) //保活
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
}
});
server.bind(port);
}
}
使用WebSocket协议
Netty自带对WebSocket的支持,添加Netty提供Handler的即可。
java
public class XimWebSocketServer {
private final static Logger logger = LoggerFactory.getLogger(XimWebSocketServer.class);
private int port;
public XimWebSocketServer(int port) {
this.port = port;
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小
.option(ChannelOption.SO_REUSEADDR, true) // 允许重复使用本地地址和端口
.option(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法,简单理解成是否允许批量发送数据,开启会影响消息及时性
.option(ChannelOption.SO_KEEPALIVE, true) //保活
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// websocket 基于http协议,所以要有http编解码器
pipeline.addLast("http-codec", new HttpServerCodec());
// 对写大数据流的支持
pipeline.addLast("http-chunked", new ChunkedWriteHandler());
// 几乎在netty中的编程,都会使用到此hanler
pipeline.addLast("aggregator", new HttpObjectAggregator(65535));
/*
websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
本handler会帮你处理一些繁重的复杂的事
会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳
对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同
*/
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
}
});
server.bind(port);
}
}
Main方法
java
public class Starter {
public static void main(String[] args) {
new XimServer(9001);
new XimWebSocketServer(19001);
}
}
使用yaml动态配置
在resources目录下新建config.yml文件
yaml
xim:
tcpPort: 9000
webSocketPort: 19000
bossThreadSize: 1
workThreadSize: 4
创建对象BootstrapConfig
,这里面的数据将通过yml文件在启动时传入。
java
@Data
public class BootstrapConfig {
private TcpConfig xim;
@Data
public static class TcpConfig {
private Integer tcpPort;
private Integer webSocketPort;
private Integer bossThreadSize;
private Integer workThreadSize;
}
}
先配置依赖文件:
xml
<!-- yaml解析 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
在Main文件读取
java
public class Starter {
public static void main(String[] args) throws FileNotFoundException {
Yaml yaml = new Yaml();
FileInputStream inputStream = new FileInputStream("D:\\code\\javaCode\\Year2023\\month02\\im-system\\im-tcp\\src\\main\\resources\\config.yml");
BootstrapConfig bootstrapConfig = yaml.loadAs(inputStream, BootstrapConfig.class);
System.out.println(bootstrapConfig);
}
}
使用yaml动态配置后启动程序改造
java
public class XimServer {
private final static Logger logger = LoggerFactory.getLogger(XimServer.class);
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
private final ServerBootstrap server;
private final BootstrapConfig.TcpConfig config;
public XimServer(BootstrapConfig.TcpConfig config) {
this.config = config;
bossGroup = new NioEventLoopGroup(config.getBossThreadSize());
workerGroup = new NioEventLoopGroup(config.getWorkThreadSize());
server = new ServerBootstrap();
server.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小
.option(ChannelOption.SO_REUSEADDR, true) // 允许重复使用本地地址和端口
.option(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法,简单理解成是否允许批量发送数据,开启会影响消息及时性
.option(ChannelOption.SO_KEEPALIVE, true) //保活
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
}
});
}
public void start() {
this.server.bind(this.config.getTcpPort());
}
}
websocket也类似
java
public class XimWebSocketServer {
private final static Logger logger = LoggerFactory.getLogger(XimWebSocketServer.class);
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
private final ServerBootstrap server;
private final BootstrapConfig.TcpConfig config;
public XimWebSocketServer(BootstrapConfig.TcpConfig config) {
this.config = config;
bossGroup = new NioEventLoopGroup(config.getBossThreadSize());
workerGroup = new NioEventLoopGroup(config.getWorkThreadSize());
server = new ServerBootstrap();
server.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小
.option(ChannelOption.SO_REUSEADDR, true) // 允许重复使用本地地址和端口
.option(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法,简单理解成是否允许批量发送数据,开启会影响消息及时性
.option(ChannelOption.SO_KEEPALIVE, true) //保活
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// websocket 基于http协议,所以要有http编解码器
pipeline.addLast("http-codec", new HttpServerCodec());
// 对写大数据流的支持
pipeline.addLast("http-chunked", new ChunkedWriteHandler());
// 几乎在netty中的编程,都会使用到此hanler
pipeline.addLast("aggregator", new HttpObjectAggregator(65535));
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
}
});
}
public void start() {
this.server.bind(this.config.getTcpPort());
}
}
启动类如下,配置文件路径通过启动参数传递。
java
public class Starter {
public static void main(String[] args) throws FileNotFoundException {
if (args.length > 0) {
start(args[0]);
}
}
private static void start(String path) {
try {
Yaml yaml = new Yaml();
FileInputStream inputStream = new FileInputStream(path);
BootstrapConfig bootstrapConfig = yaml.loadAs(inputStream, BootstrapConfig.class);
System.out.println(bootstrapConfig);
new XimServer(bootstrapConfig.getXim()).start();
new XimWebSocketServer(bootstrapConfig.getXim()).start();
} catch (Exception e) {
e.printStackTrace();
// 如果有错误,直接退出整个程序
System.exit(500);
}
}
}
IDEA中如何配置启动参数?