徹底解決關於CSocket類的Receive超時的問題(轉)
轉自: https://blog.csdn.net/enlaihe/article/details/72628700
網上有一些相關的東西,但經自己測試後,並沒有實現功能。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設定超時(轉)
- 如何徹底解決pip install慢的問題
- 徹底解決Python編碼問題Python
- 徹底解決Hive小檔案問題Hive
- 一次弄懂Event Loop(徹底解決此類面試問題)OOP面試
- 徹底解決SLF4J的日誌衝突的問題
- 關於Failed to resolve的問題解決AI
- 徹底解決第三方分享icon過大的問題
- 使用Seata徹底解決Spring Cloud中的分散式事務問題!SpringCloud分散式
- 16.徹底解決Jmap在mac版本無法使用的問題Mac
- 解決代理超時問題的三種方法
- 解決Hexo關於圖片的問題Hexo
- 關於解決問題的幾個段位
- 解決 go get 超時問題Go
- 怎樣成為解決問題的高手?——關於問題解決的關鍵4步驟
- 徹底解決java WEB專案的檔案路徑問題(war包)JavaWeb
- 九種 “姿勢” 讓你徹底解決跨域問題跨域
- 關於 LF will be replaced by CRLF 問題的解決方式
- MySQL 8.0能徹底解決困擾運維的複製延遲問題!MySql運維
- 解決代理連線超時問題
- 透過 Pulsar 原始碼徹底解決重複消費問題原始碼
- 徹底解決Asp.netCore WebApi 3.1 跨域時的預檢查204 options重複請求的問題ASP.NETNetCoreWebAPI跨域
- CSocket 是阻塞的(轉)
- Selenium爬蟲遇到超時TimeOut問題的解決方法爬蟲
- 令人拍案叫絕的 Wasserstein GAN,徹底解決GAN訓練不穩定問題
- 關於 PHP Session ID 改變的問題解決PHPSession
- 徹底搞懂Python中的類Python
- 關於BGE-M3接入LangChain時遇到的問題與解決方法LangChain
- 徹底解決Linux下mongodb的安裝LinuxMongoDB
- 【徹底搞懂】vite proxy如何解決跨域問題Vite跨域
- 使用requests庫解決Session物件設定超時的問題Session物件
- 一行程式碼徹底終結關於物件/陣列的深拷貝問題行程物件陣列
- 解決關於IIS gzip不能正常啟用的問題
- 關於input的一些問題解決方法分享
- NeurIPS 2024|浙大 & 微信 & 清華:徹底解決擴散模型反演問題模型
- 關於在執行java連線MongoDB時遇到的連線超時問題JavaMongoDB
- 關於問問題和時間管理的感悟
- 關於從其他程式切回word文件時卡頓問題的解決辦法