配置 CSocket 操作的超时时间

    技术2022-05-20  38

    摘要:

          CSocket 操作,如“接收”(Receive)、“发送”(Send) 和“连接”(Connect) 均是阻塞操作,即要等到操作成功执行完毕或套接字上出现错误后,对这些函数的调用才有返回结果。       在某些情况下,操作可能永远不能成功完成,这将导致程序无限循环等待操作完成。一种解决方法是通过编程限制完成操作使用的时间。本文将讨论这种方法。

     

    实现方法:

           这种方法是设置定时,让它在操作时间过长时启动。此方法的关键在于处理定时器的方式。虽然操作是“阻塞的”,但仍然可以处理到达的消息。如果通过使用 SetTimer 设置定时器,那么可以查找 WM_TIMER 消息,并在收到该消息时终止操作。该过程中涉及的主要函数有:

              Windows API 调用函数: ::SetTimer

    MFC 函数: CSocket::OnMessagePending                   CSocket::CancelBlockingCall

    为简单起见,可以在 CSocket 衍生类中封装该功能。 手写如下函数:

    BOOL SetTimeOut(UINT uTimeOut)       调用此函数之后仅接着调用 CSocket 函数(如 Receive、Send 和 Accept)。uTimeOut 参数是以毫秒为单位指定的。之后,进行定时器的设置。如果设置定时器失败,那么函数返回 FALSE。

    BOOL KillTimeOut()  

         在完成阻塞操作后,必须调用此函数。此函数删除用 SetTimeOut 设置的定时器。如果调用 KillTimer 失败,则返回 FALSE。

    BOOL OnMessagePending()      这是一个虚拟回调函数,在等待操作完成时由 CSocket 类进行调用。此函数给您提供处理传入消息的机会。此实施过程检查用 SetTimeOut 调用函数设置的定时器的 WM_TIMER 消息。如果收到消息,则调用 CancelBlockingCall 函数。有关 OnMessagePending 和 CancelBlockingCall 函数详细的信息,请参阅 MFC 文档。请注意:调用 CancelBlockingCall 函数 将导致操作失败,而且 GetLastError 函数返回 WSAEINTR(表示操作中断)。     

          CTimeOutSocket sockServer; CAcceptedSocket sockAccept; sockServer.Create(777); sockServer.Listen(); // Note the following sequence: // SetTimeOut // <operation which might block> // 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? // } 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); }


    最新回复(0)