1

非同期サーバーのコードがあります。クライアントはヘッダーを送信します - データ ブロック + データ ブロックのサイズ。

サーバーは、最初にヘッダーを読み取り、次にデータ ブロックを非同期に読み取ります。

データブロックを読み取った後、スレッドを非同期にするために、ヘッダー読み取り部分の BeginRead を実行する必要があります。

問題:

私が DataCallBack を取得したとき、次のようになります。

int bytesRead = ns.EndRead(結果);

読み込むように要求したすべてのバッファを取得できません

mc.Client.GetStream().BeginRead(mc.DataBuffer, 0, size, new AsyncCallback(DataCallBack), mc);

クライアントが 1MB のデータを送信すると、異なる数の「bytesRead」を取得できます。

質問:

「BeginRead」に接続からすべてのデータを強制的に読み取る方法。ヘッダー - データの新しいループが発生するはずです。

MyClient - TcpClient の単なるラッパーです。

コード:

    public  void DoAcceptTcpClientCallback(IAsyncResult ar)
    {
        TcpListener listener = (TcpListener)ar.AsyncState;
        TcpClient client = listener.EndAcceptTcpClient(ar);
        client.NoDelay = false;
       // client.ReceiveBufferSize = 1024*1024;
        listener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), listener);
        MyClient mc = new MyClient(client);
        ContinueRead(0,mc);
    }

    public void ContinueRead(int size, MyClient mc)
    {
        if (size != 0)
        {
            mc.DataBuffer = new byte[size];
            mc.Client.GetStream().BeginRead(mc.DataBuffer, 0, size, new AsyncCallback(DataCallBack), mc);
        }
        mc.Client.GetStream().BeginRead(mc.HeaderBuffer, 0, 4, new AsyncCallback(HeaderCallBack), mc);

    }

    private void HeaderCallBack(IAsyncResult result)
    {
        MyClient mc = (MyClient)result.AsyncState;
        NetworkStream ns = mc.Stream;
        int bytesRead = ns.EndRead(result);
        if (bytesRead == 0)
            throw new Exception();
        mc.TotalLengs =  BitConverter.ToInt32(mc.HeaderBuffer, 0);
        ContinueRead(mc.TotalLengs, mc);

    }
    private void DataCallBack(IAsyncResult result)
    {
        MyClient mc = (MyClient)result.AsyncState;
        NetworkStream ns = mc.Stream;
        int bytesRead = ns.EndRead(result);
        if (bytesRead == 0)
            throw new Exception();

悪いコード - 読み取りが非同期になる - 同期

        while (bytesRead < mc.TotalLengs)
        {
            bytesRead += ns.Read(mc.DataBuffer, bytesRead, mc.TotalLengs - bytesRead);
        }

悪いコードを終わらせる

        ContinueRead(0, mc);
        ProcessPacket(mc.DataBuffer, mc.IP);
    }
4

1 に答える 1

4

「クライアントが 1MB のデータを送信すると、異なる数の "bytesRead" を取得できます。」

はい...これは、TCPがフードの下でどのように機能するかです。これは変更できません。TCP は、パケットがグループ化される方法ではなく、パケットの順序を保証します。パケットが移動するルートに沿ったハードウェアとトラフィックの状態によって、データがどのようにグループ化 (またはグループ化解除) されるかが決まります。

「接続からすべてのデータを読み取るように「BeginRead」を強制する方法。

TCP は、送信されているデータの量を認識していません。関係する限り、接続は単純に無限のバイト ストリームです。したがって、データには終わりがないため(その観点から)、「すべてのデータ」を読み取ることはできません。TCP には、アプリケーションに関して「完全なメッセージ」が何であるかという概念もありません。すべてのデータがいつ送信されたかをアプリケーションが認識できるようにするプロトコルを開発するのは、プログラマであるあなた次第です。

特定のバイト数が予想される場合は、EndRead() によって返された値の実行中の合計を保持し、そのマジック ナンバーに到達したときに停止します。

于 2013-05-13T14:11:16.443 に答える