-1

サーバーからクライアントにオブジェクトを送信しようとしています。私の問題は、オブジェクトを 1 つだけ送信すると、すべてが正しく機能することです。しかし、別のオブジェクトを追加すると、「バイナリストリームに有効なバイナリヘッダーが含まれていません」または「オブジェクトのマップがありません (乱数)」という例外がスローされます。私の考えでは、デシリアライゼーションはストリームの開始/終了場所を理解していないので、皆さんがここで私を助けてくれることを願っています.

ここに私の逆シリアル化コードがあります:

public void Listen()
        {
            try
            {
                bool offline = true;
                Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(() => offline = Offline));
                while (!offline)
                {
                    TcpObject tcpObject = new TcpObject();
                    IFormatter formatter = new BinaryFormatter();
                    tcpObject = (TcpObject)formatter.Deserialize(serverStream);

                    if (tcpObject.Command == Command.Transfer)
                    {
                        SentAntenna sentAntenna = (SentAntenna)tcpObject.Object;

                        int idx = 0;
                        foreach (string name in SharedProperties.AntennaNames)
                        {
                            if (name == sentAntenna.Name)
                                break;
                            idx++;
                        }

                        if (idx < 9)
                        {
                            PointCollection pointCollection = new PointCollection();
                            foreach (Frequency f in sentAntenna.Frequencies)
                                pointCollection.Add(new Point(f.Channel, f.Intensity));

                            SharedProperties.AntennaPoints[idx] = pointCollection;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); // raise an event
            }
        }

シリアル番号:

case Command.Transfer:
                            Console.WriteLine("Transfering");
                            Thread transfer = new Thread(new ThreadStart(delegate
                            {
                                try
                                {
                                    string aName = tcpObject.Object.ToString();
                                    int indx = 0;
                                    foreach (string name in names)
                                    {
                                        if (name == aName)
                                            break;
                                        indx++;
                                    }

                                    if (indx < 9)
                                    {
                                        while (true) // need to kill when the father thread terminates
                                        {
                                            if (antennas[indx].Frequencies != null)
                                            {
                                                lock (antennas[indx].Frequencies)
                                                {
                                                    TcpObject sendTcpObject = new TcpObject();
                                                    sendTcpObject.Command = Command.Transfer;
                                                    SentAntenna sa = new SentAntenna(antennas[indx].Frequencies, aName);
                                                    sendTcpObject.Object = sa;
                                                    formatter.Serialize(networkStream, sendTcpObject);
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex) { Console.WriteLine(ex); }
                            }));
                            transfer.Start();
                            break;
4

2 に答える 2

1

面白い。シリアル化コードには特に奇妙なことは何もありません。BinaryFormatterはこのシナリオがOKであると明示的に主張していないため、実際には常に反対するようにアドバイスしていますが、過去に複数のオブジェクトにバニラ連結を使用する人を見てきました。しかし、そうでない場合、私が提案できる唯一のことは、独自のフレーミングを実装することです。したがって、書き込みコードは次のようになります。

  • 空のMemoryStreamにシリアル化する
  • 長さをメモし、長さをNetworkStreamに書き込みます。たとえば、単純な固定幅の32ビットネットワークバイトオーダー整数として書き込みます。
  • MemoryStreamからNetworkStreamにペイロードを書き込みます
  • すすぎ、繰り返します

そして、読み取られたコードは次のようになります。

  • 正確に4バイトを読み取り、長さを計算します
  • そのバイト数をMemoryStreamにバッファリングします
  • NetworkStreamから逆シリアル化

(どちらの場合も、書き込みと読み取りの間にMemoryStreamの位置を0に戻すことに注意してください)

読み取り時にバッファを回避したい場合は、長さを制限するStreamサブクラスを実装することもできます。ビットはより複雑です。

于 2012-12-09T18:13:50.100 に答える
0

どうやら私は本当に簡単な解決策を思いついた。同時にデータを転送できるスレッドが1つだけであることを確認したので、次のコード行を変更しました。

formatter.Serialize(networkStream, sendTcpObject);

これらのコード行に:

if (!transfering) // making sure only 1 thread is transfering data
{
    transfering = true;
    formatter.Serialize(networkStream, sendTcpObject);
    transfering = false;
}
于 2012-12-11T14:37:18.530 に答える