Основная проблема здесь связана с тем, что вы смешиваете два разных механизма для чтения и записи в поток, а именно: с использованием StreamReader
и отдельного анализатора на основе потока. Это также плохая идея сделать это с StreamWriter
, но ... я думаю, что вам это сойдет с рук, хотя это все еще плохая идея.
Проблема в том, что StreamReader
является жадным . Когда вы запрашиваете строку, он не читает из потока побайтно, ища \r
или \n
- он захватывает буфер данных из потока, а затем обрабатывает это , как вы просите об этом . Таким образом, предполагается, что теперь он является единственным владельцем потока.
So; когда вы делаете это:
while (!((msg = reader.ReadLine()).Equals("exit"))){
Transaction tx = (Transaction)formatter.Deserialize(strm);
}
ридер потребляет больше, чем просто "transaction\r\n
"- он потребляет эту строку и некоторое неопределенное количество байтов из того, что следует после . Затем, когда BinaryFormatter
пытается прочитать поток, он оказывается на полпути через сообщение и взрывается в потоке искр.
В идеале, ограничьте себя одним механизмом сериализации . Значение: потерять StreamReader
/ StreamWriter
полностью здесь.
Если бы я мог предложить альтернативный механизм, использующий protobuf- net и наследование:
[ProtoContract]
[ProtoInclude(1, typeof(ShutdownMessage))]
[ProtoInclude(2, typeof(TransactionMessage))]
public abstract class MessageBase {}
[ProtoContract]
public sealed class ShutdownMessage : MessageBase {}
[ProtoContract]
public sealed class TransactionMessage : MessageBase {
// your data here
}
и теперь вы можете отправлять любое количество сообщений с помощью:
public void Send(MessageBase message) {
Serializer.SerializeWithLengthPrefix(strm, message, PrefixStyle.Base128);
}
и получать любое количество сообщений с помощью:
while (true) {
var msg = Serializer.DeserializeWithLengthPrefix<MessageBase>(strm, PrefixStyle.Base128);
if (msg is null || msg is ShutdownMessage) break; // all done
switch (msg)
{
case TransactionMessage tx: ProcessTransaction(tx); break;
// etc
}
}