protobuf-csharp-порт

Я использую Jon Skeet (отличный) порт Google Protocol Buffers для C#/.Net.

Для практики я написал фиктивное приложение для обмена мгновенными сообщениями, которое отправляет несколько сообщений через сокет. У меня есть определение сообщения следующим образом: -

message InstantMessage {<br/>
  required string Message = 1;<br/>
  required int64 TimeStampTicks = 2; <br/>
}

Когда отправитель сериализует сообщение, он отправляет его очень элегантно:

        ...
        InstantMessage.Builder imBuild = new InstantMessage.Builder();

        imBuild.Message = txtEnterText.Text;
        imBuild.TimeStampTicks = DateTime.Now.Ticks;

        InstantMessage im = imBuild.BuildPartial();

        im.WriteTo(networkStream);
        ...

Это прекрасно работает. Но с другой стороны, у меня проблемы с работой ParseFrom.

Я хочу использовать: -

InstantMessage im = InstantMessage.ParseFrom(networkStream);

Но вместо этого мне пришлось прочитать его в байтах, а затем разобрать отсюда. Очевидно, что это не идеально по ряду причин. Текущий код: -

while (true)
        {
            Byte[] byteArray = new Byte[10000000];

            int intMsgLength;
            int runningMsgLength = 0;

            DateTime start = DateTime.Now;

            while (true)
            {
                runningMsgLength += networkStream.Read(byteArray, runningMsgLength, 10000000 - runningMsgLength);

                if (!networkStream.DataAvailable)
                    break;

            }

            InstantMessage im = InstantMessage.ParseFrom(byteArray.Take(runningMsgLength).ToArray());

Когда я пытаюсь использовать ParseFrom, управление не возвращается к вызывающему методу, даже если я знаю, что действительное сообщение GB находится в сети.

Любой совет будет принят с благодарностью,

PW


person Phil Whittington    schedule 27.08.2010    source источник
comment
Доступность данных — плохой вариант, кстати. Это ничего не говорит вам о реальных данных.   -  person Marc Gravell    schedule 27.08.2010
comment
Рассмотрю это завтра. Слишком устал сегодня вечером.   -  person Jon Skeet    schedule 28.08.2010


Ответы (2)


Извините, что занял некоторое время, чтобы ответить на это. Как говорит Марк, буферы протоколов не имеют терминатора и не имеют префикса длины, если только они не вложены друг в друга. Однако вы можете сами поставить префикс длины. Если вы посмотрите на MessageStreamIterator и MessageStreamWriter, вы увидите, как я это делаю — в основном я притворяюсь, что нахожусь в середине сообщения, пишу вложенное сообщение как поле 1. К сожалению, при чтении сообщение, я должен использовать внутренние данные (BuildImpl).

Теперь для этого есть еще один API: IMessage.WriteDelimitedTo и IBuilder.MergeDelimitedFrom. Это, вероятно, то, что вы хотите в данный момент, но я, кажется, помню, что есть небольшая проблема с определением конца потока (т.е. когда нет другого сообщения для чтения). Я не могу вспомнить, есть ли исправление для этого на данный момент - у меня такое ощущение, что это изменилось в версии Java, и я, возможно, еще не перенес это изменение. В любом случае, это определенно та область, на которую стоит обратить внимание.

person Jon Skeet    schedule 30.08.2010
comment
Джон, извините за поздний ответ - я был на тренинге. Спасибо за подсказку - я бегло посмотрел, и я уверен, что с этим объяснением я смогу понять это. Еще раз спасибо, я очень благодарен. PW - person Phil Whittington; 06.09.2010

Protobuf не имеет терминатора, поэтому либо закройте поток, либо используйте свой собственный префикс длины и т. д. Protobuf-net легко предоставляет это через SerializeWithLenghtPrefix / DeserializeWithLengthPrefix.

Просто: без этого он не может знать, где заканчивается каждое сообщение, поэтому пытается прочитать до конца потока.

person Marc Gravell    schedule 27.08.2010
comment
Спасибо, Марк, мне непонятно, где вы видите SerializeWithLengthPrefix и соответствующий ему Derserialize... Вы говорите, что мне нужно вызвать метод для моего объекта InstantMessage, прежде чем делать: im.WriteTo(networkStream); ? Еще раз спасибо - person Phil Whittington; 27.08.2010
comment
@phil - protobuf-net - это другая реализация, но тот же подход должен работать. В версии Джона может быть существует метод: я точно не знаю. - person Marc Gravell; 27.08.2010