📄 dpsocketmodel.cpp
字号:
//出口: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 + -