我有一条简单的信息:
包裹测试;
message sendName {
可选字符串username = 1;
}
真棒VS插件会生成.cs文件:
命名空间测试{
[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());
答案 0 :(得分:5)
Serializer.Deserialize<sendName>(stream);
应该这样做,但我猜测它永远挂了吗?这里的原因是protobuf消息没有内置的终结符,所以默认是它读取直到流的结尾 - 直到你关闭套接字才会发生。
为了解决这个问题,一个常见的技巧是前缀消息的长度,并限制自己。可能有一种内置的方法来处理Java实现中的方法,或者您可以手动处理它。在C#方面,protobuf-net有DeserializeWithLengthPrefix
,它接受枚举来指定你如何编码它。为简单起见,我建议使用长度的基本32位little-endian编码(映射到PrefixStyle.Fixed32
)。
重新编辑/评论:两者必须匹配。目前,您正在序列化而不是长度前缀,但是反序列化期望长度前缀。在您编写之前,Java API是否公开了获取数据长度的机制?如果没有,也许首先写入临时缓冲区,看看你写了多少,然后写长度,最后写数据。
或者;如果您只发送一条消息 - 只需关闭流并使用Deserialize
(无长度前缀)。我有一个C#-to-C#多消息套接字示例,但我不能对Java方面做太多评论......