Recientemente estoy escribiendo un proyecto de monitoreo de aplicaciones, usando netty como transmisión de datos. Como recién comencé a escribir, no usé Protobuf como herramienta de codificación, solo usé la propia de Netty LengthFieldBasedFrameDecoder
como herramienta de análisis de mensajes para personalizar las clases de codificación y decodificación para realizar la transmisión de datos.
Todo fue normal, como resultado, durante la prueba de ayer, el cuerpo de datos transmitido fue siempre de 16 caracteres menos, lo cual fue muy extraño.
Revisé el problema una y otra vez, y luego revisé cuidadosamente el contenido del mensaje, solo para encontrar que había 8 caracteres chinos en el mensaje. Solo entonces pensé que la longitud de bytes chinos no se puede obtener usando java.lang.String
un length()
método. Lo que debe usarse es el getBytes()
método para convertir en una matriz de bytes y length
obtener la longitud a través de los atributos de la matriz .
tal como:
"abcd".length()
El resultado es:
"abcd".getBytes().length
el resultado de 4 es: el resultado de 4 es:
"中国威武".length()
el resultado de 4 es:
"中国威武".getBytes().length
el resultado de 12 es:
"中国v5".length()
el resultado de 4
"中国v5".getBytes().length
es: 8
El ejemplo es simple, pero también puede ilustrar el problema. Aquí, la longitud de cada byte chino es 3 y las letras, números y puntuación en inglés son 1.
Entonces, en mi código de prueba, length()
la longitud de los 8 caracteres chinos obtenidos con el método es 8, que es getBytes()
16 menos que la longitud de la matriz de bytes del método, por lo que siempre faltan 16 caracteres durante el proceso de transmisión (la longitud del carácter en inglés es 1).
En general, debe prestar atención al convertir bytes a chino y no lo dé por sentado length()
. Todavía tengo que probar más según la situación específica. Triven marca este error
Adjunta el siguiente código:
Codificador: MessageEncoder
import cn.howardliu.monitor.cynomys.net.struct.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.CharsetUtil;
public class MessageEncoder extends MessageToByteEncoder<Message> {
@Override
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
if (msg == null || msg.getHeader() == null) {
throw new IllegalArgumentException("the encode message is null.");
}
out.writeInt(msg.getHeader().getCrcCode());
out.writeInt(msg.getHeader().getLength());
out.writeInt(msg.getHeader().getOpaque());
out.writeInt(msg.getHeader().getTag().length());
out.writeCharSequence(msg.getHeader().getTag(), CharsetUtil.UTF_8);
out.writeInt(msg.getHeader().getSysName().length());
out.writeCharSequence(msg.getHeader().getSysName(), CharsetUtil.UTF_8);
out.writeInt(msg.getHeader().getSysCode().length());
out.writeCharSequence(msg.getHeader().getSysCode(), CharsetUtil.UTF_8);
out.writeByte(msg.getHeader().getType());
out.writeByte(msg.getHeader().getCode());
out.writeByte(msg.getHeader().getFlagPath());
if (msg.getBody() == null) {
out.writeInt(0);
} else {
out.writeInt(msg.getBody().getBytes().length);
out.writeCharSequence(msg.getBody(), CharsetUtil.UTF_8);
}
out.setInt(4, out.readableBytes() - 8);
}
}
Decodificador: MessageDecoder
import cn.howardliu.monitor.cynomys.net.struct.Header;
import cn.howardliu.monitor.cynomys.net.struct.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.CharsetUtil;
public class MessageDecoder extends LengthFieldBasedFrameDecoder {
public MessageDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
}
@Override
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in);
if (frame == null) {
return null;
}
Message message = new Message()
.setHeader(
new Header()
.setCrcCode(frame.readInt())
.setLength(frame.readInt())
.setOpaque(frame.readInt())
.setTag(frame.readCharSequence(frame.readInt(), CharsetUtil.UTF_8).toString())
.setSysName(frame.readCharSequence(frame.readInt(), CharsetUtil.UTF_8).toString())
.setSysCode(frame.readCharSequence(frame.readInt(), CharsetUtil.UTF_8).toString())
.setType(frame.readByte())
.setCode(frame.readByte())
.setFlagPath(frame.readByte())
);
if (frame.readableBytes() > 4) {
message.setBody(frame.readCharSequence(frame.readInt(), CharsetUtil.UTF_8).toString());
}
return message;
}
}
La forma en que se usa el decodificador es new MessageDecoder(1024 * 1024 * 100, 4, 4)
.
Pega descaradamente la dirección de este proyecto, bienvenido estrella, fork y Tucao:
- Nombre del proyecto: cynomys
- Dirección del proyecto: https://github.com/howardliu-cn/cynomys
Página de inicio personal: http://www.howardliu.cn
Publicación de blog personal: pérdida de datos causada por la longitud de bytes chinos
Página de inicio de CSDN: http://blog.csdn.net/liuxinghao
Publicación de blog de CSDN: pérdida de datos causada por la longitud del byte chino