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

📄 dpsocketmodel.cpp

📁 DarkATLSmtp(SMTP COM 组件原创代码),注册后可在Delphi中发邮件。
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//出口:SOCKET_SUCCESS/SOCKET_ERROR
int CDPSocketModel::DPConnect_Event(SOCKET hSocket, const struct sockaddr * pSocketAddress, 
							  int nAddrLen,DWORD dwTimeout)
{

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

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

	// 注册FD_CONNECT事件
	if( WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, FD_CONNECT) == SOCKET_ERROR)
	{
		CloseHandle(hConnectEvent);
		DPSetLastError( WSAGetLastError() );
		return (SOCKET_ERROR);
	}

	int	nConnectResult = WSAConnect(hSocket, pSocketAddress, nAddrLen, 
		NULL, NULL, NULL, NULL);
	int	nConnectError  = WSAGetLastError();
	
	if ((nConnectResult == SOCKET_ERROR) && (nConnectError == WSAEWOULDBLOCK))
	{
		DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hConnectEvent, 
			TRUE,dwTimeout, TRUE);
		
		if (dwWaitResult != WSA_WAIT_EVENT_0)
		{
			DPSetLastError( WSAGetLastError() );
			nConnectResult = SOCKET_ERROR;
		}
		else
		{
			////////////////////////////////////////////////////////////// 
			///	注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
			///			进一步检查网络是否发生错误
			///////////////////////////////////////////////////////////////
			WSANETWORKEVENTS NetEvent;
			if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hConnectEvent,&NetEvent) 
				== SOCKET_ERROR)
			{
				DPSetLastError( WSAGetLastError() );
				nConnectResult = SOCKET_ERROR;
			}
			else if(NetEvent.iErrorCode[FD_CONNECT_BIT] !=0 )	// 发生错误
			{
				DPSetLastError( NetEvent.iErrorCode[FD_CONNECT_BIT] );
				nConnectResult = SOCKET_ERROR;
			}
			else
				nConnectResult = SOCKET_SUCCESS;
			////////////////////////////////////////////////////////////////
		}
	}

	// 注销网络事件
	WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, 0);
	CloseHandle(hConnectEvent);
	return (nConnectResult);
}

int CDPSocketModel::DPConnect_Block(SOCKET hSocket, const struct sockaddr * pSocketAddress, 
									int nAddrLen)
{
	ASSERT(hSocket!=NULL);
	if(hSocket==NULL)
		return SOCKET_ERROR;
	if(connect(hSocket, pSocketAddress, nAddrLen) == SOCKET_ERROR) 
		return SOCKET_ERROR;
	return SOCKET_SUCCESS;
}

//创建具有重叠IO能力的套接字
//入口:协议,协议类型(TCP/UDP),协议
//出口:返回创建的重叠IO SOCKET
//注意:使用SOCKET()函数创建的套接字默认具有重叠IO能力
SOCKET CDPSocketModel::DPCreateSocket(int nAddressFamily /*= AF_INET*/, 
									  int nType/*= SOCK_STREAM*/,
									  int nProtocol/*= 0*/)
{
	SOCKET hSocket = WSASocket(nAddressFamily, nType, nProtocol, 
		NULL,0,WSA_FLAG_OVERLAPPED);	
	if ( hSocket == INVALID_SOCKET )
	{
		DPSetLastError( WSAGetLastError() );
		return (INVALID_SOCKET);
	}

	//设置套接字选项
	if ( SOCKET_ERROR == DPSetSocketOption(hSocket) )	//设置属性失败
	{
		DPCloseSocket(hSocket, TRUE);
		return (INVALID_SOCKET);
	}
	return (hSocket);
}


//引入该函数的目的是为了避免NT下对域名解析的CACHE造成的问题
//入口:无
//出口:返回主机IP,或者INADDR_NONE
DWORD WINAPI DNSThread(  LPVOID pParam )
{
	DWORD dwIP = INADDR_NONE;
	PHOSTENT pHost = gethostbyname( (char *)pParam );
	if(pHost == NULL)
		return INADDR_NONE;
	dwIP = inet_addr( inet_ntoa(*(IN_ADDR *)*pHost->h_addr_list) );
	return dwIP;
}

//取得一个指定名字或者IP字串的DWORD IP表示
//入口:主机IP或者域名,是否启动新线程进行查找IP
//出口:返回IP,或者INADDR_NONE
// Used to Fix NT DNS Problem
DWORD CDPSocketModel::DPGetIP(const char* name,BOOL bFixNtDNS /* = FALSE*/)
{
	//这里是为了将字串IP直接转换成DWORD的形式
	DWORD dwIP = inet_addr(name);
	if( dwIP != INADDR_NONE )
		return dwIP;
	//如果传入的是服务器的域名则进行向下程序
	//如果NT的CATCH有问题,那么进入下面的模块,主要是启动新线程进行域名解析
	if( bFixNtDNS )
	{
		OSVERSIONINFO		osVersion;
		osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		if( GetVersionEx(&osVersion) )
		{
			if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
			{
				DWORD	dwThreadId = 0;
				HANDLE	hThread = CreateThread(NULL,0,DNSThread,(LPVOID)name,0,&dwThreadId);
				if( hThread != NULL)
				{
					//注意这里在等待的不是一个事件,而是线程句柄
					WaitForSingleObject(hThread,INFINITE);
					//注意这里取得线程退出码就是我们需要的IP
					if( GetExitCodeThread(hThread,&dwIP))
						return dwIP;
				}
			}
		}
	}
	//取得主机信息
	PHOSTENT pHost = gethostbyname(name);
	if(pHost == NULL)
		return INADDR_NONE;
		
	dwIP = inet_addr( inet_ntoa(*(IN_ADDR *)*pHost->h_addr_list) );
	return dwIP;
}

// 监听套接字
//入口:套接字,接入的等待队列长度
//出口:SOCKET_ERROR/SOCKET_SUCCESS
int CDPSocketModel::DPListenSocket(SOCKET hSocket, int nConnections)
{
	if(listen(hSocket, nConnections) == SOCKET_ERROR)
	{
		DPSetLastError( WSAGetLastError() );
		return (SOCKET_ERROR);
	}
	return (SOCKET_SUCCESS);
}


//	缓冲区函数
//	功能: 绑定套接字
LPTAG_BSD CDPSocketModel::DPBSocketAttach(SOCKET hSocket, 
										  int iBufferSize 
										  /* = DP_SOCKET_BUFFER_SIZE */ )
{

	if( hSocket == INVALID_SOCKET)
		return NULL;
	// 分配内存
	LPTAG_BSD pBSD = (LPTAG_BSD) malloc(sizeof(TAG_BSD));
	if (pBSD == NULL)
		return NULL;
	char *pszBuffer = (char *) malloc(iBufferSize);
	if (pszBuffer == NULL)
	{
		free(pBSD);
		return NULL;
	}
	// 设置结构成员
	ZeroMemory(pBSD,sizeof(TAG_BSD));
	ZeroMemory(pszBuffer,iBufferSize);

	pBSD->hSocket			= hSocket;
	pBSD->iBufferSize		= iBufferSize;
	pBSD->pszBuffer			= pszBuffer;
	pBSD->iBytesInBuffer	= 0;
	pBSD->iReadIndex		= 0;
	pBSD->iBufferIndex		= 0;
	return pBSD;
}

//	功能: 解开套接字
SOCKET CDPSocketModel::DPBSocketDetach(LPTAG_BSD pBSD, BOOL bCloseSocket /* = FALSE */ )
{
	SOCKET		 hSocket = pBSD->hSocket;

	// 释放内存
	free(pBSD->pszBuffer);
	free(pBSD);

	// 是否关闭套接字
	if (bCloseSocket)
	{
		DPCloseSocket(hSocket);
		return (INVALID_SOCKET);
	}
	return (hSocket);
}


//	purpose: Read datas from far host in buffer(LPTAG_BSD)
int CDPSocketModel::DPBSocketReadData(LPTAG_BSD pBSD, 
									  DWORD dwTimeout /* = DP_RECV_TIMEOUT */ )
{
	// calculate size of buffer that may be empty.
	int	iMaxRead = pBSD->iBufferSize - pBSD->iBytesInBuffer;
	//Create Some Mem By Free Buffer Length.
	char  *pszBuffer = (char *) malloc(iMaxRead + 1);
	if (pszBuffer == NULL)
		return (SOCKET_ERROR);
	// Init buffer by 0
	ZeroMemory(pszBuffer,iMaxRead+1);
	// Recv Data That Data's Length Is iMaxRead.
	int iReadedBytes = DPRecvData_Event(pBSD->hSocket, pszBuffer, iMaxRead, dwTimeout);
	if (iReadedBytes > 0)
	{
		//Get A Less Num Between Two Nums.
		int iHeadSize = Min(pBSD->iBufferSize - pBSD->iBufferIndex, iReadedBytes);
		//Copy iHeadSize Length Datas To pBSD Mem Space.
		if (iHeadSize > 0)
			memcpy(pBSD->pszBuffer + pBSD->iBufferIndex, pszBuffer, iHeadSize);

		pBSD->iBufferIndex += iHeadSize;
		//if the pointer move end of buffer,make it to top.
		if (pBSD->iBufferIndex == pBSD->iBufferSize)
			pBSD->iBufferIndex = 0;
		//get last length of data that do not copy to buffer
		int iBackSize = iReadedBytes - iHeadSize;
		//copy these datas to top of buffer.
		if (iBackSize > 0)
			memcpy(pBSD->pszBuffer + pBSD->iBufferIndex, pszBuffer + iHeadSize, iBackSize);
		//move buffer pointer.
		pBSD->iBufferIndex += iBackSize;
		//we change length of read data in buffer.
		pBSD->iBytesInBuffer += iReadedBytes;
	}
	free(pszBuffer);
	return (iReadedBytes);
}


//	purpose: read one bytes length data from buffer.
int CDPSocketModel::DPBSocketGetChar(LPTAG_BSD pBSD, DWORD dwTimeout /* = DP_RECV_TIMEOUT */ )
{
	if ((pBSD->iBytesInBuffer == 0) && (DPBSocketReadData(pBSD, dwTimeout) <= 0))
		return (DP_EOF);
	//get the first bytes from pBSD->pszeBuffer,by Index pointer.
	int iChar =( (int) pBSD->pszBuffer[pBSD->iReadIndex]) & 0x000000ff;
	//change iReadIndex pointer that if iReadIndex have moved end of buffer
	//we will make it to top of buffer
	pBSD->iReadIndex = INext(pBSD->iReadIndex, pBSD->iBufferSize);
	//change new size for buffer,bucause we have read a bytes length data.
	--pBSD->iBytesInBuffer;
	//return this char data.
	return (iChar);
}


// purpose: get a line data from buffer, notes that end of line is 0x0d and 0x0a.
//			but the two character do not include in return buffer.
int CDPSocketModel::DPBSocketGetString(LPTAG_BSD pBSD, char *pszBuffer, 
									   int iBufferSize, int* iStatus, 
									   DWORD dwTimeout /* = DP_RECV_TIMEOUT */ )
{
	*iStatus = 1;		//缓冲长度不足
	int ii,iChar;
	for (ii = 0; ii < (iBufferSize - 1);)
	{
		//get a character form buffer.
		iChar = DPBSocketGetChar(pBSD, dwTimeout);
		//if it is invalid character that we will return SOCKET_ERROR.
		if (iChar == DP_EOF)
		{
			*iStatus = (-1) ;
			return SOCKET_ERROR;
		}
		//judge end of line is or not a end of line flag.
		if (iChar == 0x0D)	// enter
		{
			iChar = DPBSocketGetChar(pBSD, dwTimeout);
			if (iChar == DP_EOF)
			{
				*iStatus = (-1);
				return (SOCKET_ERROR);
			}

			if (iChar == 0x0A)	// newline
			{
				*iStatus = 0;	//set status is normal.
				break;
			}
			else
				pszBuffer[ii++] = 0x0D;
		}
		else
			pszBuffer[ii++] = (char) iChar;
	}
	pszBuffer[ii] = '\0';
	return (SOCKET_SUCCESS);
}

//	功能: 从缓冲区读取一行(包括单换行0x0A)(注意,结尾的回车换行不包括在其中)
int CDPSocketModel::DPBSocketGetStringEx(LPTAG_BSD pBSD, char *pszBuffer, int iBufferSize, int* iStatus, DWORD dwTimeout /* = DP_RECV_TIMEOUT */ )
{
	
	*iStatus = 1;		//缓冲长度不足

	int ii,iChar;
	int LastChar = DP_EOF;
	for (ii = 0; ii < (iBufferSize - 1);)
	{
		iChar = DPBSocketGetChar(pBSD, dwTimeout);
		if (iChar == DP_EOF)
		{
			*iStatus = (-1) ;
			return SOCKET_ERROR;
		}

		if (iChar == 0x0A)	// newline
		{
			*iStatus = 0;	//is normal status
			if (LastChar == 0x0D)
				ii-- ;	
			break;
		}
		else
			pszBuffer[ii++] = (char) iChar;
		LastChar = iChar;
	}
	pszBuffer[ii] = '\0';
	return (SOCKET_SUCCESS);
}



//		功能: 发送一行 : 自动在最后加上“回车换行符(0x0D,0x0A)”
int CDPSocketModel::DPBSocketSendString(LPTAG_BSD pBSD, const char *pszBuffer, DWORD dwTimeout /* = DP_SEND_TIMEOUT */ )
{

	char *pszSendBuffer = (char *) malloc(strlen(pszBuffer) + 3);

	if (pszSendBuffer == NULL)
		return (SOCKET_ERROR);

	ZeroMemory( pszSendBuffer,strlen(pszBuffer) + 3);
	sprintf(pszSendBuffer, "%s\r\n", pszBuffer);

	int iSendLength = strlen(pszSendBuffer);
	if (DPSend_Event(pBSD->hSocket, pszSendBuffer, iSendLength, dwTimeout) != iSendLength)
	{
        free(pszSendBuffer);
		return (SOCKET_ERROR);
    }
	free(pszSendBuffer);
	return (iSendLength);
}

//	功能: 获取套接字
SOCKET CDPSocketModel::DPBSocketGetAttachedSocket(LPTAG_BSD pBSD)
{
	return (pBSD->hSocket);
}

//		功能: 从缓冲区读取一定数量的数据
int CDPSocketModel::DPBSocketGetData(LPTAG_BSD pBSD, char *pszBuffer, 
									 int iBufferSize,DWORD dwTimeout /*= DP_RECV_TIMEOUT*/)
{
	int iReadBytes	 = 0;
	int iHeadSize,iBackSize;

	if ((pBSD->iBytesInBuffer == 0) && (DPBSocketReadData(pBSD, dwTimeout) <= 0))
		return 0; 

	if( pBSD->iBytesInBuffer < iBufferSize ) // 数据不够多
	{
		iHeadSize = Min( pBSD->iBufferSize - pBSD->iReadIndex ,pBSD->iBytesInBuffer );
		memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iHeadSize);
			
		pBSD->iReadIndex += iHeadSize;
		if( pBSD->iReadIndex == pBSD->iBufferSize )
			pBSD->iReadIndex = 0;

		iReadBytes += iHeadSize;
		iBackSize = pBSD->iBytesInBuffer - iHeadSize;
			
		if( iBackSize > 0)
			memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iBackSize);

		iReadBytes			 += iBackSize;
		pBSD->iReadIndex	 += iBackSize;
		pBSD->iBytesInBuffer = 0; // 数据全部读完
	}
	else // 这次的数据足够多了
	{
		iHeadSize = Min( pBSD->iBufferSize - pBSD->iReadIndex,iBufferSize - iReadBytes );
		memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iHeadSize);
			
		pBSD->iReadIndex += iHeadSize;
		if( pBSD->iReadIndex == pBSD->iBufferSize )
			pBSD->iReadIndex = 0;

		iReadBytes += iHeadSize;
		iBackSize = iBufferSize - iReadBytes;

		if( iBackSize > 0)
			memcpy(pszBuffer+iReadBytes,pBSD->pszBuffer+pBSD->iReadIndex,iBackSize);

		iReadBytes			 += iBackSize;
		pBSD->iReadIndex	 += iBackSize;
		pBSD->iBytesInBuffer -= (iHeadSize+iBackSize);
	}
	return iReadBytes;
}

CString CDPSocketModel::GetLocalHostIp(void)
{
	CString strReturn;
	char name[255];
	PHOSTENT hostinfo;
	if( gethostname ( name, sizeof(name)) == 0)
	{
		if((hostinfo = gethostbyname(name)) != NULL)
		{
			strReturn = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
		}
	}
	return strReturn;
}

⌨️ 快捷键说明

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