C++ 基于事件选择模型的服务器

使用windows API 实现的简单的服务器和客户端模型

第一部分:客户端部分

// 客户端连接到服务器后创建线程,以下为线程代码
UINT ThreadProc(LPVOID lpParameter)
{
	CClientDlg *pDlg = (CClientDlg*)lpParameter;
	ASSERT(pDlg != NULL);

	SOCKET *clientSocket = pDlg->GetClientSocket();  // 获取客户端套接字

	char buffer[1024]; // 用于接收数据
	while (TRUE) {
		int rev = recv(sock, buffer, 1024, 0);
		if (rev < 0) {   // 这里一定要判断,否则关闭套接字时会返回-1,造成内存出错,程序崩死
		    break;
		}
		buffer[rev] = '\0';
		CString str;
		str.Format(_T("%s"),buffer);
		pDlg->NewMsg(str);  // 将接收到的数据返回客户端
		str.DeleteObject(); // 释放内存
		memset(buffer, 0, 1024);
	}
	return TRUE;
}

第二部分:服务器,在启动服务器的时候创建线程

UINT ThreadProc(LPVOID lpParameter)
{
	CServerDlg *pDlg = (CServerDlg*)lpParameter;
	ASSERT(pDlg != NULL);

	SOCKET acceptSocket = INVALID_SOCKET;
	SOCKET listenSocket = INVALID_SOCKET;

	WSAEVENT newEvent;
	WSANETWORKEVENTS NetworkEvents;
	
	TCHAR buf[1024] = { 0 };

	// 服务器套接字创建
	listenSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == listenSocket)
	{
		return FALSE;
	}

	// 服务器地址端口绑定
	sockaddr_in serverAddress;
	serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_port = htons(9990);

	if (SOCKET_ERROR == bind(listenSocket, (sockaddr*)&serverAddress, sizeof(sockaddr_in)))
	{
		return FALSE;
	}
	newEvent = WSACreateEvent();
	WSAEventSelect(listenSocket, newEvent, FD_ACCEPT | FD_CLOSE);
	socketArray[dwTotal] = listenSocket;
	eventArray[dwTotal] = newEvent;
	dwTotal++;
	listen(listenSocket, SOMAXCONN); // 设置监听
        
	DWORD Index;
	while (TRUE)
	{
	        // 设置超时时间,并判断触发事件的第一个下标
		Index = WSAWaitForMultipleEvents(dwTotal, eventArray, FALSE, 100, FALSE);
		if (WSA_WAIT_TIMEOUT == Index)
		{
			continue;
		}
		WSAEnumNetworkEvents(socketArray[Index - WSA_WAIT_EVENT_0], eventArray[Index - WSA_WAIT_EVENT_0], &NetworkEvents);
		WSAResetEvent(eventArray[Index - WSA_WAIT_EVENT_0]);
		// 客户端接入事件
		if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
		{
			if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
			{
				continue;
			}
			if (dwTotal > WSA_MAXIMUM_WAIT_EVENTS)
			{
				AfxMessageBox(_T("系统消息: 客户端超过最大连接数!"));
				continue;
			}

			// 有新客户端连接
			acceptSocket = accept(socketArray[Index - WSA_WAIT_EVENT_0], NULL, 0);
			WSAResetEvent(eventArray[Index - WSA_WAIT_EVENT_0]);
			newEvent = WSACreateEvent();
			WSAEventSelect(acceptSocket, newEvent, FD_READ | FD_WRITE | FD_CLOSE); // 设置监听的事件
			// 放入监听队列中,注意socket和event是一一对应关系
			socketArray[dwTotal] = acceptSocket;
			eventArray[dwTotal] = newEvent;
			dwTotal++;
			pDlg->newConnect(dwTotal - 1); // 反馈给界面
		}
		// 有数据过来了
		if (NetworkEvents.lNetworkEvents & FD_READ)
		{
			if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
			{
				AfxMessageBox(_T("系统消息:接受客户端数据失败!"));
				continue;
			}
			recv(socketArray[Index - WSA_WAIT_EVENT_0], (char *)buf, 1024, 0);
			WSAResetEvent(eventArray[Index - WSA_WAIT_EVENT_0]);
			CString cstrMsg = buf;
			pDlg->getNewMessage(cstrMsg, Index - WSA_WAIT_EVENT_0);
		}
		if (NetworkEvents.lNetworkEvents & FD_WRITE)
		{
			if (NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)
			{
				continue;
			}
		}
		// 断开连接
		if (NetworkEvents.lNetworkEvents & FD_CLOSE)
		{
			int a = NetworkEvents.iErrorCode[FD_CLOSE_BIT];
			if (a == 10053)
			{
				pDlg->clientExit(Index - WSA_WAIT_EVENT_0); // 界面操作
			}
		}
	}
	return TRUE;
}


你可能感兴趣的:(socket,服务器,客户端,事件选择模型)