【问题标题】:iOS protobuf GCDAsyncSocketiOS protobuf GCDAsyncSocket
【发布时间】:2015-03-14 23:49:58
【问题描述】:

我正在编写一个小应用程序,它需要通过 tcp 将 protobuf 消息发送到 netty 服务器,其中使用了 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”错误,详细的跟踪信息是:writeToCodedOutputStream/writeEnum/writeTag/writeRawVariant32/writeRawByte/flush。

有什么帮助吗?谢谢!

【问题讨论】:

    标签: ios netty protocol-buffers gcdasyncsocket cocoaasyncsocket


    【解决方案1】:

    我自己已经找到了答案,通过阅读 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 2013-12-22
      • 1970-01-01
      相关资源
      最近更新 更多