5

私は友人のためにいくつかのコードを見るように頼まれました。(MFCと多くの悪いコードのために躊躇しましたが、彼は勝ちました...)

これは、 を使用するダイアログ ボックス ベースのアプリケーションですCAsyncSocket

この問題は、いくつかのノンストップ デバッグ ブレークやその他の同様の現象に現れます。MFC マクロにも問題がありENSURE()、ソケットの null をチェックします。すべての問題は、MFC の奥深くで発生します。

Vista/XP でテーマを使用するとリソース リークが発生する可能性があることをグーグルで調べたところ、問題はないと思います。

私の数時間のデバッグに基づくと、コードはかなり貧弱ですが、基本的には次のことを行っています。

(接続されている場合は問題ありません。接続されていない場合のみです)

  • Connect(server, socket) を呼び出します (派生CAsyncSocketオブジェクトで)
  • で、OnConnect()接続が機能しなかった/接続されていないことが通知されます。
  • メイン ダイアログ/アプリのウィンドウ タイマー内にタイマーがあります。タイマー イベント/ハンドラーが呼び出されると、接続されているかどうかを確認します。
  • 接続されていないことが検出された場合 (これOnConnect()は良くありませんでした)、 を呼び出し、次に (パラメーターなしで) を呼び出しCAsyncSocket::Close()、次に呼び出しCAsyncSocket::Create()ますCAsyncSocket::Connect(server, port)

への最初の呼び出しにConnect()は、 への先行呼び出しがないことに注意してくださいCreate()

私の最初の本当の質問:

  • 2つの違いは何ですか?なぜCreate()必要なのですか?(それを削除するとクラッシュしなくなりますが、接続を再確立しても接続しません)

一般的な質問:

  • 上記のコードの設計で正確に間違っているのは何ですか?
  • これは一般的にどのように機能する必要がありますか?

編集:

Create()すべてのパスがthenを呼び出すようにコードを修正しましたConnect()

私はまだアサートに問題がありますCAsyncSocket::DoCallBack()- 以下のコードの最後の行はアサートしています:

void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
    if (wParam == 0 && lParam == 0)
        return;

    // Has the socket be closed - lookup in dead handle list
    CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE);

    // If yes ignore message
    if (pSocket != NULL)
        return;

    pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE);
    if (pSocket == NULL)
    {
        // Must be in the middle of an Accept call
        pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE);
        ENSURE(pSocket != NULL);

それをステップスルーすると、メッセージボックスが表示されます:「不適切な引数に遭遇しました」

ソケットを閉じた後、MFC がソケットをコールバックしようとしていると思います (確かではありません)。コールバック メソッド ( )にありますが、ソケットでDoCallback()既に呼び出しています。Close()

したがって、最初に購読を解除することになっていない限り、MFC の問題のように見えます。

4

2 に答える 2

6

本当にあなたの選択。別のソケットの実装でもっとうまくいくと思われる場合は、それを実行してください。

ただし、Microsoft には多くの開発者がいます (中には優秀な開発者もいると思います)。障害がすべて自分の側にあるわけではない可能性を考慮したいかもしれません。

私の意見では、API と製品について得られるサポートの量も十分です。

おそらく、時間をかけて MFC モデルを理解すれば、その "AHA" の瞬間を迎えて、よりよく理解できるでしょう。私は Winsock のファンではありません - 私は同期が進むべき道だった UNIX の世界に慣れており、非同期タイプの動作が必要な場合は別のプロセス/スレッドを実行するだけでした。

CAsyncSocket は、MFC が (GUI に関して) シングル スレッド モデルであるという事実によって、依然として足を引っ張られているのではないかと思います。[その身動きの取れないコメントについては間違っているかもしれません。Win32 を直接使用してからしばらく経ちました]。


アップデート:

あなたが何をしていたかを述べた更新に基づいて、作成する前に接続することは許可されていないと確信しています. http://msdn.microsoft.com/en-us/library/3d46645f(VS.80).aspxを引用すると、

CAsyncSocket オブジェクトを使用するには、そのコンストラクターを呼び出してから、Create 関数を呼び出して基になるソケット ハンドルを作成し、クライアント ソケットの場合は Connect メンバー関数を呼び出します。

理由については、メインの GUI スレッドをブロックできないため、Windows はイベントポンピング環境で非同期ソケットを実行する必要があるため、これは余分な複雑さが追加されたと思います。

UNIXy 環境では、イベント スレッドがない (通常のプロセス) か、ネットワーク操作が別のスレッドに手動で (GUI アプリで) ファーム オフされます。

これはおそらくずっと前に WinSock で行われた設計上の決定であり (おそらく、非同期操作を実行するためのはるかに制限された環境であった Windows 3.11 で)、実行されました [ただし、これは私の推測ですが、UNIX ソケット API にはこれがありませんでした。メッセージがポンピングされる一種の非同期動作であり、常にselect()スレッド/プロセスを使用する傾向があります]。


さらに更新:

このアサーション (例外ではない) は通常、保留中の操作があるソケット オブジェクトを閉じたり削除したりした場合に発生します。あなたの場合、閉じたときにまだ接続を試みていることをお勧めします。

次に、接続が成功または失敗すると、コールバックが呼び出され、テーブルでソケットが見つかりません。

これは MFC の問題ではなく、契約に違反している友人のコードです。接続 (または任意の非同期操作) を行う場合、ソケットを閉じる (またはさらに作業する) 前に、成功または失敗を待つ必要があります。この場合、それは OnConnect() 関数の呼び出しを待つことを意味します。

メモリからcreate()、非同期ソケットを作成するときに を呼び出すと、メッセージ キューに到着したメッセージ (つまり、関数の呼び出し) に応答して他のすべての処理が行われますOnXXX()。すべての Win32 GUI のものと同様に、メッセージはプログラムを駆動することになっています (コードはメッセージに応答して実行されます)。このコードは、プログラムがすべてを駆動する古典的なコーディングのように見えます。そのようにすると、プログラムと非同期ソケットの「スレッド」が制御をめぐって争うので、狂気のようになります。

しばらく見ていませんでしたが、その方法を示す CHATSRVR サンプル プログラムを手に入れることができるはずです。

于 2009-04-29T03:32:53.753 に答える
4

問題はコードの記述が不十分である可能性が高く、MFC とはほとんどまたはまったく関係がない可能性が高いです。しかし、「あらゆる種類のデバッグ アサーションをスローする MFC アプリケーションがあります。どうすればよいですか?」という説明から確実に言うのは難しいです。

書き直しが必要なのかもしれませんが、アプリケーションについて詳しく知らなければ、誰も本当のことを言うことはできません。あなた(またはあなたの友人)はその決断を下す必要があると思います.

于 2009-04-29T03:25:32.833 に答える