Protobuf-CSharp-порт - PullRequest
       12

Protobuf-CSharp-порт

4 голосов
/ 27 августа 2010

Я использую Jon Skeet (превосходный) порт буферов протокола Google для C # /. Net.

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

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

Ответы [ 2 ]

4 голосов
/ 30 августа 2010

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

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

0 голосов
/ 27 августа 2010

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

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

...