DOCUMENT:Q138692 08-NOV-2001 [visualc] TITLE :HOWTO: Configure a Time-Out on a CSocket Operation PRODUCT :Microsoft C Compiler PROD/VER::1.0 OPER/SYS: KEYWORDS:kbcode kbnetwork kbAPI kbMFC kbSDKPlatform kbTimer kbVC151 kbVC200 kbVC400 kbWinsock kb ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - Microsoft Foundation Classes (MFC), version 1.0 ------------------------------------------------------------------------------- SUMMARY ======= CSocket operations, such as Receive, Send, and Connect, are blocking operations in the sense that a call to these functions will not return until it has successfully completed or an error on the socket has occurred. Under some circumstances, the operation might never complete successfully and your program will loop forever while waiting for this completion. It might be a good idea to programmatically limit the amount of time allowed for the operation to complete. This article discusses one way to do it. MORE INFORMATION ================ One approach would be to set a timer that fires when the operation has taken too long. The key to this approach is in how the timer is handled. Although the operation is "blocking," you still have the ability to handle messages that arrive. If you set a timer by using SetTimer, then you can look for the WM_TIMER message, and abort the operation when it arrives. The primary functions involved in this process are: The Windows API call: ::SetTimer The MFC functions: CSocket::OnMessagePending CSocket::CancelBlockingCall For simplicity, this functionality can be encapsulated in your CSocket- derived class. WARNING: Before reading further, note that there is a bug in some versions of MFC that will cause problems if you attempt to use a timer and override OnMessagePending. This problem is documented in the following Microsoft Knowledge Base article: Q137632 BUG: OnMessagePending Not Called When a Timer Is Active This article applies only to versions 1.52, 1.52b, 2.1, and 2.2 of Visual C++. If you are using one of these versions of Visual C++, then you will also need to implement the workaround that is supplied. The sample code for a class that provides this time-out capability is included at the end of this article. The functions implemented by the class are described in the following sections of this article. BOOL SetTimeOut(UINT uTimeOut) ------------------------------ This would be called immediately before calling the CSocket function (for example, Receive, Send, and Accept). The uTimeOut parameter is specified in milliseconds. The following implementation simply sets up the timer. This function returns FALSE if the attempt to set the timer failed. See the Windows API documentation on the SetTimer function for further details. BOOL KillTimeOut() ------------------ This function needs to be called after the completion of the operation that was blocking. It removes the timer that was set up with SetTimeOut. It returns FALSE if the call to KillTimer failed. See the Windows API documentation on the KillTimer function for further details. BOOL OnMessagePending() ----------------------- This is a virtual callback that is called by the CSocket class when it is waiting for an operation to complete. It gives you the opportunity to do something with incoming messages. This implementation checks for the WM_TIMER message for the timer set with the SetTimeOut call. And if it arrives then it invokes the CancelBlockingCall function. See the MFC documentation on the OnMessagePending and CancelBlockingCall functions for details. Please note that by calling CancelBlockingCall, you will cause the operation to fail and GetLastError will return WSAEINTR (indicating an interrupted operation). Here is an example use of this class: ... CTimeOutSocket sockServer; CAcceptedSocket sockAccept; sockServer.Create(777); sockServer.Listen(); // Note the following sequence: // SetTimeOut // // KillTimeOut if(!sockServer.SetTimeOut(10000)) { ASSERT(FALSE); // Error Handling...for some reason, we could not setup // the timer. } if(!sockServer.Accept(sockAccept)) { int nError = GetLastError(); if(nError==WSAEINTR) AfxMessageBox("No Connections Arrived For 10 Seconds"); else ; // Do other error processing. } if(!sockServer.KillTimeOut()) { ASSERT(FALSE); // Error Handling...for some reason the timer could not // be destroyed...perhaps a memory overwrite has changed // m_nTimerID? // } ... Sample Code ----------- // // HEADER FILE // class CTimeOutSocket : public CSocket { public: BOOL SetTimeOut(UINT uTimeOut); BOOL KillTimeOut(); protected: virtual BOOL OnMessagePending(); private: int m_nTimerID; }; // // END OF FILE // // // IMPLEMENTATION FILE // 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) { m_nTimerID = SetTimer(NULL,0,uTimeOut,NULL); return m_nTimerID; } BOOL CTimeOutSocket::KillTimeOut() { return KillTimer(NULL,m_nTimerID); } REFERENCES ========== For more information on the SetTimer and KillTimer functions, please see the Windows API Help file. For more information on the CSocket class and its member functions, please see: In Visual C++ 2.x - The MFC Help file. In Visual C++ 1.5x - The Mfcext.hlp help file, which can be found on the compact disc in the \Msvc15\Help directory. Additional query words: timing ====================================================================== Keywords : kbcode kbnetwork kbAPI kbMFC kbSDKPlatform kbTimer kbVC151 kbVC200 kbVC400 kbWinsock kbCodeSam kbGrpDSNet Technology : kbAudDeveloper _IKkbbogus kbMFC Version : :1.0 Issue type : kbhowto ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2001.