CSocketクラスでタイムアウトを発生させる方法

[戻る]
よし 2014/07/25(金) 17:20:24
長文の質問で失礼します。

環境:VS2012 MFC

ある機器とソケットでHTTP通信するAPを作成していまして、CSocketを使用しています。
相手が無応答の時タイムアウトを発生させる為に別スレッドで監視しタイムアウトになっ
たら、
CancelBlockingCall()でブロックを解除して対処しました。

そこで他の方法として、下記URLにCSocketでのタイムアウトを発生させるサンプルが載っ
ていましたが、うまくいきません。
OnMessagePending内のCancelBlockingCall()に到達しません。
従って、@のiniSock.Receive関数から帰ってきません。しかしSetTimerが0でない数値を
返すのは確認しました。

下記方法でのタイムアウト処理の方がソースがシンプルで良さそうなのですが、
私が作成したサンプルで問題点など判りましたらご指摘頂けないでしょうか?

参考URL
http://support.microsoft.com/kb/138692/ja


//テストダイアログ画面でボタン押し
void CTestDlg::OnButton1()
{
    CTimeOutSocket iniSock;

    if (!iniSock.Create() )    {
        // エラー処理
        return;
    }
    if(! iniSock.Connect(IPアドレス, ポート番号))
    {
        // エラー処理
        return;
    }

    // 相手は無応答を承知でタイムアウト1秒で1文字受信を試みる
    iRet = iniSock.Receive(szBuff, 1, 1000, 0);  //@ここで無限待ち
    if ( iRet == SOCKET_ERROR)
    {
        if (GetLastError() == WSAEINTR)
            AfxMessageBox("タイムアウト");
    }

    iniSock.Close();
}

//CTimeOutSocket.h
class CTimeOutSocket : public CSocket
{
public:
   BOOL SetTimeOut(UINT uTimeOut);
   BOOL KillTimeOut();
   int Receive(char *buf, DWORD length, DWORD uTimeout, int flags);
protected:
   virtual BOOL OnMessagePending();
private:
   int m_nTimerID;
};

//CTimeOutSocket.cpp
BOOL CTimeOutSocket::OnMessagePending()
{
    MSG msg;
    if(::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE))
    {
        if (msg.wParam == (UINT) m_nTimerID)
        {
            // Remove the message and call CancelBlockingCall.
            ::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);    // ←こ
こを通過しない!
            CancelBlockingCall();
               return FALSE;  // No need for idle time processing.
          };
    };
    return CSocket::OnMessagePending();
}

BOOL CTimeOutSocket::SetTimeOut(UINT uTimeOut)
{
    CString    strMsg;
    m_nTimerID = SetTimer(NULL,0,uTimeOut,NULL);

    strMsg.Format("[ID=%d\n]", m_nTimerID);
    TRACE(strMsg);
    return m_nTimerID;
}

BOOL CTimeOutSocket::KillTimeOut()
{
    return KillTimer(NULL,m_nTimerID);
}

int CTimeOutSocket::Receive(char *buf, DWORD length, DWORD uTimeout, int flags)
{
    if( uTimeout > 0) {
        SetTimeOut( uTimeout);
    }
    int ret = CSocket::Receive( buf, length, flags);
    if( uTimeout > 0) {
         KillTimeOut();
    }
    return(ret);
}

よし 2014/07/28(月) 11:48:06
[[解決]]
自己解決しました。

下記情報によると、ワーカースレッドで動作するとの事で、サンプルをスレッドで実行
するようにしましたら、問題なく動作致しました。
当初のサンプルの様にダイアログのボタン押しのイベント内では駄目なようです。

http://www.serkey.com/csocket-timeout-problem-bd3b9a.html

古いスレッドには追加発言できません。