myclientsocket.cpp

来自「这是另外一个基于CAsyncSocket类,客户端程序!」· C++ 代码 · 共 346 行

CPP
346
字号

#include "stdafx.h"
#include "MyClientSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const int TIMEOUT_CONNECT = 1000 * 30;	// 愙懕僞僀儉傾僂僩帪娫乮儈儕昩乯
const int TIMEOUT_SEND    = 1000 * 30;	// 憲怣僞僀儉傾僂僩帪娫乮儈儕昩乯
const int TIMEOUT_RECV    = 1000 * 30;	// 庴怣僞僀儉傾僂僩帪娫乮儈儕昩乯

CMyClientSocket::CMyClientSocket()
	: m_hEventCancel(NULL)
	, m_cs()
	, m_bConnected(false)
	, m_timerConnect(TIMEOUT_CONNECT)
	, m_bufSend()
	, m_nBytesSent(0)
	, m_timerSend(TIMEOUT_SEND)
	, m_bufRecv()
	, m_timerRecv(TIMEOUT_RECV)
	, m_errInfo()
{
	m_bufRecv.SetSize(0, 1024 * 128);

	m_hEventCancel = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}

CMyClientSocket::~CMyClientSocket()
{
	if (m_bConnected) {
		TRACE0("*** ~CMyClientSocket connected\n");
		ShutDown();
	} else {
		TRACE0("*** ~CMyClientSocket\n");
	}

	Close();
	m_bConnected = false;

	::CloseHandle(m_hEventCancel);
	m_hEventCancel = NULL;
}

bool CMyClientSocket::SyncConnect(LPCTSTR lpszHostAddress, UINT nHostPort)
{
	if (!Connect(lpszHostAddress, nHostPort)) {
		const DWORD dwSysErrCode = ::GetLastError();
		if (WSAEWOULDBLOCK != dwSysErrCode) {
			m_errInfo = CErrInfo(CErrInfo::errConnect, dwSysErrCode);
			return false;
		}

		m_timerConnect.ResetTimer();

		while (true) {
			// 僜働僢僩儊僢僙乕僕傪張棟偟偮偮僉儍儞僙儖/僞僀儉傾僂僩摍傪僠僃僢僋
			if (!onMessagePending(&m_timerConnect)) {
				return false;
			}
			if (m_bConnected) {
				// OK両愙懕姰椆
				break;
			}
			TRACE0("trying to connect to the server.\n");
		}
	} else {
		// 偄偒側傝愙懕姰椆丅愙懕嵪傒僼儔僌傪棫偰偰偍偔丅
		m_bConnected = true;
	}

	return true;
}

bool CMyClientSocket::SyncSend(const void* lpBuf, int nDataLen, int nFlags)
{
	m_nBytesSent = 0;
	m_bufSend.SetSize(nDataLen, 0);
	memcpy(m_bufSend.GetData(), lpBuf, nDataLen);

	const int nBytesSent = doAsyncSendBuff();

	if (nBytesSent != m_bufSend.GetSize()) {
		//
		// 憲怣偱偒側偐偭偨僨乕僞偑巆偭偰偄傞丅
		// 埲崀丄OnSend 撪偱巆傝偺僨乕僞偑憲怣偝傟傞丅
		//
		const DWORD dwSysErrCode = ::GetLastError();
		if (WSAEWOULDBLOCK != dwSysErrCode) {
			m_errInfo = CErrInfo(CErrInfo::errSend, dwSysErrCode);
			return false;
		}

		m_timerSend.ResetTimer();

		while (true) {
			// 僜働僢僩儊僢僙乕僕傪張棟偟偮偮僉儍儞僙儖/僞僀儉傾僂僩摍傪僠僃僢僋
			if (!onMessagePending(&m_timerSend)) {
				return false;
			}
			if (m_nBytesSent == m_bufSend.GetSize()) {
				// 慡僨乕僞憲怣姰椆
				break;
			}
			TRACE0("trying to send data.\n");
		}
	}

	return true;
}

//	HTTP愱梡乮僒乕僶乕偑僜働僢僩傪暵偠傞傑偱庴怣乯
bool CMyClientSocket::SyncReceive()
{
	m_timerRecv.ResetTimer();

	while (true) {
		// 僜働僢僩儊僢僙乕僕傪張棟偟偮偮僉儍儞僙儖/僞僀儉傾僂僩摍傪僠僃僢僋
		if (!onMessagePending(&m_timerRecv)) {
			return false;
		}

		// 僒乕僶乕懁偺 Close 偵傛偭偰庴怣姰椆傪抦傞
		if (!m_bConnected) {
			TRACE0("Response OK\n");
			// 枹庴怣偺僨乕僞偑偁傟偽慡偰庢傝弌偡
			while (doReceive("*** ReceiveRemain")) {
				;
			}
			if (m_errInfo.IsError()) {
				return false;
			}
			break;
		}
	}

	return true;
}

void CMyClientSocket::SetCancel()
{
	::SetEvent(m_hEventCancel);
}

bool CMyClientSocket::IsCanceled() const
{
	bool bCanceled = false;
	if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEventCancel, 0)) {
		bCanceled = true;
	}
	return bCanceled;
}

int CMyClientSocket::GetReceivedBytes() const
{
	int nBytesReceived = 0;
	{
		// 僋儕僥傿僇儖僙僋僔儑儞偱 m_bufRecv 傪庣傞
		CSingleLock sl(&const_cast<CMyClientSocket*>(this)->m_cs, TRUE);
		nBytesReceived = m_bufRecv.GetSize();
	}
	return nBytesReceived;
}

void CMyClientSocket::RetrieveRecvData(CByteArray& recvData) const
{
	// 僋儕僥傿僇儖僙僋僔儑儞偱 m_bufRecv 傪庣傞
	CSingleLock sl(&const_cast<CMyClientSocket*>(this)->m_cs, TRUE);
	recvData.Copy(m_bufRecv);
}

const CErrInfo* CMyClientSocket::GetErrInfo() const
{
	// 柺搢側偺偱偙傟偼僗儗僢僪僙乕僼偵偟側偄丅
	// 崱偺偲偙傠杮娭悢偼捠怣僗儗僢僪廔椆屻偵偟偐屇偽傟側偄偟丅
	return &m_errInfo;
}

void CMyClientSocket::OnConnect(int nSysErrCode)
{
	if (0 != nSysErrCode) {
		TRACE0("*** OnConnect ERROR!\n");
		m_errInfo = CErrInfo(CErrInfo::errConnect, nSysErrCode);
	} else {
		TRACE0("*** OnConnect\n");
		m_bConnected = true;
	}

	// 儊僢僙乕僕偑棃傞偨傃偵僞僀儉傾僂僩寁應奐巒帪崗傪儕僙僢僩偡傞
	// OnConnect偺応崌偼堦搙偟偐棃側偄偼偢偩偗偳...
	m_timerConnect.ResetTimer();

//	CAsyncSocket::OnConnect(nSysErrCode);
}



void CMyClientSocket::OnReceive(int nSysErrCode)
{
	if (0 != nSysErrCode) {
		TRACE0("*** OnReceive ERROR1!\n");
		m_errInfo = CErrInfo(CErrInfo::errReceive, nSysErrCode);
	} else {
		doReceive("*** OnReceive");
	}

	// 儊僢僙乕僕偑棃傞偨傃偵僞僀儉傾僂僩寁應奐巒帪崗傪儕僙僢僩偡傞
	m_timerRecv.ResetTimer();

//	CAsyncSocket::OnReceive(nSysErrCode);
}

void CMyClientSocket::OnClose(int nSysErrCode)
{
	TRACE0("*** OnClose\n");

	m_bConnected = false;

//	CAsyncSocket::OnClose(nSysErrCode);
}

void CMyClientSocket::OnSend(int nSysErrCode)
{
	TRACE0("*** OnSend\n");

	if (0 != nSysErrCode) {
		m_errInfo = CErrInfo(CErrInfo::errSend, nSysErrCode);
	} else {
		doAsyncSendBuff();
	}

	// 儊僢僙乕僕偑棃傞偨傃偵僞僀儉傾僂僩寁應奐巒帪崗傪儕僙僢僩偡傞
	m_timerSend.ResetTimer();

//	CAsyncSocket::OnSend(nSysErrCode);
}

int CMyClientSocket::doAsyncSendBuff()
{
	int nSentThisTime = 0;

	while (m_nBytesSent < m_bufSend.GetSize()) {

		const int nBytesSent = Send(m_bufSend.GetData() + m_nBytesSent, m_bufSend.GetSize() - m_nBytesSent);

		if (SOCKET_ERROR == nBytesSent) {
			const DWORD dwSysErrCode = ::GetLastError();
			if (WSAEWOULDBLOCK != dwSysErrCode) {
				m_errInfo = CErrInfo(CErrInfo::errSend, dwSysErrCode);
			}
			break;
		}

		m_nBytesSent += nBytesSent;
		nSentThisTime += nBytesSent;
	}

	return nSentThisTime;
}

//
//	栠傝抣丗true ...傑偩巆傝偺僨乕僞偑偁傞偐傕丅
//			false...傕偆巆傝偺僨乕僞偑柍偄偐丄僄儔乕敪惗丅
//
bool CMyClientSocket::doReceive(LPCTSTR pszDebug)
{
	CByteArray buf;
	buf.SetSize(1024 * 64, 0);
	const int nBytesRead = Receive(buf.GetData(), buf.GetSize());

	bool bContinue = false;

	if (0 == nBytesRead) {
		// 婛偵愙懕偑暵偠傜傟偰偄傞
		TRACE("%s : received 0 byte.\n", pszDebug);

	} else if (0 < nBytesRead) {
		TRACE("%s : received %d bytes.\n", pszDebug, nBytesRead);
		buf.SetSize(nBytesRead, 0);
		{
			// 僋儕僥傿僇儖僙僋僔儑儞偱 m_bufRecv 傪庣傞
			CSingleLock sl(&m_cs, TRUE);
			m_bufRecv.Append(buf);
		}
		bContinue = true;

	} else {
		TRACE("%s : ERROR!\n", pszDebug);
		const DWORD dwSysErrCode = ::GetLastError();
		if (WSAEWOULDBLOCK != dwSysErrCode) {
			m_errInfo = CErrInfo(CErrInfo::errReceive, dwSysErrCode);
		} else {
			bContinue = true;
		}
	}

	return bContinue;
}

bool CMyClientSocket::onMessagePending(const CMyTimer* pTimer)
{
	DWORD dwTimeOut = pTimer->TimeLeft();

	DWORD dwResult = 0;
	if (0 < dwTimeOut) {
		dwResult = ::MsgWaitForMultipleObjects(
				1,					// DWORD nCount,			// 僆僽僕僃僋僩僴儞僪儖偺攝楍偵擖偭偰偄傞僴儞僪儖偺悢
				&m_hEventCancel,	// LPHANDLE pHandles,		// 僆僽僕僃僋僩僴儞僪儖偺攝楍傊偺億僀儞僞
				FALSE,				// BOOL fWaitAll,			// 偡傋偰傪懸婡偡傞偐丄偄偢傟偐 1 偮傪懸婡偡傞偐
				dwTimeOut,			// DWORD dwMilliseconds,	// 僞僀儉傾僂僩帪娫乮儈儕昩扨埵乯
				QS_ALLEVENTS);		// DWORD dwWakeMask);		// 懸婡偡傞擖椡僀儀儞僩偺庬椶
	} else {
		dwResult = WAIT_TIMEOUT;
	}

	if (dwResult == WAIT_OBJECT_0 + 1) {
		// 儊僢僙乕僕偑敪惗偟偰偄傞
		MSG msg;
		while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
			::DispatchMessage(&msg);
		}

		// 偦偺懠偺僄儔乕僠僃僢僋乮儊僢僙乕僕僴儞僪儔撪偱僄儔乕敪惗偺壜擻惈乯
		if (m_errInfo.IsError()) {
			TRACE0("onMessagePending: error occured.\n");
			return false;
		}
	}
	else if (dwResult == WAIT_OBJECT_0) {
		// 僉儍儞僙儖偝傟偨
		TRACE0("onMessagePending: canceled.\n");
		m_errInfo = CErrInfo(CErrInfo::errCanceled);
		return false;
	}
	else {
		// 僞僀儉傾僂僩偟偨
		TRACE0("onMessagePending: time out caused.\n");
		m_errInfo = CErrInfo(CErrInfo::errTimeOut);
		return false;
	}

	return true;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?