在客户端,我有一个工作正常的套接字发送Java对象:
Detail detail = new Detail(); //client object
Socket client = new Socket(host, port);
OutputStream out = client.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(detail);
oos.flush();
注意:这是客户端套接字,因此无法更改。
在服务器端,我有 camel-2.14.1 + Spring + netty4 ,在 Jboss AS7 中运行,具有这种简单的消费者风格:
from("netty4:tcp://0.0.0.0:6549?"+
"keepAlive=true&sync=true&decoder=#detailDecoder&encoder=#detailEncoder")
.log("server recive: ${body.getArea}")
.processRef("someDetailProcessor") //loaded with Spring
.log("response [${body.getArea}]");
我已经意识到我无法使用StringDecoder/StringEncoder
反序列化/序列化对象,因为这些编码器正在等待更多纯文本消息。
由于这个原因,我最终使用ObjectDecoder/ObjectEncoder
像这样注入它们:
<bean id="objDecoder" class="org.apache.camel.component.netty4.ChannelHandlerFactories" factory-method="newObjectDecoder">
<constructor-arg name="protocol" value="tcp"/>
</bean>
<bean id="objEncoder" class="org.apache.camel.component.netty4.ChannelHandlerFactories" factory-method="newObjectEncoder">
<constructor-arg name="protocol" value="tcp"/>
</bean>
但我的对象超出帧长度max,抛出异常 -
Closing channel as an exception was thrown from Netty. Caused by: [io.netty.handler.codec.TooLongFrameException - Adjusted frame length exceeds 1048576: 2901213193 - discarded]
我试图设置LengthFieldBasedFrameDecoder
(它是ObjectDecoder
的超类,并且还需要一个表示消息体长度的整数头字段,因此没有用处)。我也以不同的方式使用ByteToMessageDocoder
(通过创建我自己的类并尝试将ByteBuf
解码为详细信息),但根本没有幸运。
有谁知道如何实现这一目标?我只需要收到一个简单的对象,不应该那么难,应该是吗?
答案 0 :(得分:0)
好吧,经过一番努力,我想出了一个解决方法:
我决定使用 ReplayingDecoder
代替ObjectDecoder
和ByteToMessageDecoder
,因为:
ObjectDecoder
与ObjectOutputStream
(quote)ByteToMessaDecoder
ReplayingDecoder也有一些限制(均来自Netty in Action):
ByteBuf
上的所有操作,如果您调用不受支持的操作,则会抛出UnreplayableOperationException
。ByteBuf.readableBytes()
大部分时间都不会回复你的期望。因为我不知道消息的结尾是什么样的(如果我认为它适合DelimiterBasedFrameDecoder),也不知道每个到达包的长度(as it's said in this response),那么我最后将字节分组,做这样的事情:
// to collect the object bytes
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if(in.isReadable()){
// wrIdx - rdIdx instead of .readableBytes()
byte[] frame = new byte[in.writerIndex()-in.readerIndex()];
// I read just what I get, so the signal is never thrown
in.readBytes(frame);
// collecting bytes
baos.write(frame);
// it'll achieve this only when all the bytes from
// the incoming object have been collected
try{
out.add(SerializationUtils.deserialize(baos.toByteArray()));
}
catch(Exception e){}
}
}
TODO :
org.apache.commons.lang.SerializationUtils
更好的反序列化希望这可以帮助别人!