CSocket 是一个同步的socket类,如“接收”(Receive)、“发送”(Send) 和“连接”(Connect) 均是阻塞操作,即要等到操作成功执行完毕或套接字上出现错误后,对这些函数的调用才有返回结果。如果连接不上,只有超时以后才能返回。
在某些情况下,操作可能永远不能成功完成,这将导致程序无限循环等待操作完成。例如错误的域名解释,连接不上的IP地址,这回让用户等待近 40秒钟的时间(可能是默认的超时时间),而且等待期间,程序将会"假死", 如果这种情况频繁出现,软件就无法使用了。
微软MSDN上提供了一种解决方法:通过编程限制完成操作使用的时间。只要超过这个时间,无论是否成功都要返回。
示例代码:
//
// HEADER FILE
//
class TimeOut_CSocket : public CSocket
{
public:
BOOL SetTimeOut(UINT uTimeOut);
BOOL KillTimeOut();
protected:
virtual BOOL OnMessagePending();
private:
int m_nTimerID;
};
//
// END OF FILE
//
//
// IMPLEMENTATION FILE
//
BOOL TimeOut_CSocket::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 TimeOut_CSocket::SetTimeOut(UINT uTimeOut)
{
m_nTimerID = SetTimer(NULL,0,uTimeOut,NULL);
return m_nTimerID;
}
BOOL TimeOut_CSocket::KillTimeOut()
{
return KillTimer(NULL,m_nTimerID);
}
有了这个CSocket的派生类后,就能自由设置 自己的 超时时间了,例如:
...
TimeOut_CSocket 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?
//
}
...
这个方法经过测试还是有很大地局限性,当服务器联通时,确实能按照超时时间返回,但如果域名解释有问题或者ip地址连接不上,还是需要等待20s以上的超时时间。
要达到商业化软件的要求,我们推荐还是用专业的socket组件解决网络操作问题, 例如
糖果专业下载组件 就能做到 程序随时可以退出,永不"假死":
糖果专业下载组件 支持 多源 多线程下载, 支持各种代理,尤其是 能够穿透 局域网中的 ISA Server代理服务器(需要支持NTLM认证),做到IE能上网,软件就能上网。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1763529