[英]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.