C# 在结束组标记上调用的字段。GoogleProtobuf(C和C+;+;) 我试图用谷歌PROTO来对C++中的消息进行序列化,通过TCP套接字发送,最后在C客户端接收并解析。

C# 在结束组标记上调用的字段。GoogleProtobuf(C和C+;+;) 我试图用谷歌PROTO来对C++中的消息进行序列化,通过TCP套接字发送,最后在C客户端接收并解析。,c#,c++,tcp,winsock,protocol-buffers,C#,C++,Tcp,Winsock,Protocol Buffers,我一直在C#google proto解析器上遇到以下异常: SkipLastField在结束组标记上调用,表示缺少相应的开始组 我在发送之前和接收之后都打印了序列化的输入流,它的两端完全匹配 C#侦听器/反序列化器 namespace NetStreamHandler { public class Server { public static void ReceiveData() { var ipAddress = IPA

我一直在C#google proto解析器上遇到以下异常:

SkipLastField在结束组标记上调用,表示缺少相应的开始组

我在发送之前和接收之后都打印了序列化的输入流,它的两端完全匹配

C#侦听器/反序列化器

 namespace NetStreamHandler
{
    public class Server
    {
        public static void ReceiveData()
        {
            var ipAddress = IPAddress.Parse("127.0.0.1");
            var listener = new TcpListener(ipAddress, 20511);
            listener.Start();
            listener.BeginAcceptSocket(MessageReceived, listener);
        }

        private static void MessageReceived(IAsyncResult result)
        {
            var server = (TcpListener)result.AsyncState;
            using (var client = server.EndAcceptTcpClient(result))
            using (var stream = client.GetStream())
            {
                try
                {
                    var cod = new CodedInputStream(stream);
                    var packet = Serialize.Parser.ParseFrom(cod);
                    Console.WriteLine($"Message: {packet.ToString()}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception Caught at: {ex.Message}\n");
                }
            }
        }

    }
}
C++发送/序列化

int bCount;
Serialized::Serialize pLoad;
pLoad.set_command("Test");
pLoad.set_id(10);
pLoad.set_num(3);
pLoad.set_packettype(1);
pLoad.set_ret("Test");

printf("Size after serializing: %d bytes\n", pLoad.ByteSize());
auto size = pLoad.ByteSize();
auto packet = new char[size];
ArrayOutputStream ArrayOut(packet, size);
auto coutput = new CodedOutputStream(&ArrayOut);
coutput->WriteVarint32(pLoad.ByteSize());
pLoad.SerializeToCodedStream(coutput);
auto sConnect = SetupSocket();
if (!sConnect) { printf("Socket failure\n"); goto DONE; }
std::cout << "Buffer:" << byte_2_str(packet, size) << std::endl;


bCount = send(sConnect, packet, size, 0);
if(bCount == SOCKET_ERROR)
{
    fprintf(stderr, "Server: send() failed: error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
    goto DONE;
}
else if (bCount == -1) {
    fprintf(stderr, "Error sending data %d\n", errno);
    goto DONE;

}
else {
    printf("Sent bytes %d\n", bCount);
}

DONE:
closesocket(sConnect);
printf("All done..\n");
intbcount;
序列化::序列化pLoad;
pLoad.set_命令(“测试”);
pLoad.set_id(10);
pLoad.set_num(3);
pLoad.set_packettype(1);
pLoad.set_ret(“测试”);
printf(“序列化后的大小:%d字节\n”,pLoad.ByteSize());
自动大小=pLoad.ByteSize();
自动数据包=新字符[大小];
arrayoutputstreamarrayout(数据包、大小);
自动输出=新代码输出流(&ArrayOut);
coutput->WriteVarint32(pLoad.ByteSize());
pLoad.SerializeToCodedStream(coutput);
自动连接=SetupSocket();
如果(!sConnect){printf(“套接字失败\n”);转到完成;}

std::cout您只为绑定到CodedOutputStream的ArrayOut中使用的缓冲区分配了有效负载大小字节。但您试图写得稍微多一些(有效负载大小+大小(Varint32)。我想您需要有足够大的缓冲区来存储具有消息长度的有效负载

我使用PoCO框架。下面是C++示例代码:

void writeDelimitedTo(const google::protobuf::MessageLite& message, Poco::Net::StreamSocket& socket) {
    int totalMsgSize = message.ByteSize()+4; // Variant32 length 1-4
    char *buf = new char [totalMsgSize];
    ArrayOutputStream aos(buf, totalMsgSize);
    CodedOutputStream coded_output(&aos);
    coded_output.WriteVarint32(message.ByteSize());
    message.SerializeToCodedStream(&coded_output);
    socket.sendBytes(buf, coded_output.ByteCount());
    delete buf;
}
当然,c#部分只是使用System.Io.Stream作为clientStream.ProtoMsgStructRequest和protomsgstructrensponse是ProtoBuf消息:

using (var pbReader = new Google.Protobuf.CodedInputStream(clientStream, true))
{
    var inRequest = new ProtoMsgStructRequest();
    pbReader.ReadMessage(inRequest);
    {
        var outResponse = new ProtoMsgStructResponse();
        using (var pbWriter = new Google.Protobuf.CodedOutputStream(clientStream, true))
        {
            pbWriter.WriteMessage(outResponse);
        }
    }
}

在开始解析之前,您是否已收到所有消息?服务器可以发送8000字节,但在TCP中无法保证它将在一个数据包中接收,例如它可能作为两个4000字节的数据包接收。
stream.Read(…)
将读取4000字节并返回4000字节,然后再次调用4000字节,最后一次调用时返回0,表示没有剩余数据可读取。