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

📄 serversocket.cpp

📁 几个关于网络模型的代码!有事件选择模型、重叠I/0模型
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				AfxMessageBox("_WaitForCompletionThread 发生异常,线程将退出!");
				break;
			}
		}
	}

	return 0;
}

////////////////////////////////////////////////////////////////////////////////////
// 
//	Purposes:	构造函数,初始化SOCKET数组
//
////////////////////////////////////////////////////////////////////////////////////
CServerSocket::CServerSocket(void)
{
	for(int i=0;i<MAX_SOCKET;i++)
	{
		sockArray[i] = INVALID_SOCKET;            
	}
}

////////////////////////////////////////////////////////////////////////////////////
// 
//	Purposes:	析构,释放资源
//
////////////////////////////////////////////////////////////////////////////////////
CServerSocket::~CServerSocket(void)
{
	TRACE("CServerSocket 析构!");

	StopListening();

	WSACleanup();
}


//////////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	开始监听过程
//
//				初始化监听SOCKET,绑定地址,启动监听线程,都是老套路,不用多说:)
//
///////////////////////////////////////////////////////////////////////////////////////
int CServerSocket::StartListening(const UINT& port)
{
	m_nPort = port;

	WSADATA wsaData;

	int nRet;

	nRet=WSAStartup(MAKEWORD(2,2),&wsaData);                      
	if(nRet!=0)
	{
		AfxMessageBox("Load winsock2 failed");
		WSACleanup();
		return -1;
	}

	sockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);             //创建服务套接字(TCP)

	SOCKADDR_IN ServerAddr;                                           //分配端口及协议族并绑定

	ServerAddr.sin_family=AF_INET;                                
	ServerAddr.sin_addr.S_un.S_addr  =htonl(INADDR_ANY);          
	ServerAddr.sin_port=htons(port);

	nRet=bind(sockListen,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr)); // 绑定套接字

	if(nRet==SOCKET_ERROR)
	{
		AfxMessageBox("Bind Socket Fail!");
		closesocket(sockListen);
		return -1;
	}

	nRet=listen(sockListen,1);                                        //开始监听,并设置监听客户端数量
	if(nRet==SOCKET_ERROR)     
	{
		AfxMessageBox("Listening Fail!");
		return -1;
	}


	pServerListenThread =  AfxBeginThread(                            // 启动监听线程
		_ServerListenThread, 
		this
		);  

	pWaitForCompletionThread = AfxBeginThread(
		_WaitForCompletionThread,
		this,
		THREAD_PRIORITY_NORMAL,
		0,
		CREATE_SUSPENDED,NULL
		);

	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	停止监听,关闭线程,释放资源
//
///////////////////////////////////////////////////////////////////////////////////////
int CServerSocket::StopListening()
{
	if(pServerListenThread != NULL)
	{
		DWORD   dwStatus;
		::GetExitCodeThread(pServerListenThread->m_hThread, &dwStatus);

		if (dwStatus == STILL_ACTIVE)
		{
			delete pServerListenThread;
			pServerListenThread = NULL;
		}
	}

	if(pWaitForCompletionThread != NULL)
	{
		DWORD   dwStatus;
		::GetExitCodeThread(pWaitForCompletionThread->m_hThread, &dwStatus);

		if (dwStatus == STILL_ACTIVE)
		{
			delete pWaitForCompletionThread;
			pWaitForCompletionThread = NULL;
		}
	}


	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////
//	
//	Purposes:	枚举SOCKET数组,获得一个空闲的SOCKET的索引号
//
//	Hints:		可以利用自己定义的数据结构来获得更好的算法,但是这里考虑到代码复杂性,则略过
//
////////////////////////////////////////////////////////////////////////////////////////////
int CServerSocket::GetEmptySocket()
{
	for(int i=0;i<MAX_SOCKET;i++)
	{
		if(sockArray[i]==INVALID_SOCKET)
		{
			return i;
		}
	}

	return -1;
}

///////////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	根据回调函数中的Overlapped参数,判断是哪个SOCKET上发生了事件
//
//	Hints:		其实有更好的改进算法,但是为了降低代码的复杂性,就留给读者去考虑了
//
///////////////////////////////////////////////////////////////////////////////////////
int GetCurrentSocketIndex(LPWSAOVERLAPPED Overlapped)
{
	for(int i=0;i<nSockTotal;i++)
	{
		if(AcceptOverlapped[i].Internal == Overlapped->Internal)     // 因为每个Overlapped结构的Internal值都是不一样的
			return i;
	}

	return -1;
}

////////////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	给主窗体发消息显示文字信息
//
//	Parameters:	index:	标志哪个SOCKET上发生了事件
//				str		要显示的信息
//
/////////////////////////////////////////////////////////////////////////////////////////
void CServerSocket::ShowMessage(const int index, const CString& str)
{
	CString strSock;
	
	strSock.Format("SOCKET编号:%d", sockArray[index] );

	::SendMessage(
		CServerSocket::m_hNotifyWnd,
		WM_MSG_NEW_SOCKET,
		(LPARAM)(LPCTSTR)strSock,
		(LPARAM)(LPCTSTR)str
		);
}

////////////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	关闭指定SOCKET,释放资源
//
/////////////////////////////////////////////////////////////////////////////////////////
void ReleaseSocket(const int index)
{
	CServerSocket::ShowMessage(index, CString("客户端断开连接!"));

	closesocket(sockArray[index]);                             // 关闭SOCKET 
	sockArray[index] = INVALID_SOCKET;

	nSockTotal --;                                             // SOCKET总数减一                                         

	nCurSockIndex = NULLSOCKET;

	if(nSockTotal <= 0)                                        // 如果SOCKET总数为0,则处理线程休眠
		pWaitForCompletionThread->SuspendThread();
}


////////////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	获得本机IP
//
/////////////////////////////////////////////////////////////////////////////////////////
CString CServerSocket::GetLocalIP()
{
	WSADATA wsaData;
	if(WSAStartup(MAKEWORD(2,2),&wsaData)==SOCKET_ERROR)
	{
		AfxMessageBox("取得主机名字失败!");
		return "未能获得";
	}

	char hostname[20];
	gethostname(hostname,sizeof(hostname));                   // 获得本机主机名

	struct hostent FAR* lpHostEnt = gethostbyname(hostname);

	if(lpHostEnt == NULL)
	{
		return "0.0.0.0";
	}

	LPSTR lpAddr = lpHostEnt->h_addr_list[0];                 // 取得IP地址列表中的第一个为返回的IP

	struct in_addr inAddr;

	memmove(&inAddr,lpAddr,4);

	return inet_ntoa(inAddr);                                // 转化成标准的IP地址形式
} 

⌨️ 快捷键说明

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