socketmodel.cpp
资源名称:1731.rar [点击查看]
上传用户:swkcbjrc
上传日期:2016-04-02
资源大小:45277k
文件大小:30k
源码类别:
游戏
开发平台:
Visual C++
- // 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);
- }