iOS protobuf GCDAsyncSocket
iOS protobuf GCDAsyncSocket
我正在编写一个小应用程序,它需要通过 tcp 向 netty 服务器发送 protobuf 消息,其中使用了 CocoaAsyncSocket/GCDAsyncSocket。
为此,我使用以下代码:
Message_LoginMessageRequest_Builder *msg_tmp_login_build=[Message_LoginMessageRequest builder];
[msg_tmp_login_build setPhoneNumber:input_phone.text];
[msg_tmp_login_build setEmail:input_email.text];
[msg_tmp_login_build setPassword:input_password.text];
Message_Builder *msg_tmp_build=[Message builder];
[msg_tmp_build setType:Message_MessageTypeLoginReq];
[msg_tmp_build setLoginRequest:msg_tmp_login_build.build];
// send the message to the socket: we need to code the stream first
Message *msg=[msg_tmp_build build];
NSMutableData *msg_data=[[NSMutableData alloc] initWithCapacity:[[msg data] length]];
PBCodedOutputStream *coded_output_stream=[PBCodedOutputStream streamWithData:msg_data];
[msg writeToCodedOutputStream:coded_output_stream];
[socket writeData:msg_data withTimeout:-1 tag:Message_MessageTypeLoginReq];
但是,代码总是在writeToCodedOutputStream中收到"out of space"错误,其中详细的trace信息是:writeToCodedOutputStream/writeEnum/writeTag/writeRawVariant32/writeRawByte/flush.
有什么帮助吗?谢谢!
我自己找到了答案,通过阅读 protobuf 的 netty 编解码器代码,可以在 netty/codec/src/main/java/io/netty/handler/codec/protobuf/
中找到
在netty protobuf中,必须在消息体之前插入一个描述protobuf消息长度的消息头(后面会提到消息体)。消息体的长度必须通过 RawVariant32 类型进行编码。更详细的请参考ProtobufVariant32FrameDecoder.java中的例子,下面也引用:
/**
* A decoder that splits the received {@link ByteBuf}s dynamically by the
* value of the Google Protocol Buffers
* <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">Base
* 128 Varints</a> integer length field in the message. For example:
* <pre>
* BEFORE DECODE (302 bytes) AFTER DECODE (300 bytes)
* +--------+---------------+ +---------------+
* | Length | Protobuf Data |----->| Protobuf Data |
* | 0xAC02 | (300 bytes) | | (300 bytes) |
* +--------+---------------+ +---------------+
* </pre>
*
* @see CodedInputStream
*/
public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {
// TODO maxFrameLength + safe skip + fail-fast option
// (just like LengthFieldBasedFrameDecoder)
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
in.markReaderIndex();
final byte[] buf = new byte[5];
for (int i = 0; i < buf.length; i ++) {
if (!in.isReadable()) {
in.resetReaderIndex();
return;
}
buf[i] = in.readByte();
if (buf[i] >= 0) {
int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32();
if (length < 0) {
throw new CorruptedFrameException("negative length: " + length);
}
if (in.readableBytes() < length) {
in.resetReaderIndex();
return;
} else {
out.add(in.readBytes(length));
return;
}
}
}
// Couldn't find the byte whose MSB is off.
throw new CorruptedFrameException("length wider than 32-bit");
}
}
也欢迎您访问我的个人页面了解更多详情:http://167.88.47.13/?p=254
我正在编写一个小应用程序,它需要通过 tcp 向 netty 服务器发送 protobuf 消息,其中使用了 CocoaAsyncSocket/GCDAsyncSocket。
为此,我使用以下代码:
Message_LoginMessageRequest_Builder *msg_tmp_login_build=[Message_LoginMessageRequest builder];
[msg_tmp_login_build setPhoneNumber:input_phone.text];
[msg_tmp_login_build setEmail:input_email.text];
[msg_tmp_login_build setPassword:input_password.text];
Message_Builder *msg_tmp_build=[Message builder];
[msg_tmp_build setType:Message_MessageTypeLoginReq];
[msg_tmp_build setLoginRequest:msg_tmp_login_build.build];
// send the message to the socket: we need to code the stream first
Message *msg=[msg_tmp_build build];
NSMutableData *msg_data=[[NSMutableData alloc] initWithCapacity:[[msg data] length]];
PBCodedOutputStream *coded_output_stream=[PBCodedOutputStream streamWithData:msg_data];
[msg writeToCodedOutputStream:coded_output_stream];
[socket writeData:msg_data withTimeout:-1 tag:Message_MessageTypeLoginReq];
但是,代码总是在writeToCodedOutputStream中收到"out of space"错误,其中详细的trace信息是:writeToCodedOutputStream/writeEnum/writeTag/writeRawVariant32/writeRawByte/flush.
有什么帮助吗?谢谢!
我自己找到了答案,通过阅读 protobuf 的 netty 编解码器代码,可以在 netty/codec/src/main/java/io/netty/handler/codec/protobuf/
中找到在netty protobuf中,必须在消息体之前插入一个描述protobuf消息长度的消息头(后面会提到消息体)。消息体的长度必须通过 RawVariant32 类型进行编码。更详细的请参考ProtobufVariant32FrameDecoder.java中的例子,下面也引用:
/**
* A decoder that splits the received {@link ByteBuf}s dynamically by the
* value of the Google Protocol Buffers
* <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">Base
* 128 Varints</a> integer length field in the message. For example:
* <pre>
* BEFORE DECODE (302 bytes) AFTER DECODE (300 bytes)
* +--------+---------------+ +---------------+
* | Length | Protobuf Data |----->| Protobuf Data |
* | 0xAC02 | (300 bytes) | | (300 bytes) |
* +--------+---------------+ +---------------+
* </pre>
*
* @see CodedInputStream
*/
public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {
// TODO maxFrameLength + safe skip + fail-fast option
// (just like LengthFieldBasedFrameDecoder)
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
in.markReaderIndex();
final byte[] buf = new byte[5];
for (int i = 0; i < buf.length; i ++) {
if (!in.isReadable()) {
in.resetReaderIndex();
return;
}
buf[i] = in.readByte();
if (buf[i] >= 0) {
int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32();
if (length < 0) {
throw new CorruptedFrameException("negative length: " + length);
}
if (in.readableBytes() < length) {
in.resetReaderIndex();
return;
} else {
out.add(in.readBytes(length));
return;
}
}
}
// Couldn't find the byte whose MSB is off.
throw new CorruptedFrameException("length wider than 32-bit");
}
}
也欢迎您访问我的个人页面了解更多详情:http://167.88.47.13/?p=254