在Netty高并发下可能会突然出现Channel.isWritable 和Channel.isOpen的情况,主要是因为buffer缓冲区达到预设值。当buffer缓冲区大小超过高水位时,该Channel的isWritable状态为false变成不可发送; 当buffer缓冲区低于低水位线时,isWritable又会变回true,可以重新发送数据。
解决方法:
int lowWaterMark = (int) websocketProperties.getLowWaterMark().toBytes();
int highWaterMark = (int) websocketProperties.getHighWaterMark().toBytes();
//设置高低水位。当buffer缓冲区大小超过高水位时,该Channel的isWritable状态为false变成不可发送; 当buffer缓冲区低于低水位线时,isWritable又会变回true,可以重新发送数据
WriteBufferWaterMark writeBufferWaterMark = new WriteBufferWaterMark(lowWaterMark, highWaterMark);
//设置主从线程组
serverBootstrap.group(bossGroup, workerGroup)
//配置写入高低水位
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, writeBufferWaterMark);
Netty完整代码:
//创建netty服务器
ServerBootstrap serverBootstrap = new ServerBootstrap();
int lowWaterMark = (int) websocketProperties.getLowWaterMark().toBytes();
int highWaterMark = (int) websocketProperties.getHighWaterMark().toBytes();
//设置高低水位。当buffer缓冲区大小超过高水位时,该Channel的isWritable状态为false变成不可发送; 当buffer缓冲区低于低水位线时,isWritable又会变回true,可以重新发送数据
WriteBufferWaterMark writeBufferWaterMark = new WriteBufferWaterMark(lowWaterMark, highWaterMark);
//设置主从线程组
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(webSocketInitializer)
//socket参数,当服务器请求处理程全满时,用于临时存放已完成三次握手请求的队列的最大长度。如果未设置或所设置的值小于1,Java将使用默认值50。
.option(ChannelOption.SO_BACKLOG, 1024)
//启用心跳保活机制,tcp,默认2小时发一次心跳
.childOption(ChannelOption.SO_KEEPALIVE, true)
//配置写入高低水位
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, writeBufferWaterMark)
//接受数据buffer大小
.option(ChannelOption.SO_RCVBUF, 256 * 1024)
//发送数据buffer大小
.option(ChannelOption.SO_SNDBUF, highWaterMark);
//绑定端口,异步任务回调
ChannelFuture future = serverBootstrap.bind(websocketProperties.getPort())
.syncUninterruptibly();//同步等待
if (future != null && future.isSuccess()) {
// 获取通道
channel = future.channel();
log.info("WebSocket server start success,port={}", websocketProperties.getPort());
} else {
log.error("WebSocket server start fail");
}