在C#中读取Protobuf消息

son*_*onu 5 c# protobuf-net

我有一个简单的信息:

包装测试;

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); }   }    }
Run Code Online (Sandbox Code Playgroud)

我正在使用java从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);

        }
Run Code Online (Sandbox Code Playgroud)

}

我显然在这里缺少一些基础知识.

我应该使用什么方法来获取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);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是我的java代码:

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

        SocketRequest.INSTANCE.openSocket();
       sendNameMessageObj.build().writTo(SocketRequest.INSTANCE.getWriter());
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 5

Serializer.Deserialize<sendName>(stream);应该这样做,但我猜测,这是永远挂?这里的原因是protobuf消息没有内置的终结符,所以默认情况下它会读取直到流的结尾 - 直到你关闭套接字才会发生.

为了解决这个问题,一个常见的伎俩是前缀,长度消息,并限制自己这一点.可能有一种内置的方法来处理Java实现中的方法,或者您可以手动处理它.在C#方面,protobuf-net有DeserializeWithLengthPrefix,它接受枚举来指定你如何编码它.为简单起见,我建议使用长度的基本32位little-endian编码(映射到PrefixStyle.Fixed32).


重新编辑/评论:两者必须匹配.目前,您正在序列化而没有长度前缀,但反序列化期望长度前缀.编写数据长度之前,Java API是否公开了获取数据长度的机制?如果没有,也许首先写入临时缓冲区,看看你写了多少,然后写长度,最后写入数据.

要么; 如果您只发送一条消息 - 只需关闭流并使用Deserialize(无长度前缀).我有一个C#-to-C#多消息套接字示例,但我不能对Java方面做出太多评论......