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

📄 socketmodel.cpp

📁 <VC++网络游戏建摸与实现>源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		/////////////////////////////////////////////////////////////////////////
		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);
		}

		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);
}


//关闭套接字
//入口:套接字,是否强行关闭(如果bHardClose==FALSE,那么接收剩余的数据后关闭连接)
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);
}


//阻塞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
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
		{
			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/U),协议
//出口:返回创建的重叠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);
}



// 监听套接字
//入口:套接字,接入的等待队列长度
//出口: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);
}

⌨️ 快捷键说明

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