2016-05-23 38 views
1

我想使用谷歌proto在C++中序列化消息,通過TCP套接字發送它,最後接收並解析它在C#客戶端。SkipLastField在終端組標籤上調用。 GoogleProtobuf(C#和C++)

我一直得到在C#谷歌原解析器以下例外:

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"); 
+0

你收到的所有消息的您開始解析之前,服務器可以發送? 8000字節,但沒有保證TCP將在一個數據包中收到它,例如,它可能會被接收爲兩個4000字節的數據包。 'stream.Read(...)'將讀取4000字節並返回4000,然後再次調用4000,然後在最終調用時返回0以指示沒有數據要讀取。 –

回答

1

您已分配的唯一的有效載荷大小的字節在ArrayOut使用的緩衝液是結合到CodedOutputStream。但是你試圖寫稍多(有效載荷大小+(Varint32)的大小猜你需要有緩衝器足夠大以存儲有效載荷與信息長度

我使用波索框架這裏是低於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; 
} 

只是用System.Io.Stream作爲clientStream ProtoMsgStructRequest和ProtoMsgStructResponse當然C#部分,並且是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); 
     } 
    } 
}