配置类
import cn.hutool.core.thread.ThreadUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
@Component
@Slf4j
public class NettyServerConfig {
@Resource
private BizHandler bizHandler;
@Value("${netty.port}")
private int port;
@PostConstruct
public void start(){
ThreadUtil.newSingleExecutor().execute(this::doStart);
}
public void doStart(){
ServerBootstrap serverBootstrap = new ServerBootstrap();
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
serverBootstrap.group(bossGroup,workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel socketChannel) {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addFirst(bizHandler);
}
});
ChannelFuture channelFuture;
try {
channelFuture = serverBootstrap.bind(port).sync();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
channelFuture.addListener(future -> {
if(future.isSuccess()){
log.info("netty服务 启动成功");
}
});
ChannelFuture closeFuture = channelFuture.channel().closeFuture();
try {
closeFuture.sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
处理器
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Slf4j
@Service
@ChannelHandler.Sharable
public class BizHandler extends ChannelInboundHandlerAdapter {
private static final String SPACE = " ";
private static final ConcurrentHashMap<ChannelHandlerContext, String> channelContextMap = new ConcurrentHashMap<>();
public void send(){
channelContextMap.entrySet().forEach(e -> {
ChannelHandlerContext context = e.getKey();
ByteBuf buf = context.alloc().buffer();
byte[] dataFrame = generateDataFrame();
buf.writeBytes(dataFrame);
context.channel().writeAndFlush(buf);
});
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buffer = (ByteBuf) msg;
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes);
String msgHexStr = this.byteArrayToHexString(bytes);
//如果不是预期的连接发过来消息 主动断开连接
//ctx.channel().close();
ctx.fireChannelRead(msg);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
channelContextMap.remove(ctx);
}
private String byteArrayToHexString(byte[] bytes) {
List<String> dataFrame = Lists.newArrayList();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
// 如果是一位的话,要补0
hex = "0" + hex;
}
dataFrame.add(hex.toUpperCase());
}
return dataFrame.stream().collect(Collectors.joining(SPACE));
}
}