彻底解决关于CSocket类的Receive超时的问题
2017-05-22 18:10
447 查看
网上有一些相关的东西,但经自己测试后,并没有实现功能。OnMessagePending没有监测到WM_TIMER消息。
然后我对类进行了调整,一来使得封装更好,二来外部调用基本不用做任何变化,三来希望能使OnMessagePending能够起作用。
其实修改很简单,就是将SetTimeOut和KillTimeOut都修改为私有函数,并重载CSocket基类的Receive和Send函数,在收发前后启动和关闭定时器。
注意:原文中 if(::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE))语句并没有实现获取WM_TIMER消息的功能,后来,经过网上查找资料
PM_NOREMOVE 修改为PM_REMOVE
头文件 ClientSocket.h
#pragma once
#include "afxwin.h"
#include <afxsock.h>
// CClientSocket 命令目标
class CTimeOutSocket : public CSocket
{
// Attributes
public:
CTimeOutSocket();
virtual~CTimeOutSocket();
public:
virtual BOOL OnMessagePending();
virtual int Receive(void* lpBuf, int nBufLen, int nFlags =0);
virtual int Send(const void* lpBuf, int nBufLen, int nFlags =0);
virtual int SendTo(const void* lpBuf, int nBufLen,UINT nHostPort, LPCTSTR lpszHostAddress , int nFlags);
virtual int ReceiveFrom(void* lpBuf, int nBufLen,CString& rSocketAddress, UINT& rSocketPort, int nFlags);
int m_nTimerID;
private:
BOOL KillTimeOut();
BOOL SetTimeOut(int nTimeOut);
};
以下为ClientSocket.c文件
#include "stdafx.h"
#include "ClientSocket.h"
CTimeOutSocket::CTimeOutSocket()
{
}
CTimeOutSocket::~CTimeOutSocket()
{
}
BOOL CTimeOutSocket::OnMessagePending()
{
MSG msg;
if(::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE))//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();
}
int CTimeOutSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
{
SetTimeOut(5000);
int nRecv = CSocket::Receive(lpBuf, nBufLen, nFlags);
KillTimeOut();
return nRecv;
}
int CTimeOutSocket::ReceiveFrom(void* lpBuf, int nBufLen,CString& rSocketAddress, UINT& rSocketPort, int nFlags)
{
SetTimeOut(10000);
int nRecv = CSocket::ReceiveFrom(lpBuf, nBufLen, rSocketAddress, rSocketPort,nFlags);
KillTimeOut();
return nRecv;
}
int CTimeOutSocket::Send(const void* lpBuf, int nBufLen, int nFlags)
{
SetTimeOut(10000);
int nSend = CSocket::Send(lpBuf, nBufLen, nFlags);
KillTimeOut();
return nSend;
}
int CTimeOutSocket::SendTo(const void* lpBuf, int nBufLen,UINT nHostPort, LPCTSTR lpszHostAddress, int nFlags )
{
SetTimeOut(10000);
int nSend = CSocket::SendTo(lpBuf, nBufLen, nHostPort,lpszHostAddress,nFlags);
KillTimeOut();
return nSend;
}
BOOL CTimeOutSocket::SetTimeOut(int nTimeOut)
{
m_nTimerID = SetTimer(NULL,0,nTimeOut,NULL);
return m_nTimerID;
}
BOOL CTimeOutSocket::KillTimeOut()
{
return KillTimer(NULL,m_nTimerID);
}
经过修改的代码,运行后OnMessagePending得到了WM_TIMER消息,正确解决了Receive的阻塞问题,同时我只需将原来的CSocket对象改为CTimeOutSocket对象就可以了,以上代码经测试可直接使用。
然后我对类进行了调整,一来使得封装更好,二来外部调用基本不用做任何变化,三来希望能使OnMessagePending能够起作用。
其实修改很简单,就是将SetTimeOut和KillTimeOut都修改为私有函数,并重载CSocket基类的Receive和Send函数,在收发前后启动和关闭定时器。
注意:原文中 if(::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE))语句并没有实现获取WM_TIMER消息的功能,后来,经过网上查找资料
PM_NOREMOVE 修改为PM_REMOVE
头文件 ClientSocket.h
#pragma once
#include "afxwin.h"
#include <afxsock.h>
// CClientSocket 命令目标
class CTimeOutSocket : public CSocket
{
// Attributes
public:
CTimeOutSocket();
virtual~CTimeOutSocket();
public:
virtual BOOL OnMessagePending();
virtual int Receive(void* lpBuf, int nBufLen, int nFlags =0);
virtual int Send(const void* lpBuf, int nBufLen, int nFlags =0);
virtual int SendTo(const void* lpBuf, int nBufLen,UINT nHostPort, LPCTSTR lpszHostAddress , int nFlags);
virtual int ReceiveFrom(void* lpBuf, int nBufLen,CString& rSocketAddress, UINT& rSocketPort, int nFlags);
int m_nTimerID;
private:
BOOL KillTimeOut();
BOOL SetTimeOut(int nTimeOut);
};
以下为ClientSocket.c文件
#include "stdafx.h"
#include "ClientSocket.h"
CTimeOutSocket::CTimeOutSocket()
{
}
CTimeOutSocket::~CTimeOutSocket()
{
}
BOOL CTimeOutSocket::OnMessagePending()
{
MSG msg;
if(::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE))//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();
}
int CTimeOutSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
{
SetTimeOut(5000);
int nRecv = CSocket::Receive(lpBuf, nBufLen, nFlags);
KillTimeOut();
return nRecv;
}
int CTimeOutSocket::ReceiveFrom(void* lpBuf, int nBufLen,CString& rSocketAddress, UINT& rSocketPort, int nFlags)
{
SetTimeOut(10000);
int nRecv = CSocket::ReceiveFrom(lpBuf, nBufLen, rSocketAddress, rSocketPort,nFlags);
KillTimeOut();
return nRecv;
}
int CTimeOutSocket::Send(const void* lpBuf, int nBufLen, int nFlags)
{
SetTimeOut(10000);
int nSend = CSocket::Send(lpBuf, nBufLen, nFlags);
KillTimeOut();
return nSend;
}
int CTimeOutSocket::SendTo(const void* lpBuf, int nBufLen,UINT nHostPort, LPCTSTR lpszHostAddress, int nFlags )
{
SetTimeOut(10000);
int nSend = CSocket::SendTo(lpBuf, nBufLen, nHostPort,lpszHostAddress,nFlags);
KillTimeOut();
return nSend;
}
BOOL CTimeOutSocket::SetTimeOut(int nTimeOut)
{
m_nTimerID = SetTimer(NULL,0,nTimeOut,NULL);
return m_nTimerID;
}
BOOL CTimeOutSocket::KillTimeOut()
{
return KillTimer(NULL,m_nTimerID);
}
经过修改的代码,运行后OnMessagePending得到了WM_TIMER消息,正确解决了Receive的阻塞问题,同时我只需将原来的CSocket对象改为CTimeOutSocket对象就可以了,以上代码经测试可直接使用。
相关文章推荐
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 关于CSocket类的Receive超时的问题
- 彻底解决asp里用ADO连接数据库的超时问题
- 关于linux下的udp/tcp通信设置发送sendto/接收recvfrom信息超时的参数。解决通道堵塞问题。
- 关于新浪微博SSO授权时出现 Weibo-authorize Failed to receive access token by SSO 的问题解决
- 关于在uwsgi server中出现cassandra超时问题的解决
- 关于MySQL数据库连接超时问题的分析与解决
- 关于android sdk path 问题的彻底解决方法 Android_SDK_HOME
- 关于android sdk path 问题的彻底解决 (2011-11-01 17:00:33)
- 彻底地/ 终于地, 解决 关于apache 权限的问题了:: 修改 DocumentRoot后的 403错误: have no permission to access / on this server
- 关于oj问题时间超时(Time Limit Error)的解决