2

SSL(over SSLStream)で動作するサーバー/クライアントアプリケーションを作成しています。これは、ファイルの送受信だけでなく、多くのことを行う必要があります。現在、次のように動作します。接続は 1 つだけです。1 つの接続ですべての情報を送信でき、データを破壊することなくすべてのスレッドから送信できるため、 私は常に を使用してクライアント/サーバーからデータを送信し、SSLStream.WriteLine()それを使用して受信します。SSLStream.ReadLine()

次に、ファイルの送受信を実装したいと思いました。クライアント/サーバー アプリの他のものと同様に、すべてのメッセージにはプレフィックス (cl_files や sth など) と base64 でエンコードされたコンテンツ部分 (プレフィックスとコンテンツは | で区切られています) があります。私はそのようにファイル共有を実装しました: アップローダは受信者にファイルの合計サイズに関するメッセージを送信し、その後、アップローダはファイルの base64 でエンコードされた部分を prefix 経由で送信しますr

私の問題は、ファイル共有が非常に遅いことです。localhost から localhost まで約 20KB/s を取得しました。私には別の問題もあります。ファイルのbase64でエンコードされた部分のサイズを大きくすると(ファイル共有が高速になります)、プレフィックスrは受信者に送信されなくなります(そのため、データを識別できませんでした)。

どうすれば速くなりますか?

どんな助けでも大歓迎です。

私の(おそらく悪い)コードはクライアント用です:

//its running inside a Thread
FileInfo x = new FileInfo(ThreadInfos.Path);
long size = x.Length; //gets total size
long cursize = 0;
FileStream fs = new FileStream(ThreadInfos.Path, FileMode.Open);
Int16 readblocks = default(Int16);
while (cursize < size) {
    byte[] buffer = new byte[4096];
    readblocks = fs.Read(buffer, 0, 4096);
    ServerConnector.send("r", getBase64FromBytes(buffer));//It sends the encoded Data with the prefix r over SSLStream.WriteLine
    cursize = cursize + Convert.ToInt64(readblocks);
    ThreadInfos.wait.setvalue((csize / size) * 100);//outputs value to the gui
}
fs.Close();

サーバーの場合:

case "r"://switch case for prefixes
           if (isreceiving)
           {
              byte[] buffer = getBytesFromBase64(splited[1]);//splited ist the received Line over ReadLine splitted by the seperator "|"
              rsize = rsize + buffer.LongLength;
              writer.Write(buffer, 0, buffer.Length);//it writes the decoded data into the file
              if (rsize == rtotalsize)//checks if file is completed
              {
                 writer.Close();
              }
           }
break;
4

4 に答える 4

5

あなたの問題は、テキストプロトコルを介して本質的にバイナリ操作を実行しており、暗号化されたチャネルを介して実行することでその問題を悪化させているという事実に起因しています。これを再発明するつもりはありませんが、いくつかのオプションがあります...

  1. 車輪を再発明するのではなく、HTTPS クライアント/サーバー モデルへの変換を検討してください。これにより、ファイルに対する PUT/GET 操作の明確に定義されたモデルが得られます。

  2. HTTPS に変換できない (または変換しない) 場合は、バイナリ データ用の安全なトランスポートと適切に定義されたプロトコルを提供する他のクライアント/サーバー ライブラリを検討してください。たとえば、protobuf-csharp-portprotobuf-csharp-rpcをよく使用して、データセンターまたはローカル ネットワーク内で安全なプロトコルとトランスポートを提供します。

  3. トランスポートが生の SslStream であることに行き詰まっている場合は、プロトコルを定義するために、 protobuf-csharp-portprotobuf-netなどの明確に定義された実証済みのバイナリ シリアル化フレームワークを使用してみてください。

  4. 最後に、使用しているフレームワークを引き続き使用する必要がある場合は、http のようなトリックを試してください。名前と値のペアをテキストとして記述し、その後に続く生のバイナリ コンテンツを定義します。

于 2012-09-19T00:28:26.617 に答える
2

まず第一に、ssl を介した base64 はとにかく遅くなります。ssl 自体は生の転送よりも遅くなります。現在、ファイル転送は base64 で行われていません。http プロトコルは何よりも安定しており、すべてのプラットフォームのほとんどのライブラリは非常に安定しています。Base64 は、実際のデータよりも多くのサイズと、エンコードに時間がかかります。

また、次の行が問題になる可能性があります。

ThreadInfos.wait.setvalue((csize / size) * 100);//outputs value to the gui

この行がブロックされている場合、これは 4kb ごとに遅くなります。4kb ごとに更新することも適切ではありません。進行状況の値が以前の値と大きく異なる場合を除き、UI を更新する必要はありません。

于 2012-09-19T07:16:59.323 に答える
1

ネットワークの前後に gzip 圧縮を試してみます。私の経験から、それは役に立ちます。このようなコードが役立つと思います:

using(GZipStream stream = new GZipStream(sslStream, CompressionMode.Compress)) 
{
    stream.Write(...);
    stream.Flush();
    stream.Close();
}

警告 : Flush が行われていない場合、SSL に干渉する可能性があります。いくつかのテストが必要になります...そして、コードをコンパイルしようとしませんでした。

于 2012-09-19T14:49:02.803 に答える
0

Akash Kava は正しいと思います。

while (cursize < size) {
    DateTime start = DateTime.Now;
    byte[] buffer = new byte[4096];
    readblocks = fs.Read(buffer, 0, 4096);
    ServerConnector.send("r", getBase64FromBytes(buffer));
    DateTime end = DateTime.Now;
    Console.Writline((end-start).TotalSeconds);
    cursize = cursize + Convert.ToInt64(readblocks);
    ThreadInfos.wait.setvalue((csize / size) * 100);
    end = DateTime.Now;
    Console.Writline((end-start).TotalSeconds);
}

こうすることで、ボトルネックがどこにあるかを知ることができます。

また、データ パケットをサーバーに送信する方法も堅牢ではありません。

の実装を貼り付けることは可能ですか

ThreadInfos.wait.setvalue((csize / サイズ) * 100);

于 2012-09-19T14:49:58.650 に答える