4

TCP 接続 (BeginAccept/EndAccept) とデータ (BeginReceive/EndReceive) を非同期に受け入れるサーバー アプリケーションを開発しています。このプロトコルでは、次のメッセージを送信する前に EOM 文字が検出されるたびに ACK を送信する必要があります。受け入れと受信は機能していますが、送信アプリは ACK を受信して​​いません (同期的に送信されます)。

    private void _receiveTransfer(IAsyncResult result)
    {
        SocketState state = result.AsyncState as SocketState;
        int bytesReceived = state.Socket.EndReceive(result);

        if (bytesReceived == 0)
        {
            state.Socket.Close();
            return;
        }

        state.Offset += bytesReceived;
        state.Stream.Write(state.Buffer, 0, bytesReceived);

        if (state.Buffer[bytesReceived - 1] == 13)
        {
            // process message
            Messages.IMessage message = null;
            try
            {
                var value = state.Stream.ToArray();

                // do some work
                var completed = true;

                if (completed)
                {
                    // send positive ACK
                    var ackMessage = string.Format(ack, message.TimeStamp.ToString("yyyyMMddhhmm"), message.MessageType, message.Id, "AA", message.Id);
                    var buffer = ASCIIEncoding.ASCII.GetBytes(ackMessage);
                    int bytesSent = state.Socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
                }
                else
                {
                    // send rejected ACK
                    var ackMessage = string.Format(ack, message.TimeStamp.ToString("yyyyMMddhhmm"), message.MessageType, message.Id, "AR", message.Id);
                    state.Socket.Send(ASCIIEncoding.ASCII.GetBytes(ackMessage));
                }
            }
            catch (Exception e)
            {
                // log exception


                // send error ACK
                if (message != null)
                {
                    var ackMessage = string.Format(ack, DateTime.Now.ToString("yyyyMMddhhmm"), message.MessageType, message.Id, "AE", message.Id);
                    state.Socket.Send(ASCIIEncoding.ASCII.GetBytes(ackMessage));
                }
            }
        }

        state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(_receiveTransfer), state);
    }

state.Socket.Send は正しいバイト数を返しますが、ソケットが破棄されるまでデータは受信されません。

提案を歓迎します。

4

4 に答える 4

2
  • 非同期完了ルーチンから同期的に何かを行うべきではありません。負荷がかかると、スレッド プールからすべての IO 完了スレッドをハイジャックし、完全な IO デッドロックまで、パフォーマンスを著しく損なう可能性があります。したがって、非同期コールバックから同期的に ACK を送信しないでください。
  • プリアンブルを使用するプロトコルとフォーマットは、ターミネータを使用するものよりも管理が容易です。すなわち。ターミネータ \0x13 を検出するのではなく、メッセージの長さを固定サイズのメッセージ ヘッダーに書き込みます。もちろん、これはプロトコルが最初からあなたの管理下にある場合に当てはまります。

あなたの質問に関しては、あなたが投稿したのと同じコードがクライアント側にもあるかどうかを指定しませんでした。

于 2010-02-15T21:57:00.897 に答える
0

NoDelayソケットのプロパティを に設定しましたtrueか? (デフォルト) に設定するとfalse、データは送信前に最大 200 ミリ秒バッファリングされます。その理由は、送信されるパケットの数を制限することによってネットワーク トラフィックを削減するためです。に設定NoDelayするtrueと、データがより早く送信されます。

于 2010-02-15T22:53:02.990 に答える
0

いつまであげてるの?ネットワーク スタックはバッファすることができ、それによって送信が遅延する可能性があります。MSDNから:

ネットワークの効率を高めるために、大量の送信データが収集されるまで、基盤となるシステムが送信を遅らせる場合があります。Send メソッドが正常に完了したということは、基になるシステムにネットワーク送信用のデータをバッファリングする余地があることを意味します。

IOControlメソッドを使用してフラッシュを試してみてください。

編集

実際には、IOControl フラッシュはバッファを殺します。プロトコルに固有の問題があるかどうかを確認するために、Two Generals Problemを確認することをお勧めします。

于 2010-02-15T21:56:34.330 に答える
0

TCP_NODELAY ソケットオプションを設定してみてください

于 2010-02-15T22:20:34.923 に答える