4

winsock を使用している C++ CLI でサーバー用のソケットを作成しました。ソケットは、接続の送受信に非同期メソッドを使用しています。実稼働環境でソケットを実装した後、送信機能が停止し、エラー WSAEWOULDBLOCK が表示されます。私のネットでの調査によると、これはソケット IO のネットワーク バッファがいっぱいであるか、ネットワークがビジー状態で現時点で操作を実行できないことを意味します。ただし、この問題に対処できる具体的な解決策は見たことがありません。私の一時的な解決策は、WSASend 関数の周りに do-while ループを作成し、スレッドを X 量の MS の間スリープさせてから再試行することでした。これにより、以前のソケット (.NET ソケット クラス) よりもはるかに長い待機時間と大きなラグ スパイクが発生しました。

データを送信するための私のコードは次のとおりです。

void Connectivity::ConnectionInformation::SendData(unsigned char data[], const int length)
{
    if (isClosed || sendError)
        return;

    Monitor::Enter(this->syncRoot);

    try
    {
        sendInfo->buf = (char*)data;
        sendInfo->len = length;

        do
        {
            state = 0;
            if (WSASend(connection, sendInfo, 1, bytesSent, 0, NULL, NULL) == SOCKET_ERROR)
            {
                state = WSAGetLastError();
                if (state == WSAEWOULDBLOCK)
                {
                    Thread::Sleep(SleepTime);
                    //Means the networking is busy and we need to wait a bit for data to be sent
                    //Might wanna decrease the value since this could potentially lead to lagg
                }
                else if (state != WSA_IO_PENDING)
                {
                    this->sendError = true;
                    //The send error bool makes sure that the close function doesn't get called
                    //during packet processing which could cause a lot of null reffernce exceptions.
                }
            }
        }
        while (state == WSAEWOULDBLOCK);
    }
    finally
    {
        Monitor::Exit(this->syncRoot);
    }
}

データを送信できるときにコールバックを取得するために、たとえば WSAEventSelect メソッドを使用する方法はありますか? MSDN のドキュメントによると、wait for data メソッドもこのエラーでスタックする可能性があります。これを回避するための解決策はありますか?

4

2 に答える 2

3

エラー コードWSAEWOULDBLOCKは、非ブロック ソケットで操作を試みたが、操作をすぐに完了できなかったことを意味します。これは実際のエラーではありません。後で再試行するか、非同期 IO をスケジュールすることができます (失敗することはありません)。しかし、これはそもそもあなたが望むものではありません。説明させてください:

次の 2 つの方法のいずれかでソケットを使用することになっています。

  1. 同期、ブロッキング。
  2. 非同期、ノンブロッキング、コールバックベース。

2つを混ぜ合わせていると、両方の最悪の結果になります。ノンブロッキング ソケットを作成し、それをブロッキングの可能性がある方法で使用しました。

残念ながら、私はネイティブ コード ソケットのベスト プラクティスを提供する資格はありません。WSASendのすべてのドキュメントを読むことをお勧めします。これらすべてが説明されているようです。

では、なぜこの奇妙なエラー コードが存在するのでしょうか。パフォーマンスの最適化です。投機的に同期送信を試みることができます (これは非常に高速です)。失敗した場合にのみ、非同期 IO をスケジュールすることになっています。その最適化が必要ない場合(必要ない場合)は、実行しないでください。

于 2012-12-23T13:04:36.873 に答える
1

@usr が言うように、操作をノンブロッキングにするために、LPWSAOVERLAPPED または LPWSAOVERLAPPED_COMPLETION_ROUTINE のいずれかを値に設定する必要があります。しかし、テストの結果、完了ルーチンを呼び出すために LPWSAOVERLAPPED オブジェクトが必要ないことがわかりました。MSDN の WSASend 関数のドキュメントにも記載されていますが、オーバーラップしたオブジェクトと完了ルーチンが NULL の場合、ソケットはブロッキング ソケットとして動作します。

ありがとう、そしてメリークリスマス!:)

于 2012-12-25T12:11:27.490 に答える