⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dpsocketmodel.cpp

📁 DarkATLSmtp(SMTP COM 组件原创代码),注册后可在Delphi中发邮件。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// DPEventSocket.cpp: implementation of the CDPSocketModel class.
//作者:高越 邮箱:darkprince@v.cn
//QQ:1738387 (本人只接受技术探讨以及软件项目合作事宜,其他误扰)
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DPSocketModel.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDPSocketModel::CDPSocketModel()
{
	::InitializeCriticalSection(&m_csErrorNo);
}

CDPSocketModel::~CDPSocketModel()
{
	::DeleteCriticalSection(&m_csErrorNo);
}

// 设置套接字是否为阻塞的
//入口:套接字,是否需要阻塞的
//出口:如果正确那么返回0,错误返回-1
int CDPSocketModel::DPBlockSocket(SOCKET hSocket, BOOL bBlock/*FALSE*/)
{
	u_long IoctlLong = (bBlock) ? 0 : 1;

	if (ioctlsocket(hSocket, FIONBIO, &IoctlLong) == SOCKET_ERROR)
	{
		DPSetLastError( WSAGetLastError() );
		return (SOCKET_ERROR);
    }
	return (SOCKET_SUCCESS);
}

//设置套接字属性
//入口:套接字
//出口:如果正确那么返回0,错误返回-1
int CDPSocketModel::DPSetSocketOption(SOCKET hSocket)
{

    int nActivate = 1;

	//允许地址重用
    if (setsockopt(hSocket, SOL_SOCKET, SO_REUSEADDR, (const char *) &nActivate,
		sizeof(nActivate)) == SOCKET_ERROR )
    {
        DPSetLastError( WSAGetLastError() );
        return (SOCKET_ERROR);//return (-1)
    }

	//  如果支持,设置KEEPALIVE属性 (这样做会带来其他不良后果)
	//setsockopt(hSocket, SOL_SOCKET, SO_KEEPALIVE, (const char *) &nActivate,sizeof(iActivate));

	return (SOCKET_SUCCESS);
}

//接收所有数据,注意在这个函数调用之前必须确认是否有接收消息到来
//入口:套接字,数据缓冲区,缓冲区大小
//出口:如果正确那么返回接收的字节数量,错误返回错误代码
//注意:这里使用的是WINSOCK2的专有WSARecv()函数进行接收,所以为非阻塞模式
//     所以调用此函数前必须确认有数据到来的消息,否则返回错误
int CDPSocketModel::DPRecvLL(SOCKET hSocket, char *pszBuffer, int nBufferSize)
{
	DWORD		dwRtxBytes = 0,
				dwRtxFlags = 0;
	WSABUF		WSABuff;

	//清空缓冲
	ZeroMemory(&WSABuff,sizeof(WSABUF));

	WSABuff.len = nBufferSize;
	WSABuff.buf = pszBuffer;
	//如果正确就返回本次接收的字节个数,如果错误返回错误号码(负数)
	return ((WSARecv(hSocket, &WSABuff, 1, &dwRtxBytes, &dwRtxFlags,NULL, NULL) 
		== SOCKET_SUCCESS) ? (int) dwRtxBytes : -WSAGetLastError());
}

int CDPSocketModel::DPRecvData_Block(SOCKET hSocket, char *pszBuffer, int nBufferSize, 
		DWORD dwTimeout)
{
	ASSERT(hSocket != NULL);
	if(hSocket==NULL)
		return ( SOCKET_ERROR );
	FD_SET fd = {1, hSocket};
	TIMEVAL tv = {dwTimeout, 0};
	int nBytesReceived=0;
	if(select(0, &fd, NULL, NULL, &tv) == 0) 
		goto CLEAR;
	if((nBytesReceived = recv(hSocket, pszBuffer, nBufferSize, 0)) == SOCKET_ERROR)
		goto CLEAR;
	return nBytesReceived;

CLEAR:
	DPSetLastError(WSAGetLastError());//超时
	return(SOCKET_ERROR);
}

// 接收数据(阻塞直至收到数据为止)
//入口:套接字,缓冲区,缓冲区大小,超时
//注意:这个函数只管理一个端口的接收信息需求,所以这里的EventSelect不能一起管理64
//     个端口的信息
int CDPSocketModel::DPRecvData_Event(SOCKET hSocket, char *pszBuffer, 
							   int nBufferSize, DWORD dwTimeout)
{
	HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (hReadEvent == NULL)
	{
		DPSetLastError( (int)GetLastError() );
		return ( SOCKET_ERROR );
	}

	int		nRecvBytes = 0;
	DWORD	dwWaitResult ;
	for (;;)
	{
		// 注册FD_READ | FD_CLOSE 事件 
		// (因为可能在等待FD_READ事件中,对方关闭套接字,所以要关注FD_CLOSE)
		if( WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, FD_READ | FD_CLOSE) 
			== SOCKET_ERROR)
		{
			CloseHandle(hReadEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}
	
		// 等等FD_READ | FD_CLOSE事件的发生
		dwWaitResult = WSAWaitForMultipleEvents(1, &hReadEvent, TRUE,dwTimeout, TRUE);

		if (dwWaitResult != WSA_WAIT_EVENT_0)
		{
			// 清除事件
			WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
			CloseHandle(hReadEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		
		////////////////////////////////////////////////////////////// 
		///	注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
		///			进一步检查网络是否发生错误
		///////////////////////////////////////////////////////////////
		WSANETWORKEVENTS NetEvent;
		if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hReadEvent,&NetEvent) == SOCKET_ERROR)
		{
			// 清除事件
			WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
			CloseHandle(hReadEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		//判断发生了什么事件 FD_READ 或 FD_CLOSE	
		if( ( NetEvent.lNetworkEvents == FD_CLOSE ) ||
			 ( NetEvent.lNetworkEvents	== FD_READ && 
			   NetEvent.iErrorCode[FD_READ_BIT] !=0 ) )	// 发生错误
		{
			// 清除事件
			WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
			CloseHandle(hReadEvent);
			DPSetLastError(WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		////////////////////////////////////////////////////////////////
		// 清除事件
		WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
	
		// 接收数据
		if ((nRecvBytes = DPRecvLL(hSocket, pszBuffer, nBufferSize)) >= 0)
			break;	// 跳出循环

		//Recv返回的是错误代码的负数,所以需要调转过来
		int nErrorCode = -nRecvBytes;

		if ( nErrorCode != WSAEWOULDBLOCK )	//太多的未完成重叠操作
		{
			CloseHandle(hReadEvent);
			DPSetLastError( nErrorCode );
			return (SOCKET_ERROR);
		}
		//阻塞住了
		////////////////////////////////////////////////////////////////////////
		//  如果发生阻塞,就等待一定时间后重试,以免CPU轮询浪费时间
		////////////////////////////////////////////////////////////////////////
		Sleep(DP_BLOCKED_SNDRCV_SLEEP);
    }
    CloseHandle(hReadEvent);
    return (nRecvBytes);
}

int CDPSocketModel::DPRecvDataFrom_Block( SOCKET hSocket, struct sockaddr * pFrom, 
									int nAddrlen,char *pszBuffer, int nBufferSize,
									DWORD dwTimeout)
{
	ASSERT(hSocket != NULL);
	if(hSocket==NULL)
		return (SOCKET_ERROR);
	FD_SET fd = {1, hSocket};
	TIMEVAL tv = {dwTimeout, 0};
	int nFromSize=0;
	int nBytesReceived=0;
	if(select(0, &fd, NULL, NULL, &tv) == 0) 
		goto CLEAR;
	nFromSize = nAddrlen;
	nBytesReceived = recvfrom(hSocket, pszBuffer, nBufferSize, 0, pFrom, &nFromSize);
	if(nBytesReceived == SOCKET_ERROR) 
		goto CLEAR;
	return nBytesReceived;

CLEAR:
	DPSetLastError(WSAGetLastError());//超时
	return(SOCKET_ERROR);
}


// 数据报接收函数
int CDPSocketModel::DPRecvDataFrom_Event( SOCKET hSocket, struct sockaddr * pFrom, 
								   int nAddrlen,char *pszBuffer, 
								   int nBufferSize,DWORD dwTimeout)
{
	HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (hReadEvent == NULL)
	{
		DPSetLastError((int)GetLastError() );
		return (SOCKET_ERROR);
	}

	DWORD		dwRtxBytes = 0,
				dwRtxFlags = 0;
	WSABUF		WSABuff;

	ZeroMemory(&WSABuff,sizeof(WSABUF));
	WSABuff.len = nBufferSize;
	WSABuff.buf = pszBuffer;

	for (;;)
	{
		// 注册FD_READ事件
		if( WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, FD_READ) 
			== SOCKET_ERROR)
		{
			CloseHandle(hReadEvent);
			DPSetLastError(  WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hReadEvent, 
			TRUE,dwTimeout, TRUE);

		if( dwWaitResult != WSA_WAIT_EVENT_0 )
		{
			// 注销事件
			WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
			CloseHandle(hReadEvent);
			DPSetLastError( WSAGetLastError());
			return (SOCKET_ERROR);
		}

		////////////////////////////////////////////////////////////// 
		///	注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
		///			进一步检查网络是否发生错误
		///////////////////////////////////////////////////////////////
		WSANETWORKEVENTS NetEvent;
		if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hReadEvent,&NetEvent)
			== SOCKET_ERROR)
		{
			// 注销事件
			WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
			CloseHandle(hReadEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		if(NetEvent.iErrorCode[FD_READ_BIT] !=0 )	// 发生错误
		{
			// 注销事件
			WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
			CloseHandle(hReadEvent);
			DPSetLastError(NetEvent.iErrorCode[FD_READ_BIT]);
			return (SOCKET_ERROR);
		}
		////////////////////////////////////////////////////////////////
		// 注销事件
		WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);

		int FromLen = nAddrlen;
		if ( WSARecvFrom(hSocket, &WSABuff, 1, &dwRtxBytes, 
			&dwRtxFlags,pFrom, &FromLen, NULL, NULL) == SOCKET_SUCCESS )
			break;

		if ( WSAGetLastError() != WSAEWOULDBLOCK)
		{
			CloseHandle(hReadEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}

		///////////////////////////////////////////////////////////////////////////
		//	睡眠一段时间
		//////////////////////////////////////////////////////////////////////////
		Sleep(DP_BLOCKED_SNDRCV_SLEEP);
	}
	CloseHandle(hReadEvent);
	return ((int) dwRtxBytes);
}

//发送数据,阻塞
//入口:套接字,发送的字串,字串长度,超时值
//出口:正确返回发送的字节数量,错误返回SOCKET_ERROR
int CDPSocketModel::DPSend_Block(SOCKET hSocket,char const * pszBuffer, 
		int nBufferSize, DWORD dwTimeout)
{
	ASSERT(hSocket!=NULL);
	if(hSocket==NULL||pszBuffer==NULL)
		return (SOCKET_ERROR);
	FD_SET fd = {1, hSocket};
	TIMEVAL tv = {dwTimeout, 0};
	int nBytesSent=0;
	if(select(0, NULL, &fd, NULL, &tv) == 0)
		goto CLEAR;//选择发送超时
	if((nBytesSent = send(hSocket, pszBuffer, nBufferSize, 0)) == SOCKET_ERROR) 
		goto CLEAR;//发送出错误
	return nBytesSent;

CLEAR:
	DPSetLastError(WSAGetLastError());//超时
	return(SOCKET_ERROR);
}

//发送全部缓冲区中数据,阻塞
//入口:套接字,发送的字串,字串长度,超时值
//出口:正确返回发送的字节数量,错误返回SOCKET_ERROR
int CDPSocketModel::DPSendData_Block(SOCKET hSocket,char const * pszBuffer, 
		int nBufferSize, DWORD dwTimeout)

{
	if(hSocket==NULL)
		return(SOCKET_ERROR);
	int nBytesSent = 0;
	int nBytesThisTime;
	const char* pszTemp = pszBuffer;
	do {
		nBytesThisTime = DPSend_Block(hSocket,pszTemp, nBufferSize-nBytesSent, dwTimeout);
		if(nBytesThisTime<0)
			return(SOCKET_ERROR);
		//如果一次没有发送成功
		nBytesSent += nBytesThisTime;
		//改变当前字符指针
		pszTemp += nBytesThisTime;
	} while(nBytesSent < nBufferSize);
	return nBytesSent;
}

// 发送数据
//入口:套接字,发送缓冲区,大小,超时
//出口:返回一次发送数据的字节数量,如果错误返回SOCKET_ERROR
int CDPSocketModel::DPSend_Event(SOCKET hSocket, char const * pszBuffer, 
							   int nBufferSize, DWORD dwTimeout)
{

	HANDLE	hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	if (hWriteEvent == NULL)
	{
		DPSetLastError( (int)GetLastError() );
		return (SOCKET_ERROR);
	}

	int nSendBytes = 0;

	for (;;)
	{
		////////////////////////////////////////////////////////////////
		// 发送数据成功
		if ((nSendBytes = DPSendLL(hSocket, pszBuffer, nBufferSize)) >= 0)
			break;

		//如果发送的字节数量小于0证明出错
		int nErrorCode = -nSendBytes;
		//如果是WSAEWOULDBLOCK错误,证明在该端口上仍然进行着其他I/O操作
		//所以我们下面进行必要的等待循环处理
		if (nErrorCode != WSAEWOULDBLOCK)
		{
			CloseHandle(hWriteEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}

		///////////////////////////////////////////////////////////////////////////////
		//  睡眠一段时间
		///////////////////////////////////////////////////////////////////////////////
		Sleep(DP_BLOCKED_SNDRCV_SLEEP);

		// 注册FD_WRITE | FD_CLOSE 事件
		if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE|FD_CLOSE) 
			== SOCKET_ERROR)
		{
			CloseHandle(hWriteEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}

		// 等待事件发生
		DWORD dwWaitResult = WSAWaitForMultipleEvents(1, 
			&hWriteEvent, TRUE,dwTimeout, TRUE);

		if (dwWaitResult != WSA_WAIT_EVENT_0)
		{
			// 清除网络事件
			WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
			CloseHandle(hWriteEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}

		////////////////////////////////////////////////////////////// 
		///	注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
		///			进一步检查网络是否发生错误
		///////////////////////////////////////////////////////////////
		WSANETWORKEVENTS NetEvent;
		if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hWriteEvent,&NetEvent) == SOCKET_ERROR)
		{
  			// 清除网络事件
			WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
			CloseHandle(hWriteEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		if( ( NetEvent.lNetworkEvents == FD_CLOSE ) ||
			 ( NetEvent.lNetworkEvents == FD_WRITE   &&
				NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) )	// 发生错误
		{
			// 清除网络事件
			WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
			CloseHandle(hWriteEvent);
			DPSetLastError( WSAGetLastError() );
			return (SOCKET_ERROR);
		}
		// 清除网络事件
		WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
   }

    CloseHandle(hWriteEvent);
    return (nSendBytes);
}

⌨️ 快捷键说明

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