📄 socketmodel.cpp
字号:
// SocketModel.cpp.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SocketModel.h"
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)
}
return (SOCKET_SUCCESS);
}
//接收所有数据,注意在这个函数调用之前必须确认是否有接收消息到来
//入口:套接字,数据缓冲区,缓冲区大小
//出口:如果正确那么返回接收的字节数量,错误返回错误代码
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);
}
// 接收数据(阻塞直至收到数据为止)
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);
}
//阻塞住了
Sleep(_BLOCKED_SNDRCV_SLEEP);
}
CloseHandle(hReadEvent);
return (nRecvBytes);
}
//发送数据,阻塞
//入口:套接字,发送的字串,字串长度,超时值
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::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);
}
//////////////////////////////////////////////////////////////////////////
// 睡眠一段时间
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -