任意のオブジェクトを文字列にシリアル化してから、もちろん逆シリアル化することになっている次の C# コードがあります。
public static string Pack(Message _message)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream original = new MemoryStream();
MemoryStream outputStream = new MemoryStream();
formatter.Serialize(original, _message);
original.Seek(0, SeekOrigin.Begin);
DeflateStream deflateStream = new DeflateStream(outputStream, CompressionMode.Compress);
original.CopyTo(deflateStream);
byte[] bytearray = outputStream.ToArray();
UTF8Encoding encoder = new UTF8Encoding();
string packed = encoder.GetString(bytearray);
return packed;
}
public static Message Unpack(string _packed_message)
{
UTF8Encoding encoder = new UTF8Encoding();
byte[] bytearray = encoder.GetBytes(_packed_message);
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream input = new MemoryStream(bytearray);
MemoryStream decompressed = new MemoryStream();
DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress);
deflateStream.CopyTo(decompressed); // EXCEPTION
decompressed.Seek(0, SeekOrigin.Begin);
var message = (Message)formatter.Deserialize(decompressed); // EXCEPTION 2
return message;
}
しかし問題は、コードが実行されるたびに例外が発生することです。上記のコードを使用して、以下に示すように呼び出すと、InvalidDataException: Unknown block type を受け取ります。ストリームが破損している可能性があります。マークされた// EXCEPTION
ラインで。
この問題を検索した後、私はデフレを捨てようとしました。これは小さな変更Pack
に過ぎませbytearray
んoriginal.ToArray()
でしUnpack
た。変更された唯一の結果: 例外の位置と本体は異なりますが、それでも発生します。SerializationException: No map for object '201326592'を受け取りました。で。Seek()
input
decompressed
Deserialize(input)
decompressed
// EXCEPTION 2
何が問題なのかわかりません。多分それはシリアライゼーション全体のアイデアです...問題は、これらのオブジェクトがサーバーとクライアントアプリケーションの間を移動する情報を保持するため、何らかの方法でインスタンスをパックする必要があることです. Message
(シリアライゼーション ロジックは、両端で参照される.Sharedstring
DLL プロジェクトにありますが、現時点では、最初にサーバー側のみを開発しています。) また、現在は出力のみを使用していることも伝えなければなりません。 、サーバーとクライアント間のTCP接続は、両端で文字列の読み書きに基づいています。ですから、どうにかして弦のレベルまで下げる必要があります。
Message オブジェクトは次のようになります。
[Serializable]
public class Message
{
public MessageType type;
public Client from;
public Client to;
public string content;
}
(現在は、属性のみを持ち、プロパティやメソッドを持たないClient
空のクラスです。)Serializable
これは、pack-unpack が呼び出される方法です ( Main()
... から):
Shared.Message msg = Shared.MessageFactory.Build(Shared.MessageType.DEFAULT, new Shared.Client(), new Shared.Client(), "foobar");
string message1 = Shared.MessageFactory.Pack(msg);
Console.WriteLine(message1);
Shared.Message mess2 = Shared.MessageFactory.Unpack(message1); // Step into... here be exceptions
Console.Write(mess2.content);
IDE で何が起こるかを示す画像を次に示します。コンソール ウィンドウの出力は の値ですmessage1
。
bytearray
残念ながら、一部の調査では、問題が変数の周りにある可能性があることも明らかになりました。を実行するPack()
と、エンコーダーが文字列を作成した後、配列には 152 個の値が含まれますが、 でデコードされた後Unpack()
、配列には代わりに160個の値が含まれます。
私は本当にアイデアがなく、この問題を抱えていると進歩が妨げられているので、助けていただければ幸いです。ありがとうございました。
(更新)最終的な解決策:
解決策にたどり着いたので、回答とコメントをくれた皆さんに感謝します。ありがとうございました。
Marc Gravellは正しかったです。私は の締めくくりに失敗deflateStream
しました。そのため、結果は空か破損していました。私は時間をかけてメソッドを再考し、書き直しましたが、今では問題なく動作します. また、これらのバイトをネットワーク ストリーム経由で送信するという目的も機能しています。
また、Eric J.が示唆したように、とASCIIEnconding
の間string
でbyte[]
データが流れているときに を使用するように切り替えましたStream
。
固定コードは次のとおりです。
public static string Pack(Message _message)
{
using (MemoryStream input = new MemoryStream())
{
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(input, _message);
input.Seek(0, SeekOrigin.Begin);
using (MemoryStream output = new MemoryStream())
using (DeflateStream deflateStream = new DeflateStream(output, CompressionMode.Compress))
{
input.CopyTo(deflateStream);
deflateStream.Close();
return Convert.ToBase64String(output.ToArray());
}
}
}
public static Message Unpack(string _packed)
{
using (MemoryStream input = new MemoryStream(Convert.FromBase64String(_packed)))
using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress))
using (MemoryStream output = new MemoryStream())
{
deflateStream.CopyTo(output);
deflateStream.Close();
output.Seek(0, SeekOrigin.Begin);
BinaryFormatter bformatter = new BinaryFormatter();
Message message = (Message)bformatter.Deserialize(output);
return message;
}
}
以下のスクリーンショットが示すように、すべてが適切に行われます。これは、最初から予想された出力でした。サーバーとクライアントの実行可能ファイルは相互に通信し、メッセージは移動します...そして、適切にシリアライズおよびアンシリアライズされます。