netty server端使用自定义解码器,通过存储client连接实现主动推送消息,并发送自定义心跳包
Server端
依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.19.Final</version>
</dependency>
创建服务端
@Component
public class NettyServer {
@Autowired
private ServiceConfiguration serviceConfiguration;
private EventLoopGroup bossGroup = new NioEventLoopGroup();
private EventLoopGroup workGroup = new NioEventLoopGroup();
@PostConstruct
public void start() throws Exception {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.SO_REUSEADDR, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new IdleStateHandler(0, 0, 5, TimeUnit.SECONDS));
socketChannel.pipeline().addLast("messageHandler", new MessageHandler());
socketChannel.pipeline().addLast("serverHandler", new ServerHandler());
}
});
ChannelFuture future = b.bind(serviceConfiguration.getAddress(), serviceConfiguration.getClientPort()).sync();
if (future.isSuccess()) {
System.out.println("IP:" + serviceConfiguration.getAddress() + "端口" + serviceConfiguration.getClientPort() + "启动监听成功");
}
}
@PreDestroy
public void destroy() {
bossGroup.shutdownGracefully().syncUninterruptibly();
workGroup.shutdownGracefully().syncUninterruptibly();
System.out.println("关闭 Netty 成功");
}
ServerHandler
@Component
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Autowired
private ServiceConfiguration serviceConfiguration;
public static Map<String, ChannelHandlerContext> realMap = new ConcurrentHashMap<>();
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
sendHeart(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Disconnected client." + ctx.channel().remoteAddress().toString());
String ipAddress = getContext(ctx);
if (realMap.containsKey(ipAddress)) {
realMap.remove(ipAddress);
}
ctx.fireChannelInactive();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
if (realMap.size() > 1) {
realMap.clear();
sendHeart(ctx);
} else {
byte[] bytes = (byte[]) msg;
String s = getMessage(bytes);
if (s.contains("heartbeats")) {
System.out.println(s);
HeartBeat heartBeat = JsonUtil.json2Object(s, HeartBeat.class);
System.out.println(heartBeat);
System.out.println("接收到的数据" + ByteCopyUtil.toHexString(bytes));
if(realMap.size() != 1){
realMap.put(getContext(ctx), ctx);
}
} else {
System.out.println("接收到的数据" + ByteCopyUtil.toHexString(bytes));
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void userEventTriggered(ChannelHandlerContext context, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleState state = ((IdleStateEvent) evt).state();
if (state == IdleState.ALL_IDLE) {
sendHeart(context);
}
}
}
public String getContext(ChannelHandlerContext context) {
InetSocketAddress ipSocket = (InetSocketAddress) context.channel().remoteAddress();
String clientIp = ipSocket.getAddress().getHostAddress();
System.out.println("客户端ip地址" + clientIp);
return clientIp;
}
public int sendMessage(String jsonObj) {
if (realMap.size() == 1) {
realMap.get(serviceConfiguration.getAddress()).writeAndFlush(SendJsonObj.getBuf(jsonObj));
return 1;
} else if (realMap.size() > 1) {
return -1;
} else {
return 0;
}
}
public void sendMessageData(String ipAddress,String jsonObj) {
realMap.get(ipAddress).writeAndFlush(SendJsonObj.getBuf(jsonObj));
}
public void sendHeart(ChannelHandlerContext context) {
HeartBeat heartBeat = new HeartBeat("heartbeats");
String s = JsonUtil.object2Json(heartBeat);
context.writeAndFlush(SendJsonObj.getBuf(s));
}
public int getMessageLen(byte[] bytes) {
if (bytes.length > 8) {
byte[] len = new byte[4];
len[0] = bytes[4];
len[1] = bytes[5];
len[2] = bytes[6];
len[3] = bytes[7];
return BitConverter.toInt(len) - 17;
} else {
return -1;
}
}
public String getMessage(byte[] bytes) {
int len = getMessageLen(bytes);
byte[] message = new byte[len];
try {
for (int i = 0; i < len; i++) {
message[i] = bytes[i + 16];
}
String s = JsonUtil.object2Json(new String(message));
return s;
} catch (Exception e) {
e.printStackTrace();
return "getMessageFail";
}
}
MessageHandler(自定义解码器)
@Component
public class MessageHandler extends ByteToMessageDecoder {
private ByteBuf tempMessage = Unpooled.buffer();
public MessageHandler() {
this.tempMessage.writeInt(0x00000000);
}
@Override
protected void decode(ChannelHandlerContext context, ByteBuf input, List<Object> output) throws Exception {
while (true) {
int index = IndexOf(input, tempMessage);
if (index == -1) {
return;
} else if (index != 0) {
input.skipBytes(index);
}
if (input.readableBytes() < 8) {
return;
}
input.markReaderIndex();
int length = 0;
ByteBuf b = input.skipBytes(4).readBytes(4);
byte[] bs = new byte[b.readableBytes()];
b.readBytes(bs);
b.release();
length = BitConverter.ToInt32(bs, 0);
input.resetReaderIndex();
if (length < 0) {
input.skipBytes(4);
return;
}
if (input.readableBytes() >= (length)) {
byte[] bb = new byte[length];
input.readBytes(bb);
output.add(bb);
} else {
return;
}
}
}
static int IndexOf(ByteBuf haystack, ByteBuf needle) {
for (int i = haystack.readerIndex(); i < needle.writerIndex(); i++) {
int haystackIndex = i;
int needleIndex;
for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex++) {
if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
break;
} else {
haystackIndex++;
if (haystackIndex == haystack.writerIndex() && needleIndex != 3) {
return -1;
}
}
}
if (needleIndex == 4) {
return i - haystack.readerIndex();
}
}
return -1;
}