簡體   English   中英

在 C# 中讀取 Protobuf 消息

[英]Reading a Protobuf Message in C#

我有一個簡單的消息:

package test;

message sendName {  
  optional string username = 1; 
}

很棒的 VS 插件生成.cs文件:

namespace test {  

    [global::System.Serializable global::ProtoBuf.ProtoContract(Name=@"sendName")]

    public partial class sendName : global::ProtoBuf.IExtensible {

        public sendName() {}    

        private string _username = "";
        [global::ProtoBuf.ProtoMember(1, IsRequired = false, Name=@"username", DataFormat = > global::ProtoBuf.DataFormat.Default)]
        [global::System.ComponentModel.DefaultValue("")]
        public string username
        {
            get { return _username; }
            set { _username = value; }
        }

        private global::ProtoBuf.IExtension extensionObject;

        global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
        {
            return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
        }
    }
}

我正在通過使用從 java 端發送消息

objName.build().writeTo((FileOutputStream)socket.getOutputStream());

在我的 C# 應用程序中,它的作用類似於 Socket Listener,我有一個名為 Listen 的方法,它偵聽 java 客戶端發送的消息:

public void Listen()
{

    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    TcpListener listener = new TcpListener(ipAddress, 4055);
    TcpClient client = null;

    listener.Start();

    while (true)
    {
        Debug.WriteLine("Waiting for a Connection");

        client = listener.AcceptTcpClient();

        Stream stream = client.GetStream();

        // sendName sendNameObj = Serializer.Deserialize<sendName>(stream);
    }
}

我顯然在這里缺少一些基礎知識。

我應該使用什么方法來獲取 sendName 對象?


當我在 C# 中調試我的代碼時,調試器會在我調用DeserializeWithLengthPrefix方法時退出。

這是我的 C# 代碼:

private void Listen()
{
    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    TcpListener listener = new TcpListener(ipAddress,4055);
    listener.Start();
    listener.BeginAcceptSocket(ClientConnected, listener);
}

private void ClientConnected(IAsyncResult result)
{
    TcpListener server = (TcpListener)result.AsyncState;
    using (TcpClient client = server.EndAcceptTcpClient(result))
    using (NetworkStream stream = client.GetStream())
    {
        try
        {
            //SendNameMessage sendNameObj = Serializer.Deserialize<SendNameMessage>(stream);
            SendNameMessage sendNameObj = Serializer.DeserializeWithLengthPrefix<SendNameMessage>(stream, PrefixStyle.Fixed32);
            string name = sendNameObj.sendName;
            if (name != null && name.Length > 0)
            {
                nameTextBox.Text = name;
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

這是我的Java代碼:

SendNameMessage.Builder sendNameMessageObj = null;
sendNameMessageObj = SendNameMessage.newBuilder();
sendNameMessageObj.setSendName("Protobuf-net");

SocketRequest.INSTANCE.openSocket();
sendNameMessageObj.build().writTo(SocketRequest.INSTANCE.getWriter());

Serializer.Deserialize<sendName>(stream); 應該這樣做,但我它永遠掛着? 這里的原因是 protobuf 消息沒有內置終止符,因此默認情況下它會讀取到流結束 - 這在您關閉套接字之前不會發生。

為了解決這個問題,一個常用的伎倆就是用長度前綴的消息,並限制自己這一點。 在 Java 實現中可能有一種內置的方法來處理它,或者您可以手動處理它。 在 C# 方面,protobuf-net 有DeserializeWithLengthPrefix ,它接受一個枚舉來指定你如何編碼它。 為簡單起見,我建議使用基本的 32 位小端長度編碼(映射到PrefixStyle.Fixed32 )。


重新編輯/評論:兩者必須匹配。 此刻你正在序列化沒有長度的前綴,但預期反序列長度前綴。 Java API 是否公開了一種編寫之前獲取數據長度的機制? 如果沒有,也許先寫到臨時緩沖區,看看你寫了多少,然后寫長度,最后寫數據。

或者; 如果您只發送一條消息 - 只需關閉流並使用Deserialize (無長度前綴)。 我有一個 C#-to-C# 多消息套接字示例可用,但我不能在 Java 方面發表太多評論......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM