socket 测试工具_socket数据反序列化失败的问题

前言: 问题出自今年6月份, 当时做了一些整理, 记录到了自己的有道云笔记中,最近打算笔记搬到公众号, 顺带就重新再次记录下, 就当是重温了吧. 另外后续也会将笔记陆续搬过来, 同时也会重新拾起这个公众号, 谢谢大家

回归问题

场景:


使用netty作为socket服务器

使用机器人批量登录操作, 发送跑马灯

跑马灯类型: 公告

机器人数量: 500

测试工具是自己写的(socket客户端连接socket游服,
并对外提供websocket服务, 使用html页面连接websocket)

同时我这边还登录的个测试账号

问题说明

测试账户收到的数据如下

9e62b82682b9b4c7bad41940ea88f33b.png

自己测试客户端client解码输出正常

4d23051695842ddb85f510d05b1f15f5.png

服务器端发送出去的数据也正常, 如图

8e4d02190887637af657d8ac27a14c1c.png

也就是只有AIclient会报错

e6e9f39e92531973cdb39b9a7f66f972.png

上面报错的那段的内容如下

decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 2460, cap: 4096)
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
byte in: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 360, cap: 512)
gdddd
decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 30, cap: 64)
data: [8, 7, 16, 0, 26, 16, -26, -75, -117, -24, -81, -107, -27, -123, -84, -27, -111, -118, 45, 45, 45, 49]
decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 30, cap: 64)
data: [8, 7, 16, 0, 26, 16, -26, -75, -117, -24, -81, -107, -27, -123, -84, -27, -111, -118, 45, 45, 45, 49]
decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 810, cap: 1024)
gdddd
decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 90, cap: 128)
gdddd
decode in: PooledUnsafeDirectByteBuf(ridx: 0, widx: 30, cap: 64)
[17:55:07:509] [nioEventLoopGroup-3-8] [ERROR] - (GameCodecer.java:54) - decode
java.lang.IllegalStateException: Reading from a byte array threw an IOException (should never happen).反序列化类发生异常
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:94) ~[classes/:?]
at com.miguantech.common.netty.GameCodecer.decodeRec(GameCodecer.java:52) [classes/:?]
at com.miguantech.test.client.net.tcp.ClientDecodeHandler.decode(ClientDecodeHandler.java:72) [test-classes/:?]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:503) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:281) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_191]
Caused by: java.lang.RuntimeException: Reading from a byte array threw an IOException (should never happen).
at io.protostuff.IOUtil.mergeFrom(IOUtil.java:54) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ProtobufIOUtil.mergeFrom(ProtobufIOUtil.java:103) ~[protostuff-core-1.5.9.jar:1.5.9]
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:90) ~[classes/:?]
... 25 more
Caused by: io.protostuff.ProtobufException: Protocol message contained an invalid tag (zero).
at io.protostuff.ProtobufException.invalidTag(ProtobufException.java:106) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ByteArrayInput.readFieldNumber(ByteArrayInput.java:253) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.runtime.RuntimeSchema.mergeFrom(RuntimeSchema.java:457) ~[protostuff-runtime-1.5.9.jar:1.5.9]
at io.protostuff.IOUtil.mergeFrom(IOUtil.java:45) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ProtobufIOUtil.mergeFrom(ProtobufIOUtil.java:103) ~[protostuff-core-1.5.9.jar:1.5.9]
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:90) ~[classes/:?]
... 25 more

客户端的解码handler内容如

package com.miguantech.test.client.net.tcp;

import com.miguantech.common.netty.GameCodecer;
import com.miguantech.common.protocol.message.Message;
import com.miguantech.test.LocalLoggerUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.Arrays;
import java.util.List;

public class ClientDecodeHandler extends ByteToMessageDecoder {

// @Override
// protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception {
// if (buffer.readableBytes() >= 8) {
//
// System.out.println("decode in: " + buffer.toString());
// // 记录包头开始的index
// int beginReader;
// // 获取包头开始的index
// beginReader = buffer.readerIndex();
// // 标记包头开始的index
// buffer.markReaderIndex();
//
//
// // 消息的长度
// int length = buffer.readInt();
// int code = buffer.readInt();
// // 判断请求数据包数据是否到齐
// if (buffer.readableBytes() < length) {
// // 还原读指针
// buffer.readerIndex(beginReader);
// return;
// }
//
// Message decode = GameCodecer.decode(buffer, code, length);
// if (decode == null) {
LocalLoggerUtils.info("decode fail code:{}", code);
// buffer.readerIndex(beginReader);
// return;
// }
// out.add(decode);
buffer.resetReaderIndex();
//
// }
// }


@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {if(in.readableBytes() < 8){return;
}
System.out.println("decode in: " + in.toString());// System.out.println("decode in: " + Arrays.toString(in.array()));int begin = in.readerIndex();in.markReaderIndex();int length = in.readInt();int code = in.readInt();if(in.readableBytes() < length){in.resetReaderIndex();return;
}
Message msg = GameCodecer.decodeRec(in, code, length);if(msg == null){
System.out.println("gdddd");in.resetReaderIndex();return;
}out.add(msg);
}
}

自定义的编码规则如下GameCoderc

package com.miguantech.common.netty;

import com.miguantech.MessageDispatcher;
import com.miguantech.common.protocol.message.Message;
import com.miguantech.common.protocol.message.SCMessage;
import com.miguantech.common.utils.LoggerUtils;
import com.miguantech.common.utils.SerializationUtil;
import com.miguantech.protocol.sys.CSLogin;

import io.netty.buffer.ByteBuf;

import java.util.Arrays;

public class GameCodecer {

// ---4---|---4---|---len---|
// ---l---|---code|---data--|
// l:消息总长,用于半包
// len消息体长度, 用于读data

public static void encode(SCMessage message, ByteBuf out) {
System.out.println("bytes: " + Arrays.toString(message.getBytes()));
out.writeBytes(message.getBytes());
}

public static Message decode(ByteBuf in, int code, int len) {
try {
byte[] bytes = new byte[len];
Class extends Message> clazz = MessageDispatcher.getClazz(code);
if (clazz == null) {
return null;
}
in.readBytes(bytes, 0, len);
Message deserialize = SerializationUtil.deserialize(bytes, len, clazz);
return deserialize;
} catch (Exception e) {
LoggerUtils.errorLogger.error("decode", e);
}
return null;
}

public static Message decodeRec(ByteBuf buf, int code, int len){
// int dataLen = buf.readableBytes();
Class extends Message> clazz = MessageDispatcher.getClazz(code);
if(clazz == null){
return null;
}
byte[] data = new byte[len];
buf.readBytes(data, 0, len);
System.out.println("data: " + Arrays.toString(data));
try{
return SerializationUtil.deserialize(data, clazz);
}catch (Exception e){
LoggerUtils.errorLogger.error("decode", e);
}
return null;
}

}

序列化工具用的是protoStuff, 代码如下SerializeUtil

package com.miguantech.common.utils;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import io.protostuff.ProtostuffIOUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.objenesis.Objenesis;
import org.springframework.objenesis.ObjenesisStd;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtobufIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;

public class SerializationUtil {

private static Map, Schema>> cachedSchema = new ConcurrentHashMap<>();private static Objenesis objenesis = new ObjenesisStd(true);private static final ThreadLocal buffer = new ThreadLocal();private SerializationUtil() {
}
public static void initSchema(Class> cls) {if (!ArrayUtils.isEmpty(cls.getFields())) {
RuntimeSchema> createFrom = RuntimeSchema.createFrom(cls);
cachedSchema.put(cls, createFrom);
}
}
@SuppressWarnings("unchecked")
public static Schema getSchema(Classcls) {
Schema schema = (Schema) cachedSchema.get(cls);if (schema == null) {
schema = RuntimeSchema.createFrom(cls);if (schema != null) {
cachedSchema.put(cls, schema);
}
}
return schema;
}
@SuppressWarnings("unchecked")
public static byte[] serialize(T obj) {
Class cls = (Class) obj.getClass();
LinkedBuffer linkedBuffer = buffer.get();if(linkedBuffer == null){
linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
buffer.set(linkedBuffer);
}try {
Schema schema = getSchema(cls);
return ProtobufIOUtil.toByteArray(obj, schema, linkedBuffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
linkedBuffer.clear();
}
}
public static T deserialize(byte[] in, int len, Class cls) {try {
T obj = null;if (!ArrayUtils.isEmpty(cls.getDeclaredFields())) {
obj = (T) objenesis.newInstance(cls);if(len > 0){
Schema schema = getSchema(cls);ProtobufIOUtil.mergeFrom(in, 0, len, obj, schema);
}
}else{
obj = cls.newInstance();
}
return obj;
} catch (Exception e) {System.out.println("byte in: " + Arrays.toString(in));
throw new IllegalStateException(e.getMessage() + ",反序列化类发生异常:" + cls.getSimpleName()
+ ",byte数组长度:" + in.length + ",len:" + len, e);
}
}
public static T deserialize(byte[] bytes, Class cls){try {
T obj = cls.newInstance();
Schema schema = getSchema(cls);ProtobufIOUtil.mergeFrom(bytes, obj, schema);
return obj;
} catch (Exception e) {System.out.println("byte in: " + Arrays.toString(bytes));
throw new IllegalStateException(e.getMessage() + "反序列化类发生异常", e);
}
}
public static T deserialize(byte[] in, int offset, int len, Class cls) {try {
T obj = null;if (!ArrayUtils.isEmpty(cls.getDeclaredFields())) {
obj = (T) objenesis.newInstance(cls);if(len > 0){
Schema schema = getSchema(cls);ProtobufIOUtil.mergeFrom(in, offset, len, obj, schema);
}
}else{
obj = cls.newInstance();
}
return obj;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}

贼懵逼

到现在也还没找到方法解决

handle中注释的同名函数不是我写的, 当然也会报错

解决

接上一篇

目前的新进展 先看错误日志

以下是两次连续的错误

[15:32:39:383] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:54) - /127.0.0.1:61085 1 decode error data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[15:32:39:383] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:55) - /127.0.0.1:61085 1 decode error buf schema: PooledUnsafeDirectByteBuf(ridx: 30, widx: 30, cap: 512)
[15:32:39:383] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:56) - /127.0.0.1:61085 1 decode error code: 1532 len: 22
[15:32:39:384] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:57) - /127.0.0.1:61085 1 decode error
java.lang.IllegalStateException: Reading from a byte array threw an IOException (should never happen).反序列化类发生异常
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:93) ~[classes/:?]
at com.miguantech.common.netty.GameCodecer.decodeRec(GameCodecer.java:52) [classes/:?]
at com.miguantech.test.client.net.tcp.ClientDecodeHandler.decode(ClientDecodeHandler.java:88) [test-classes/:?]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:503) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:281) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_191]
Caused by: java.lang.RuntimeException: Reading from a byte array threw an IOException (should never happen).
at io.protostuff.IOUtil.mergeFrom(IOUtil.java:54) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ProtobufIOUtil.mergeFrom(ProtobufIOUtil.java:103) ~[protostuff-core-1.5.9.jar:1.5.9]
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:90) ~[classes/:?]
... 25 more
Caused by: io.protostuff.ProtobufException: Protocol message contained an invalid tag (zero).
at io.protostuff.ProtobufException.invalidTag(ProtobufException.java:106) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ByteArrayInput.readFieldNumber(ByteArrayInput.java:253) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.runtime.RuntimeSchema.mergeFrom(RuntimeSchema.java:457) ~[protostuff-runtime-1.5.9.jar:1.5.9]
at io.protostuff.IOUtil.mergeFrom(IOUtil.java:45) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ProtobufIOUtil.mergeFrom(ProtobufIOUtil.java:103) ~[protostuff-core-1.5.9.jar:1.5.9]
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:90) ~[classes/:?]
... 25 more
[15:32:39:389] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:90) - /127.0.0.1:61085 decode error in schema : PooledUnsafeDirectByteBuf(ridx: 30, widx: 30, cap: 512)
[15:32:39:389] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:91) - /127.0.0.1:61085 decode error , code: 1532 length: 22
[15:32:39:389] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:93) - /127.0.0.1:61085 decode error resetIndex after now: 0
[15:32:39:389] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:94) - /127.0.0.1:61085 已经接收个数num: 37
[0, 0, 0, 22, 0, 0, 5, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[15:32:39:411] [work-1-78] [INFO] - (LocalLoggerUtils.java:23) - WeightRandomSelectorImpl choose ActionBulletin
[15:32:39:411] [work-1-78] [INFO] - (LocalLoggerUtils.java:21) - 992816132391960587===》要不要执行:true
[15:32:39:417] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:54) - /127.0.0.1:61085 1 decode error data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[15:32:39:418] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:55) - /127.0.0.1:61085 1 decode error buf schema: PooledUnsafeDirectByteBuf(ridx: 30, widx: 60, cap: 512)
[15:32:39:418] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:56) - /127.0.0.1:61085 1 decode error code: 1532 len: 22
[15:32:39:418] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:57) - /127.0.0.1:61085 1 decode error
java.lang.IllegalStateException: Reading from a byte array threw an IOException (should never happen).反序列化类发生异常
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:93) ~[classes/:?]
at com.miguantech.common.netty.GameCodecer.decodeRec(GameCodecer.java:52) [classes/:?]
at com.miguantech.test.client.net.tcp.ClientDecodeHandler.decode(ClientDecodeHandler.java:88) [test-classes/:?]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:503) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:281) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.43.Final.jar:4.1.43.Final]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_191]
Caused by: java.lang.RuntimeException: Reading from a byte array threw an IOException (should never happen).
at io.protostuff.IOUtil.mergeFrom(IOUtil.java:54) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ProtobufIOUtil.mergeFrom(ProtobufIOUtil.java:103) ~[protostuff-core-1.5.9.jar:1.5.9]
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:90) ~[classes/:?]
... 25 more
Caused by: io.protostuff.ProtobufException: Protocol message contained an invalid tag (zero).
at io.protostuff.ProtobufException.invalidTag(ProtobufException.java:106) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ByteArrayInput.readFieldNumber(ByteArrayInput.java:253) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.runtime.RuntimeSchema.mergeFrom(RuntimeSchema.java:457) ~[protostuff-runtime-1.5.9.jar:1.5.9]
at io.protostuff.IOUtil.mergeFrom(IOUtil.java:45) ~[protostuff-core-1.5.9.jar:1.5.9]
at io.protostuff.ProtobufIOUtil.mergeFrom(ProtobufIOUtil.java:103) ~[protostuff-core-1.5.9.jar:1.5.9]
at com.miguantech.common.utils.SerializationUtil.deserialize(SerializationUtil.java:90) ~[classes/:?]
... 25 more
[15:32:39:418] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:90) - /127.0.0.1:61085 decode error in schema : PooledUnsafeDirectByteBuf(ridx: 30, widx: 60, cap: 512)
[15:32:39:419] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:91) - /127.0.0.1:61085 decode error , code: 1532 length: 22
[15:32:39:419] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:93) - /127.0.0.1:61085 decode error resetIndex after now: 0
[15:32:39:419] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:94) - /127.0.0.1:61085 已经接收个数num: 37
[0, 0, 0, 22, 0, 0, 5, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 5, -4, 8, 7, 16, 0, 26, 16, -26, -75, -117, -24, -81, -107, -27, -123, -84, -27, -111, -118, 45, 45, 45, 49]
[15:32:39:417] [work-1-78] [INFO] - (LocalLoggerUtils.java:21) - 992816132391960587===》ConditionIsLogin

ClientDecodeHandler

package com.miguantech.test.client.net.tcp;

import com.miguantech.common.netty.GameCodecer;
import com.miguantech.common.protocol.message.Message;
import com.miguantech.common.utils.LoggerUtils;
import com.miguantech.test.LocalLoggerUtils;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class ClientDecodeHandler extends ByteToMessageDecoder {

private static final Logger logger = LoggerFactory.getLogger(ClientDecodeHandler.class);

// 测试,key: localAddress, value: 从gameServer socket中已经接收的个数
// private static final TObjectIntHashMap localAddressNumMap = new TObjectIntHashMap<>();
private static final HashMap localAddressNumMap = new HashMap<>();
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {if(in.readableBytes() < 8){
return;
}
String localAdd = ctx.channel().localAddress().toString();in.markReaderIndex();int begin = in.readerIndex();int length = in.readInt();int code = in.readInt();if((length == 0 && code == 0) || in.readableBytes() < length){in.resetReaderIndex();
return;
}
Message msg = GameCodecer.decodeRec(in, code, length, localAdd);if(msg == null){LoggerUtils.errorLogger.error(localAdd + " decode error in schema : " + in.toString());LoggerUtils.errorLogger.error(localAdd + " decode error , code: " + code + " length: " + length);in.resetReaderIndex();LoggerUtils.errorLogger.error(localAdd + " decode error resetIndex after now: " + in.readerIndex());LoggerUtils.errorLogger.error(localAdd + " 已经接收个数num: " + getNumByAddress(localAdd));int wLen = in.writerIndex();
byte[] testByte = new byte[wLen];in.getBytes(begin, testByte);System.out.println(Arrays.toString(testByte));
return;
}
out.add(msg);
updateNumByAddress(localAdd);
}
public static int getNumByAddress(String address){if(localAddressNumMap.containsKey(address)){
return localAddressNumMap.get(address);
}
return 0;
}
public static void addNumByAddress(String address, int add){int oldNum = getNumByAddress(address);
localAddressNumMap.put(address, oldNum + add);
}
public static void updateNumByAddress(String address){
addNumByAddress(address, 1);
}
public static void removeAddress(String address){
localAddressNumMap.remove(address);
}
public static HashMap getChannelIdNumMap(){
return localAddressNumMap;
}
}

每次出现错误时, 我这边已经将readerIndex重置为原来的开始读的那个位置

并将当前已经写入的字节数据打印出来

int wLen = in.writerIndex();
byte[] testByte = new byte[wLen];
in.getBytes(begin, testByte);

System.out.println(Arrays.toString(testByte));

第一次打印如下

[0, 0, 0, 22, 0, 0, 5, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

第二次打印如下

[0, 0, 0, 22, 0, 0, 5, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 5, -4, 8, 7, 16, 0, 26, 16, -26, -75, -117, -24, -81, -107, -27, -123, -84, -27, -111, -118, 45, 45, 45, 49]

此前再说明下目前构造的包结构如下

---4---|---4---|---x---|
---a---|---b---|---c---|

首先
上面一行表示字节长度, 4表示4个字节长度

a: 数据c的长度数值, 占4个字节
b: 协议名字对应的int值, 占4个字节
c: 数据 字节数据

总的包字节个数 = 4 + 4 + x

从上面的输出中

[15:32:39:418] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:55) - /127.0.0.1:61085 1 decode error buf schema: PooledUnsafeDirectByteBuf(ridx: 30, widx: 60, cap: 512)
[15:32:39:418] [nioEventLoopGroup-3-12] [ERROR] - (GameCodecer.java:56) - /127.0.0.1:61085 1 decode error code: 1532 len: 22

也就可以看出第一个错误的包结构是正常的, 结构是正常, 所以会被认为是一个完整的包

故放进入进行解码解析

放进来后

public static Message decodeRec(ByteBuf buf, int code, int len, String localAdd){
Class extends Message> clazz = MessageDispatcher.getClazz(code);
if(clazz == null){
LoggerUtils.errorLogger.error(localAdd + " clazz空 code: " + code);
return null;
}
byte[] data = new byte[len];
buf.readBytes(data, 0, len);
try{
return SerializationUtil.deserialize(data, clazz);
}catch (Exception e){
LoggerUtils.errorLogger.error(localAdd + " 1 decode error data: " + Arrays.toString(data));
LoggerUtils.errorLogger.error(localAdd + " 1 decode error buf schema: " + buf.toString());
LoggerUtils.errorLogger.error(localAdd + " 1 decode error code: " + code + " len: " + len);
LoggerUtils.errorLogger.error(localAdd + " 1 decode error", e);
}
return null;
}

发现读取到的data这个字节数组里面的字节都是0, 故在SerializationUtil中反序列化时就报错了

SerializationUtil

package com.miguantech.common.utils;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import io.protostuff.ProtostuffIOUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.objenesis.Objenesis;
import org.springframework.objenesis.ObjenesisStd;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtobufIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;

public class SerializationUtil {

private static Map, Schema>> cachedSchema = new ConcurrentHashMap<>();private static Objenesis objenesis = new ObjenesisStd(true);private static final ThreadLocal buffer = new ThreadLocal();private SerializationUtil() {
}
@SuppressWarnings("unchecked")public static Schema getSchema(Class cls) {
Schema schema = (Schema) cachedSchema.get(cls);if (schema == null) {
schema = RuntimeSchema.createFrom(cls);if (schema != null) {
cachedSchema.put(cls, schema);
}
}return schema;
}
@SuppressWarnings("unchecked")public static byte[] serialize(T obj) {
Class cls = (Class) obj.getClass();
LinkedBuffer linkedBuffer = buffer.get();if(linkedBuffer == null){
linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
buffer.set(linkedBuffer);
}try {
Schema schema = getSchema(cls);return ProtobufIOUtil.toByteArray(obj, schema, linkedBuffer);
} catch (Exception e) {throw new IllegalStateException(e.getMessage(), e);
} finally {
linkedBuffer.clear();
}
}public static T deserialize(byte[] bytes, Class cls){try {
T obj = cls.newInstance();
Schema schema = getSchema(cls);
ProtobufIOUtil.mergeFrom(bytes, obj, schema);return obj;
} catch (Exception e) {throw new IllegalStateException(e.getMessage() + "反序列化类发生异常", e);
}
}
}

往后看, 可以看到第二个报错的位置, 打印的两个包中第二个包时正常的

这不免怀疑是服务器端发送的包有误, 序列化编码的时候出错..?

但是

我当前的测试场景是500个机器人, 加一个自己的测试账号

进行跑马灯功能的测试,会发现就只有一个账号报错(即所有的报错都是这个账号进程)

[15:32:39:389] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:93) - /127.0.0.1:61085 decode error resetIndex after now: 0
[15:32:39:389] [nioEventLoopGroup-3-12] [ERROR] - (ClientDecodeHandler.java:94) - /127.0.0.1:61085 已经接收个数num: 37

String localAdd = ctx.channel().localAddress().toString();

LoggerUtils.errorLogger.error(localAdd + " decode error resetIndex after now: " + in.readerIndex());
LoggerUtils.errorLogger.error(localAdd + " 已经接收个数num: " + getNumByAddress(localAdd));

socket进程标识/127.0.0.1:61085的这个账户会出现问题

而别的账户进程都收发都正常

服务器发送的包

15:32:41.673 [work-1-2] INFO  (SCMessage.java:28) - sc : SCPushMarquee :[8, 7, 16, 0, 26, 16, -26, -75, -117, -24, -81, -107, -27, -123, -84, -27, -111, -118, 45, 45, 45, 49]
bytes: [0, 0, 0, 22, 0, 0, 5, -4, 8, 7, 16, 0, 26, 16, -26, -75, -117, -24, -81, -107, -27, -123, -84, -27, -111, -118, 45, 45, 45, 49]

测试账号的接收信息如图

2d3f7d3e0dfc436e36f95a4f3047e4fc.png

出错账户信息

4eecb090de4a7dd36e745a433c1c2b4b.png

错误

ea71fe61863b1e308204a99d62ca1e89.png


update-1

进展

现在解决了

问题出在服务器端序列化操作, 一个对象进行重复性的序列化操作导致的

在高并发的情况下容易出现

如目前修改后的代码

351b55ab7530fd05bff48cb23a5d75fc.png

我在这里就增加了是否为null的判断

if (bytes != null){
    return;
}

如果进行这个判断, 就会出现字节数组全为0或者前后混乱的情况, 类似粘包的结构

3a31e0e2219207fad0e02a63d2ac82fe.png

28b368386d585d53334f3826e5cc1f9b.png这里再看下他的调用情况

33353b96c2bc4eba7dfae30b1ca613d4.png

发送SCMessage

public void send(SCMessage sc) {
sc.setSession(this); sc.serialize(); channel.writeAndFlush(sc);}

之后来到

056f338cc4d786ce0a357e8603fc4520.png

GameEncodeHandler是编码操作, 编码其实在serialize()函数中就完成了

GameEncodeHandler是继承MessageToByteEncoder, 它是一个向外发送消息时处理的一个类ChannelOutboundHandlerAdapter

这里就涉及到一个pipeline管道的东西了, 就先不记录了

之所以会走到GameEncodeHandler中来, 是在server中定义用到

f313b4fc8c544b348be84ae300523996.png

ok不扯了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值