1

クライアント/サーバーアプリがあります。どちらもデータを受信するときに非同期呼び出しを使用します。TCPを使用したビルドであり、主にファイルの送信を目的としています。

コマンドはソケットに沿って送信され、ソケットは単純なスイッチケースに「変換」されてアクションを実行します。クライアントがコマンド「SENDFILE」を送信した場合、サーバーが関数を呼び出すケースを入力できるようにします。この関数は、そのソケットに沿ってさらにデータを処理し、それをファイルに結合します。

これは、サーバー側のOnDataReceiveコールバック関数とスイッチケースです。

public void OnDataReceived(IAsyncResult asyn)
        {
            SocketData socketData = (SocketData)asyn.AsyncState;
            try
            {

                // Complete the BeginReceive() asynchronous call by EndReceive() method
                // which will return the number of characters written to the stream 
                // by the client
                socketData.m_currentSocket.EndReceive(asyn);

                //Get packet dtata
                Packet returnPacket = Helper.ByteArrayToPacket(socketData.dataBuffer);

                switch (returnPacket.command)
                {
                    case Command.SENDREQUEST: //Get ready for an incoming file      

ここで、ネットワークストリームから非同期的に読み取り、ファイルストリームに同期的に書き込むクラス:そうですか?

    public static void NetToFile(NetworkStream net, FileStream file)
        {
            var copier = new AsyncStreamCopier(net, file);
            copier.Start();
        }

public class AsyncStreamCopier
    {
        public event EventHandler Completed;

        private readonly Stream input;
        private readonly Stream output;

        private byte[] buffer = new byte[Settings.BufferSize];

        public AsyncStreamCopier(Stream input, Stream output)
        {
            this.input = input;
            this.output = output;
        }

        public void Start()
        {
            GetNextChunk();
        }

        private void GetNextChunk()
        {
            input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null);
        }

        private void InputReadComplete(IAsyncResult ar)
        {
            // input read asynchronously completed
            int bytesRead = input.EndRead(ar);

            if (bytesRead == 0)
            {
                RaiseCompleted();
                return;
            }

            // write synchronously
            output.Write(buffer, 0, bytesRead);

            // get next
            GetNextChunk();
        }

        private void RaiseCompleted()
        {
            if (Completed != null)
            {
                Completed(this, EventArgs.Empty);
            }
        }
    }

私が抱えている問題は、ファイルストリームからネットワークストリームへの読み取りとは逆のことです。ファイルストリームから非同期で読み取り、ネットワークストリームに同期的に書き込む必要がありますか?

また、上記の例では、Start()が最初に呼び出されて関数が終了すると、サーバーのswitchケースに戻り、それ以降の(ファイル)データがPacket returnPacket = Helper.ByteArrayToPacket(socketData.dataBuffer);

とエラー:(

*編集1*

  • 外部ライブラリや大量のコードを使用することはできません。これはゼロから構築する必要があります。

  • これは典型的なクライアントサーバーアプリではなく、より多くのp2pですが、完全ではありません。各アプリには、異なるスレッドで実行される独自のサーバーとクライアントがあります。これにより、複数のアプリがすべて相互に接続して...ネットワークを作成できます。

  • クライアントはサーバーにファイルを送信していることを通知しますが、サーバーにファイルを要求しません

4

3 に答える 3

0

非同期ストリーム操作に関するこの記事http://msdn.microsoft.com/en-us/magazine/cc337900.aspxを確認してください(ストリームを非同期にコピーするコンパクトなコードがあります)。

サンプルコードでは、完了通知を使用していません...ストリームコピーが完了するのを外部コードが待機していることを確認してください。

于 2011-01-11T23:08:06.457 に答える
0

ええと、あなたの質問に対する直接的な答えはないと思います。ただし、ここにいくつかの所見があります。

クライアントがコマンド「SENDFILE」を送信した場合、サーバーができるようにしたいのですが...

これはアプローチです。ただし、コントロールをもう少し反転することを検討するかもしれません。サイズ/バージョン情報を返すフェッチファイル情報があります。次に、オフセットと長さをとる読み取りファイルを用意します。これで、クライアントは、サーバーが送信できる速度でデータを吸収しようとするのではなく、ファイルを「ポーリング」することができます。

ここで、ネットワークストリームから非同期的に読み取り、ファイルストリームに同期的に書き込むクラス:そうですか?

ええ、一見すると正しく見えます。

私が抱えている問題は、ファイルストリームからネットワークストリームへの読み取りとは逆のことです。ファイルストリームから非同期で読み取り、ネットワークストリームに同期的に書き込む必要がありますか?

ここでも、クライアントのポーリングループを使用して、ファイルの一部を一度にプルします。ソケットが切断された場合は、これを再起動することもできます。

また、上記の例では、最初にStart()が呼び出され、関数が終了するためです...

ええ、これは一般的にソケットで問題になります。受信したバイトをどう処理するかがわかるように、各ソケットでいくつかの状態情報を追跡する必要があります。ファイルに書き込んでいるのか、コマンドを待っているのかなど。率直に言って、これを書いている場合(とにかくソケットは使用しません)、各リクエストの詳細を含む長さのプレフィックスが付いたgoogleprotobufferにすべてをパックします。これにより、サーバーで状態管理を追跡するのではなく、クライアントに状態管理をオフロードできます。

誰かが私を正しい方向に向けることができますか?私が見ることができるものからネット上に多くはありません。

このネット検索であまり見つけられない一般的な理由は、ほとんど(90%程度)がこれを試していないからだと思います。ソケットを使用してこれを行うことは、困難で、面倒で、非常にエラーが発生しやすくなります。私は通信にrawソケットを使い始めることすらしませんでした。そこにある既存のクライアント/サーバートランスポートを選択して、それを使用します。例が必要な場合は、おそらくWCFに傾倒することをお勧めします。

乾杯、そして幸運を!

于 2011-01-11T22:34:18.927 に答える
0

関数が終了せず、networkstream-> filestreamを完了できるように、waitイベントを使用してその一部を解決したと思います。

私が今抱えている問題は、ファイルストリーム->ネットワークストリームをそうすることです。「ファイルストリームから非同期に読み取り、ネットワークストリームに同期的に書き込む必要がありますか?」

于 2011-01-12T19:18:01.180 に答える