Чтение Protobuf обменивается сообщениями в C#

У меня есть простое сообщение:

тест пакета;

передайте sendName {

дополнительное строковое имя пользователя = 1;

}

Потрясающий плагин VS генерирует .cs файл:

тест пространства имен {

[глобальный:: Система. Сериализуемый глобальный:: ProtoBuf. ProtoContract (Имя = "sendName")]

общедоступный частичный класс sendName: глобальный:: 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#, которое действует как Слушатель Сокета, мне назвали метод, Слушают, который прислушивается к сообщению, отправленному клиентом Java:

общественность пусто Слушает ()

{

       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());
5
задан sonu 1 July 2010 в 18:28
поделиться

1 ответ

Serializer.Deserialize (stream); должен это делать, но я предполагаю , что он висит вечно? Причина здесь в том, что сообщения protobuf не имеют встроенного терминатора, поэтому по умолчанию считывается до конца потока, чего не произойдет, пока вы не закроете сокет.

Чтобы обойти это, обычная уловка состоит в том, чтобы префикс сообщения с длиной сообщения и ограничился этим. В реализации Java может быть встроенный способ справиться с этим, или вы можете справиться с этим вручную. На стороне C # protobuf-net имеет DeserializeWithLengthPrefix , который принимает перечисление, чтобы указать, как вы его закодировали. Для простоты я бы предложил базовую 32-битную кодировку с прямым порядком байтов длины (которая соответствует PrefixStyle.Fixed32 ).


По поводу правки / комментария: они должны совпадать. В настоящий момент вы сериализуете без префикса длины, но десериализуете , ожидая префикса длины. Предоставляет ли Java API механизм для получения длины данных до того, как вы ее напишете? Если нет, возможно, сначала запишите во временный буфер, посмотрите, сколько вы написали, затем запишите длину и, наконец, данные.

Или; если вы отправляете только одно сообщение - просто закройте поток и используйте Deserialize (без префикса длины). У меня есть пример сокетов с несколькими сообщениями C # -to-C #, но я не могу много комментировать со стороны Java ...

5
ответ дан 14 December 2019 в 18:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: