转自:
http://blog.163.com/wupengzhi2005@126/blog/static/1710100220094715936897/
// DPEventSocket.cpp: implementation of the CSocketModel class.
//
//
#include "stdafx.h"
#include "SocketModel.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CSocketModel::CSocketModel()
{
::InitializeCriticalSection(&m_csErrorNo);
}
CSocketModel::~CSocketModel()
{
::DeleteCriticalSection(&m_csErrorNo);
}
// 设置套接字是否为阻塞的
//入口:套接字,是否需要阻塞的
//出口:如果正确那么返回0,错误返回-1
int CSocketModel::BlockSocket(SOCKET hSocket, BOOL bBlock/*FALSE*/)
{
u_long IoctlLong = (bBlock) ? 0 : 1;
if (ioctlsocket(hSocket, FIONBIO, &IoctlLong) == SOCKET_ERROR)
{
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
return (SOCKET_SUCCESS);
}
//设置套接字属性
//入口:套接字
//出口:如果正确那么返回0,错误返回-1
int CSocketModel::SetSocketOption(SOCKET hSocket)
{
int nActivate = 1;
//允许地址重用
if (setsockopt(hSocket, SOL_SOCKET, SO_REUSEADDR, (const char *) &nActivate,
sizeof(nActivate)) == SOCKET_ERROR )
{
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);//return (-1)
}
// 如果支持,设置KEEPALIVE属性 (这样做会带来其他不良后果)
//setsockopt(hSocket, SOL_SOCKET, SO_KEEPALIVE, (const char *) &nActivate,sizeof(iActivate));
return (SOCKET_SUCCESS);
}
//接收所有数据,注意在这个函数调用之前必须确认是否有接收消息到来
//入口:套接字,数据缓冲区,缓冲区大小
//出口:如果正确那么返回接收的字节数量,错误返回错误代码
//注意:这里使用的是WINSOCK2的专有WSARecv()函数进行接收,所以为非阻塞模式
// 所以调用此函数前必须确认有数据到来的消息,否则返回错误
int CSocketModel::RecvLL(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 CSocketModel::RecvData_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:
SetLastError(WSAGetLastError());//超时
return(SOCKET_ERROR);
}
// 接收数据(阻塞直至收到数据为止)
//入口:套接字,缓冲区,缓冲区大小,超时
//注意:这个函数只管理一个端口的接收信息需求,所以这里的EventSelect不能一起管理64
// 个端口的信息
int CSocketModel::RecvData_Event(SOCKET hSocket, char *pszBuffer,
int nBufferSize, DWORD dwTimeout)
{
HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hReadEvent == NULL)
{
SetLastError( (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);
SetLastError( 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);
SetLastError( 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);
SetLastError( 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);
SetLastError(WSAGetLastError() );
return (SOCKET_ERROR);
}
// 清除事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
// 接收数据
if ((nRecvBytes = RecvLL(hSocket, pszBuffer, nBufferSize)) >= 0)
break; // 跳出循环
//Recv返回的是错误代码的负数,所以需要调转过来
int nErrorCode = -nRecvBytes;
if ( nErrorCode != WSAEWOULDBLOCK ) //太多的未完成重叠操作
{
CloseHandle(hReadEvent);
SetLastError( nErrorCode );
return (SOCKET_ERROR);
}
//阻塞住了
// 如果发生阻塞,就等待一定时间后重试,以免CPU轮询浪费时间
Sleep(_BLOCKED_SNDRCV_SLEEP);
}
CloseHandle(hReadEvent);
return (nRecvBytes);
}
int CSocketModel::RecvDataFrom_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:
SetLastError(WSAGetLastError());//超时
return(SOCKET_ERROR);
}
// 数据报接收函数
int CSocketModel::RecvDataFrom_Event( SOCKET hSocket, struct sockaddr * pFrom,
int nAddrlen,char *pszBuffer,
int nBufferSize,DWORD dwTimeout)
{
HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hReadEvent == NULL)
{
SetLastError((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);
SetLastError( 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);
SetLastError( 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);
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
if(NetEvent.iErrorCode[FD_READ_BIT] !=0 ) // 发生错误
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
CloseHandle(hReadEvent);
SetLastError(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);
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
///
// 睡眠一段时间
//
Sleep(_BLOCKED_SNDRCV_SLEEP);
}
CloseHandle(hReadEvent);
return ((int) dwRtxBytes);
}
//发送数据,阻塞
//入口:套接字,发送的字串,字串长度,超时值
//出口:正确返回发送的字节数量,错误返回SOCKET_ERROR
int CSocketModel::Send_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:
SetLastError(WSAGetLastError());//超时
return(SOCKET_ERROR);
}
//发送全部缓冲区中数据,阻塞
//入口:套接字,发送的字串,字串长度,超时值
//出口:正确返回发送的字节数量,错误返回SOCKET_ERROR
int CSocketModel::SendData_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 = Send_Block(hSocket,pszTemp, nBufferSize-nBytesSent, dwTimeout);
if(nBytesThisTime<0)
return(SOCKET_ERROR);
//如果一次没有发送成功
nBytesSent += nBytesThisTime;
//改变当前字符指针
pszTemp += nBytesThisTime;
} while(nBytesSent < nBufferSize);
return nBytesSent;
}
// 发送数据
//入口:套接字,发送缓冲区,大小,超时
//出口:返回一次发送数据的字节数量,如果错误返回SOCKET_ERROR
int CSocketModel::Send_Event(SOCKET hSocket, char const * pszBuffer,
int nBufferSize, DWORD dwTimeout)
{
HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hWriteEvent == NULL)
{
SetLastError( (int)GetLastError() );
return (SOCKET_ERROR);
}
int nSendBytes = 0;
for (;;)
{
// 发送数据成功
if ((nSendBytes = SendLL(hSocket, pszBuffer, nBufferSize)) >= 0)
break;
//如果发送的字节数量小于0证明出错
int nErrorCode = -nSendBytes;
//如果是WSAEWOULDBLOCK错误,证明在该端口上仍然进行着其他I/O操作
//所以我们下面进行必要的等待循环处理
if (nErrorCode != WSAEWOULDBLOCK)
{
CloseHandle(hWriteEvent);
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
///
// 睡眠一段时间
///
Sleep(_BLOCKED_SNDRCV_SLEEP);
// 注册FD_WRITE | FD_CLOSE 事件
if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE|FD_CLOSE)
== SOCKET_ERROR)
{
CloseHandle(hWriteEvent);
SetLastError( 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);
SetLastError( 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);
SetLastError( 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);
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
// 清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
}
CloseHandle(hWriteEvent);
return (nSendBytes);
}
//发送完所有数据或超时
//入口:套接字,缓冲区,缓冲区大小,超时
//出口:返回已经发送的字节个数或SOCKET_ERROR
int CSocketModel::SendData_Event(SOCKET hSocket, char const * pszBuffer,
int nBufferSize, DWORD dwTimeout)
{
int nRtxBytes = 0;
int nRtxCurrent = 0;
while (nRtxBytes < nBufferSize)
{
nRtxCurrent = Send_Event(hSocket, (pszBuffer + nRtxBytes),
(nBufferSize - nRtxBytes), dwTimeout);
if (nRtxCurrent < 0)
return (nRtxBytes);
nRtxBytes += nRtxCurrent;
}
return (nRtxBytes);
}
//一次发送数据,但不一定全部都发送
//入口:套接字,接收方地址信息,地址结构,结构长度,缓冲区,缓冲区长度,超时
//出口:正确返回发送字节数量,错误返回SOCKET_ERROR
int CSocketModel::SendTo_Block(SOCKET hSocket, const struct sockaddr * pTo,
int nAddrLen,char const * pszBuffer, int nBufferSize, DWORD dwTimeout)
{
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;
nBytesSent = sendto(hSocket, pszBuffer, nBufferSize, 0, pTo, nAddrLen);
if(nBytesSent == SOCKET_ERROR)
goto CLEAR;
return nBytesSent;
CLEAR:
SetLastError(WSAGetLastError());//超时
return(SOCKET_ERROR);
}
// 数据报发送数据报
int CSocketModel::SendTo_Event(SOCKET hSocket, const struct sockaddr * pTo,
int nAddrLen,char const * pszBuffer,
int nBufferSize, DWORD dwTimeout)
{
HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hWriteEvent == NULL)
{
SetLastError( (int)GetLastError() );
return (SOCKET_ERROR);
}
DWORD dwRtxBytes = 0,
dwRtxFlags = 0;
WSABUF WSABuff;
ZeroMemory(&WSABuff,sizeof(WSABUF));
WSABuff.len = nBufferSize;
WSABuff.buf = (char *) pszBuffer;
for (;;)
{
if (WSASendTo( hSocket, &WSABuff, 1, &dwRtxBytes, dwRtxFlags,
pTo, nAddrLen, NULL, NULL) == SOCKET_SUCCESS)
break;
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
CloseHandle(hWriteEvent);
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
//
// 睡眠一段时间
/
Sleep(_BLOCKED_SNDRCV_SLEEP);
// 注册FD_WRITE事件
if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE)
== SOCKET_ERROR)
{
CloseHandle(hWriteEvent);
SetLastError( 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);
SetLastError( 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);
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
if(NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) // 发生错误
{
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
CloseHandle(hWriteEvent);
SetLastError(NetEvent.iErrorCode[FD_WRITE_BIT]);
return (SOCKET_ERROR);
}
// 注销事件
WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
}
CloseHandle(hWriteEvent);
return ((int) dwRtxBytes);
}
//一次性发送数据(事件IO)
//入口:套接字,缓冲区,缓冲区长度
//出口:正确-返回发送的字节数量,错误-返回错误代码的负数
int CSocketModel::SendLL(SOCKET hSocket, char const * pszBuffer,
int nBufferSize)
{
DWORD dwRtxBytes = 0;
WSABUF WSABuff;
ZeroMemory(&WSABuff,sizeof(WSABUF));
WSABuff.len = nBufferSize;
WSABuff.buf = (char *) pszBuffer;
return ((WSASend(hSocket, &WSABuff, 1, &dwRtxBytes, 0,NULL, NULL)
== SOCKET_SUCCESS) ? (int) dwRtxBytes : -WSAGetLastError());
}
//关闭套接字
//入口:套接字,是否强行关闭(如果bHardClose==FALSE,那么接收剩余的数据后关闭连接)
//注意:这里的接收剩余数据只是为了让SERVER将数据发送操作执行完毕
// 所以接收的剩余数据不可用
void CSocketModel::CloseSocket(SOCKET hSocket, BOOL bHardClose)
{
// 不需要捕获错误
if (!bHardClose) // 优雅关闭 Graceful close
{
// 不再发送数据,对于TCP套接字,在所有的数据都发送完毕之后,
// 将发送一个 FIN ,通知接收方所有数据已经发送完毕。
shutdown(hSocket, SD_SEND);
// 接收缓冲区有可能还有未接收的数据,在关闭套接字之前应该先
// 读取残留的数据。
int nRecvResult;
HANDLE hSocketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
//为残留数据提供的缓冲区
char szBuffer[256];
do
{
if (hSocketEvent != NULL)
{
//注册网络事件
WSAEventSelect(hSocket, (WSAEVENT) hSocketEvent, FD_READ | FD_CLOSE);
WSAWaitForMultipleEvents(1, &hSocketEvent, TRUE,_SHUTDOWN_RECV_TIMEOUT, TRUE);
//清除网络事件
WSAEventSelect(hSocket, (WSAEVENT) hSocketEvent, 0);
}
ZeroMemory(szBuffer,256);
//接收残留数据
nRecvResult = RecvLL(hSocket, szBuffer, sizeof(szBuffer));
} while (nRecvResult > 0);
if (hSocketEvent != NULL)
CloseHandle(hSocketEvent);
//不再允许接收和发送
shutdown(hSocket, SD_BOTH);
}
// 关闭套接字
closesocket(hSocket);
}
//接受套接字连接
//入口:侦听端口号,本地地址
//出口:返回一个可用的套接字或INVALID_SOCKET
//注意:如果为阻塞等待,就是在DWTIMEOUT的时间设置为无限的时候
// 如果我们关闭该套接字会出现的问题
SOCKET CSocketModel::Accept_Event(SOCKET hSocket, struct sockaddr * pSocketAddress,
int *nAddrLen,DWORD dwTimeout
/*= DP_DEFAULT_TIMEOUT*/)
{
HANDLE hAcceptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hAcceptEvent == NULL)
{
SetLastError( (int)GetLastError() );
return (INVALID_SOCKET);
}
//异步事件选择
// 注册FD_ACCEPT事件
if( WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, FD_ACCEPT) == SOCKET_ERROR)
{
CloseHandle(hAcceptEvent);
SetLastError( WSAGetLastError() );
return (INVALID_SOCKET);
}
//进行非阻塞接收
SOCKET hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
int nConnectError = WSAGetLastError();
//如果返回的端口是没有定义的,并且接收的错误码为"代决"状态
if ((hSocketAccept == INVALID_SOCKET) && (nConnectError == WSAEWOULDBLOCK))
{
//阻塞,这个函数如果正确返回那么我们在使用WSAACCEPT重新接收一次,
//就可以获得用户的SOCKET
//因为这个函数返回代表ACCPETEVENT成为传信状态,如果网络没有错误那么
//代表有用户的正确端口接入
DWORD dwWaitResult = WSAWaitForMultipleEvents
(1,&hAcceptEvent,TRUE,dwTimeout,TRUE);
if (dwWaitResult == WSA_WAIT_EVENT_0)
{
//
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,hAcceptEvent,&NetEvent) == SOCKET_ERROR)
SetLastError( WSAGetLastError() );
else if(NetEvent.iErrorCode[FD_ACCEPT_BIT] !=0 ) // 发生错误
SetLastError( NetEvent.iErrorCode[FD_ACCEPT_BIT] );
else
//接收到真正的用户SOCKET
hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
}
else
SetLastError(WSAGetLastError());
}
// 注销网络事件
WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, 0);
CloseHandle(hAcceptEvent);
if (hSocketAccept != INVALID_SOCKET)
{
// 设置套接字的属性为地址可重用并且为非阻塞的
if ((BlockSocket(hSocketAccept, 0) == SOCKET_ERROR ) ||
(SetSocketOption(hSocketAccept) == SOCKET_ERROR ) )
{
CloseSocket(hSocketAccept,TRUE);
return (INVALID_SOCKET);
}
}
return (hSocketAccept);
}
// 接受套接字连接(允许中断)
//入口:结束事件,其他入口都和Accept一样
//出口:返回一个可用的套接字或INVALID_SOCKET
//注意:超时值默认为DP_DEFAULT_TIMEOUT,如果结束事件没有的话,
// 那么跟调用上面的函数没有区别
SOCKET CSocketModel::AcceptEx_Event(SOCKET hSocket, struct sockaddr * pSocketAddress,
int *nAddrLen,HANDLE hEndEvent,DWORD dwTimeout
/*= DP_DEFAULT_TIMEOUT*/)
{
if( hEndEvent == NULL)
return Accept_Event(hSocket,pSocketAddress,nAddrLen,dwTimeout);
HANDLE hAcceptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hAcceptEvent == NULL)
{
SetLastError( (int)GetLastError() );
return (INVALID_SOCKET);
}
WSAEVENT hEvent[2];
hEvent[0] = (WSAEVENT)hAcceptEvent;
hEvent[1] = (WSAEVENT)hEndEvent;
// 注册FD_ACCEPT事件
if( WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, FD_ACCEPT) == SOCKET_ERROR)
{
CloseHandle(hAcceptEvent);
SetLastError( WSAGetLastError() );
return (INVALID_SOCKET);
}
SOCKET hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
int nConnectError = WSAGetLastError();
if ((hSocketAccept == INVALID_SOCKET) && (nConnectError == WSAEWOULDBLOCK))
{
// 阻塞,等待两个事件,如果其中一个发生那么我们向下继续执行
//所以这意味着指定结束事件后,如果程序想中断ACCEPT的执行
//那么就激活该结束事件,程序将按照错误一样的处理
DWORD dwWaitResult = WSAWaitForMultipleEvents(2, hEvent, FALSE,dwTimeout, TRUE);
if (dwWaitResult == WSA_WAIT_EVENT_0)
{
//
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,hAcceptEvent,&NetEvent) == SOCKET_ERROR)
SetLastError(WSAGetLastError());
else if(NetEvent.iErrorCode[FD_ACCEPT_BIT] !=0 ) // 发生错误
SetLastError( NetEvent.iErrorCode[FD_ACCEPT_BIT] );
else
hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
}
else
SetLastError( WSAGetLastError() );
}
// 注销网络事件
WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, 0);
CloseHandle(hAcceptEvent);
if (hSocketAccept != INVALID_SOCKET)
{
// 设置套接字的属性为地址可重用并且为非阻塞的
if ((BlockSocket(hSocketAccept, 0) < 0) ||
(SetSocketOption(hSocketAccept) < 0) )
{
CloseSocket(hSocketAccept,TRUE);
return (INVALID_SOCKET);
}
}
return (hSocketAccept);
}
//阻塞ACCEPT,没有响应不返回
//入口:套接字,主机地址,长度
//出口:正确返回端口号,否则返回INVALID_SOCKET
SOCKET CSocketModel::Accept_Block(SOCKET hSocket, struct sockaddr * pSocketAddress,
int *nAddrLen)
{
ASSERT(hSocket!=NULL);
//int nLengthAddr = sizeof(SOCKADDR);
SOCKET hAccept = accept(hSocket, pSocketAddress, nAddrLen);
//如果该端口错误
if(hAccept == INVALID_SOCKET) {
SetLastError(WSAGetLastError());
}
return hAccept;
}
// 绑定套接字
//入口:套接字,绑定的地址信息,长度
//出口:正确0,错误-1
int CSocketModel::BindSocket(SOCKET hSocket, struct sockaddr * pSocketAddress,
int nAddrLen)
{
if (bind(hSocket, pSocketAddress, nAddrLen) == SOCKET_ERROR)
{
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
return (SOCKET_SUCCESS);
}
// 绑定套接字
//入口:套接字,端口号
//出口:正确0,错误-1
//注意:这个函数不同于上个函数,调用这个函数只需要给定一个端口号
// 至于地址信息在函数内部默认处理(本机IP的该端口)
int CSocketModel::BindSocketEx(SOCKET hSocket,int nPort)
{
SOCKADDR_IN sockAddr;
ZeroMemory(&sockAddr,sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockAddr.sin_port = htons((u_short)nPort);
return BindSocket(hSocket,(SOCKADDR *)&sockAddr, sizeof(sockAddr));
}
//释放Winsock2动态连接库
//入口:无
//出口:无
void CSocketModel::CleanupLibrary(void)
{
WSACleanup();
}
//注册WINSOCK2.2DLL
//入口:无
//出口:无
int CSocketModel::InitLibrary(void)
{
WSADATA WSD;
WORD wVersionRequired = MAKEWORD( _SOCKET_MAJOR_VERSION,_SOCKET_MINOR_VERSION );
ZeroMemory(&WSD,sizeof(WSADATA));
int nErrorNo = WSAStartup(wVersionRequired, &WSD);
if ( SOCKET_SUCCESS != nErrorNo )
{
SetLastError( nErrorNo );
return ( SOCKET_ERROR );
}
if ( LOBYTE( WSD.wVersion ) != _SOCKET_MINOR_VERSION ||
HIBYTE( WSD.wVersion ) != _SOCKET_MAJOR_VERSION )
{
WSACleanup( );
SetLastError( WSAVERNOTSUPPORTED );
return (SOCKET_ERROR);
}
//成功初始化
return (SOCKET_SUCCESS);
}
// 建立连接
//入口:套接字,地址结构,结构长度,超时
//出口:SOCKET_SUCCESS/SOCKET_ERROR
int CSocketModel::Connect_Event(SOCKET hSocket, const struct sockaddr * pSocketAddress,
int nAddrLen,DWORD dwTimeout)
{
HANDLE hConnectEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hConnectEvent == NULL)
{
SetLastError( (int)GetLastError() );
return (SOCKET_ERROR);
}
// 注册FD_CONNECT事件
if( WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, FD_CONNECT) == SOCKET_ERROR)
{
CloseHandle(hConnectEvent);
SetLastError( 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)
{
SetLastError( WSAGetLastError() );
nConnectResult = SOCKET_ERROR;
}
else
{
//
/// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该
/// 进一步检查网络是否发生错误
///
WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hConnectEvent,&NetEvent)
== SOCKET_ERROR)
{
SetLastError( WSAGetLastError() );
nConnectResult = SOCKET_ERROR;
}
else if(NetEvent.iErrorCode[FD_CONNECT_BIT] !=0 ) // 发生错误
{
SetLastError( NetEvent.iErrorCode[FD_CONNECT_BIT] );
nConnectResult = SOCKET_ERROR;
}
else
nConnectResult = SOCKET_SUCCESS;
}
}
// 注销网络事件
WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, 0);
CloseHandle(hConnectEvent);
return (nConnectResult);
}
int CSocketModel::Connect_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 CSocketModel::CreateSocket(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 )
{
SetLastError( WSAGetLastError() );
return (INVALID_SOCKET);
}
//设置套接字选项
if ( SOCKET_ERROR == SetSocketOption(hSocket) ) //设置属性失败
{
CloseSocket(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
DWORD CSocketModel::GetIP(const char* name,BOOL bFixNtDNS /* = FALSE*/)// Used to Fix NT DNS Problem
{
//这里是为了将字串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 CSocketModel::ListenSocket(SOCKET hSocket, int nConnections)
{
if(listen(hSocket, nConnections) == SOCKET_ERROR)
{
SetLastError( WSAGetLastError() );
return (SOCKET_ERROR);
}
return (SOCKET_SUCCESS);
}