配置Csocket 操作的超时时间
最后修改 : 2005年8月24日
本文的发布号曾为 CHS138692
转载自www.blogjava/weidagang2046/articles/79285.html
转载自www.blogjava/weidagang2046/articles/79285.html
BOOL SetTimeOut(UINT uTimeOut)
BOOL KillTimeOut()
BOOL OnMessagePending()
示例代码
参考
概要
CSocket 操作,如“接收”(Receive)、“发送”(Send) 和“连接”(Connect) 均是阻塞操作,即要等到操作成功执行完毕或套接字上出现错误后,对这些函数的调用才有返回结果。
概要
CSocket 操作,如“接收”(Receive)、“发送”(Send) 和“连接”(Connect) 均是阻塞操作,即要等到操作成功执行完毕或套接字上出现错误后,对这些函数的调用才有返回结果。
在某些情况下,操作可能永远不能成功完成,这将导致程序无限循环等待操作完成。一种解决方法是通过编程限制完成操作使用的时间。本文将讨论这种方法。
这种方法是设置定时,让它在操作时间过长时启动。此方法的关键在于处理定时器的方式。虽然操作是“阻塞的”,但仍然可以处理到达的消息。如果通过使用 SetTimer 设置定时器,那么可以查 WM_TIMER 消息,并在收到该消息时终止操作。该过程中涉及的主要函数有:
Windows API 调用函数:
::SetTimer
MFC 函数:
CSocket::OnMessagePending
CSocket::CancelBlockingCall
为简单起见,可以在 Csocket 衍生类中封装该功能。
Windows API 调用函数:
::SetTimer
MFC 函数:
CSocket::OnMessagePending
CSocket::CancelBlockingCall
为简单起见,可以在 Csocket 衍生类中封装该功能。
警告:在进一步阅读本文之前,请注意在某些 MFC 版本中存在错误,会在试图使用定时
器并重叠 OnMessagePending 时引起问题。这一问题将在下面的 Microsoft Knowledge Base 文章中进行讨论:
137632 (support.microsoft/kb/137632/EN-US/) 错误:定时器激活时未调用 OnMessagePending
本文仅适用于 Visual C++ 的 1.52、1.52b、2.1 和 2.2 版本。如果使用的是这些 Visual C++ 版本之一,则还需要实施所提供的变通解决方法。
137632 (support.microsoft/kb/137632/EN-US/) 错误:定时器激活时未调用 OnMessagePending
本文仅适用于 Visual C++ 的 1.52、1.52b、2.1 和 2.2 版本。如果使用的是这些 Visual C++ 版本之一,则还需要实施所提供的变通解决方法。
本文最后部分显示提供这种超时功能的类的示例代码。以下内容讲述由该类实现的函数。
BOOL SetTimeOut(UINT uTimeOut)
调用此函数之后紧接着调用 CSocket 函数(如 Receive、Send 和 Accept)。uTimeOut 参数是以毫秒为单位指定的。之后,进行定时器的设置。如果设置定时器失败,那么函数返回 FALSE。有关详细情况,请参阅 SetTimer 函数的 Windows API 文档。
BOOL KillTimeOut()
在完成阻塞操作后,必须调用此函数。此函数删除用 SetTimeOut 设置的定时器。如果调用 KillTimer 失败,则返回 FALSE。有关详细情况,请参阅 KillTimer 函数的 Windows API 文档。
BOOL OnMessagePending()
这是一个虚拟回调函数,在等待操作完成时由 CSocket 类进行调用。此函数给您提供处理传入消息的机会。此实施过程检查用 SetTimeOut 调用函数设置的定时器的 WM_TIMER 消息。如果收到消息,则调用 CancelBlockingCall 函数。有关 OnMessagePending 和 CancelBlockingCall 函数详细的信息,请参阅 MFC 文档。请注意:调用 CancelBlockingCall 函数 将导致操作失败,而且 GetLastError 函数返回 WSAEINTR(表示操作中断)。
下面是使用该类的一个例子:
...
...
CTimeOutSocket sockServer;
CAcceptedSocket sockAccept;
CAcceptedSocket sockAccept;
sockServer.Create(777);
sockServer.Listen();
sockServer.Listen();
// Note the following sequence:
// SetTimeOut
//
// KillTimeOut
// SetTimeOut
//
// KillTimeOut
if(!sockServer.SetTimeOut(10000))
timeout on t2 timer {
ASSERT(FALSE);
// for some reason, we could not setup
// the timer.
}
timeout on t2 timer {
ASSERT(FALSE);
// 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.
}
{
int nError = GetLastError();
if(nError==WSAEINTR)
AfxMessageBox("No Connections Arrived For 10 Seconds");
else
; // Do other error processing.
}
if(!sockServer.KillTimeOut())
{
ASSERT(FALSE);
// for some reason the timer could not
// perhaps a memory overwrite has changed
// m_nTimerID?
//
{
ASSERT(FALSE);
// for some reason the timer could not
// perhaps a memory overwrite has changed
// m_nTimerID?
//
}
...
//
// HEADER FILE
//
class CTimeOutSocket : public CSocket
{
public:
BOOL SetTimeOut(UINT uTimeOut);
BOOL KillTimeOut();
protected:
virtual BOOL OnMessagePending();
private:
int m_nTimerID;
};
...
//
// HEADER FILE
//
class CTimeOutSocket : public CSocket
{
public:
BOOL SetTimeOut(UINT uTimeOut);
BOOL KillTimeOut();
protected:
virtual BOOL OnMessagePending();
private:
int m_nTimerID;
};
//
// END OF FILE
//
// 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.
};
};
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;
}
{
m_nTimerID = SetTimer(NULL,0,uTimeOut,NULL);
return m_nTimerID;
}
BOOL CTimeOutSocket::KillTimeOut()
{
{
return KillTimer(NULL,m_nTimerID);
}
CSOCKET的超时设置和UDP发送接收
使用CSoket多次了,但对于它的block模式的理解并不是很深入。昨天使用csoket的udp多发测试(server接到数据后,需要通过某种方式将数据发送到client,使用tcp方式比较可靠,我一直这样用的,但是比较费时,需要逐一发送),发现了问题:
}
CSOCKET的超时设置和UDP发送接收
使用CSoket多次了,但对于它的block模式的理解并不是很深入。昨天使用csoket的udp多发测试(server接到数据后,需要通过某种方式将数据发送到client,使用tcp方式比较可靠,我一直这样用的,但是比较费时,需要逐一发送),发现了问题:
1)create(),sendto(),receivefrom()....
2)其中,发送方一直定时发送数据无问题;
3)而接收方,通过一个单独的接收线程实现( 注意:csocket不能跨线程使用!主线程中socket create()后,detach()并将sock作为lpvoid传入接收线程 )。代码如下:
//处理接收数据
UINT CSockSvr::DealSvrRevData(LPVOID lParam)
{
UINT CSockSvr::DealSvrRevData(LPVOID lParam)
{
......
DWORD dwError;
TCHAR cBuff[1000];
CString sIP;
UINT uPort;
for(;!pDlg->m_bExit;)
{
::memset( cBuff,0,sizeof(cBuff) );
DWORD dwError;
TCHAR cBuff[1000];
CString sIP;
UINT uPort;
for(;!pDlg->m_bExit;)
{
::memset( cBuff,0,sizeof(cBuff) );
// 如果没有接到数据,一直等待。。。。
// 阻塞模式的弊端:::在退出时候,通过CancelBlockingCall
int iRst=SockSvr.ReceiveFrom( cBuff,sizeof(cBuff),sIP,uPort,0 );
if( iRst!=SOCKET_ERROR )
{
CString sTemp=cBuff;
TRACE1( _T("\r\n Rev Data: %s\r\n"),sTemp );
// 阻塞模式的弊端:::在退出时候,通过CancelBlockingCall
int iRst=SockSvr.ReceiveFrom( cBuff,sizeof(cBuff),sIP,uPort,0 );
if( iRst!=SOCKET_ERROR )
{
CString sTemp=cBuff;
TRACE1( _T("\r\n Rev Data: %s\r\n"),sTemp );
}
else
{
dwError=GetLastError();
TRACE1( _T("\r\n Rev Data Error code: %d\r\n"),dwError );
}
::Sleep(200);
}
return 0;
}
else
{
dwError=GetLastError();
TRACE1( _T("\r\n Rev Data Error code: %d\r\n"),dwError );
}
::Sleep(200);
}
return 0;
}
问题:如果发送方没有数据,SockSvr.ReceiveFrom()会一致处于等待状态,导致整个处理接收线程的停止,如果用户需要退出/结束程序,无法正确释放资源(无法关闭在线程函数重打开的socket--不能跨线程操作socket,无法关闭线程),造成系统
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论