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

📄 serversocket.cpp

📁 几个关于网络模型的代码!有事件选择模型、重叠I/0模型
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "StdAfx.h"
#include ".\serversocket.h"

#define DATA_BUFSIZE 4096         // 接收缓冲区

#define MAX_SOCKET 100            // 最大可以连入的SOCKET数量,这里可以自行更改
                                  // 重叠I/O模型在P4级别的主机上可以处理上万个工作量不大的SOCKET连接

#define NULLSOCKET -1

CWinThread* pServerListenThread = NULL;
CWinThread* pWaitForCompletionThread = NULL;

SOCKET sockListen;                               // 监听SOCKET,用以接收客户端连接

SOCKET sockArray[MAX_SOCKET];                    // 与客户端通信的SOCKET

WSAOVERLAPPED AcceptOverlapped[MAX_SOCKET];      // 重叠结构数组,每个事件对应一个

WSABUF DataBuf[MAX_SOCKET];                      // 缓冲区,WSARecv的参数

WSAEVENT EventArray[1];                          // 因为WSAWaitForMultipleEvents() API要求在一个或多个事件对象上等待,
												 //	因此不得不创建一个伪事件对象.详见配套文章
                                                 // 但是这个事件数组已经不是和SOCKET相关联的了

int  nSockIndex = 0,                             // SOCKET序号
     nSockTotal = 0,                             // SOCKET总数
	 nCurSockIndex = 0;                          // 当前完成重叠操作的SOCKET

BOOL bNewSocket = FALSE;                         // 是否是第一次投递SOCKET上的WSARecv操作

HWND CServerSocket::m_hNotifyWnd = NULL;         // 主对话框句柄,用以发送消息



int GetCurrentSocketIndex(LPWSAOVERLAPPED Overlapped);

void ReleaseSocket(const int);


///////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	系统自动调用的回调函数
//
//				在我们投递的WSARecv操作完成的时候,系统会自动调用这个函数	
//
////////////////////////////////////////////////////////////////////////////////////
void CALLBACK CompletionRoutine(DWORD Error,
								DWORD BytesTransfered,
								LPWSAOVERLAPPED Overlapped,
								DWORD inFlags)
{
	TRACE("回调CompletionRoutine......");

	nCurSockIndex = GetCurrentSocketIndex(Overlapped);             // 根据传入的重叠结构,
	                                                               // 来寻找究竟是哪个SOCKET上触发了事件

	//////////////////////////////////////////////////////////////////////
	//	错误处理:可能是对方关闭套接字,或者发生一个严重错误
	if(Error != 0 || BytesTransfered == 0)                         
	{
		ReleaseSocket(nCurSockIndex);

		return;
	}

	TRACE("数据:");
	TRACE(DataBuf[nCurSockIndex].buf);

	//////////////////////////////////////////////////////////////////////////////////
	//	程序执行到这里,说明我们先前投递的WSARecv操作已经胜利完成了!!!^_^
	//	DataBuf结构里面就有客户端传来的数据了!!^_^

	CServerSocket::ShowMessage(nCurSockIndex,CString(DataBuf[nCurSockIndex].buf));
		
	return;
}

///////////////////////////////////////////////////////////////////////////////////
//
//	Purposes:	监听端口,接收连入的连接
//
////////////////////////////////////////////////////////////////////////////////////
UINT _ServerListenThread(LPVOID lParam)
{
	TRACE("服务器端监听中.....\n");

	CServerSocket* pServer = (CServerSocket*)lParam;

	SOCKADDR_IN ClientAddr;                                  // 定义一个客户端得地址结构作为参数
	int addr_length=sizeof(ClientAddr);

	while(TRUE)
	{
		SOCKET sockTemp = accept(                            // 接收连入的客户端
			sockListen,
			(SOCKADDR*)&ClientAddr,
			&addr_length
			); 

		if(sockTemp  == INVALID_SOCKET)
		{
			AfxMessageBox("Accept Connection failed!");
			
			continue;
		}

		nSockIndex = pServer->GetEmptySocket();               // 获得一个空闲的SOCKET索引号

		sockArray[nSockIndex] = sockTemp;

		// 这里可以取得客户端的IP和端口,但是我们只取其中的SOCKET编号
		//LPCTSTR lpIP =  inet_ntoa(ClientAddr.sin_addr);     // IP
		//UINT nPort = ntohs(ClientAddr.sin_port);            // PORT

		CServerSocket::ShowMessage(nSockIndex,"客户端建立连接!");

		nSockTotal++;                                         // SOCKET总数加一

		bNewSocket = TRUE;                                    // 标志投递一个新的WSARecv请求

		if(nSockTotal == 1)                                   // SOCKET数量不为空时激活处理线程
			pWaitForCompletionThread->ResumeThread();
	}

	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////
// 
//	Purposes:	用于投递第一个WSARecv请求,并等待系统完成的通知,然后继续投递后续的请求
//
////////////////////////////////////////////////////////////////////////////////////////////
UINT _WaitForCompletionThread(LPVOID lParam)
{
	TRACE("开始等待线程....\n");

	EventArray[0] = WSACreateEvent();                        // 建立一个事件

	DWORD dwRecvBytes = 0,                                   // WSARecv的参数
		  Flags = 0;

	while(TRUE)
	{
		if(bNewSocket)                                       // 如果标志为True,则表示投递第一个WSARecv请求!
		{
			bNewSocket = FALSE;

		//************************************************************************
		//
		//				现在开始投递第一个WSARecv请求! 
		//
		//************************************************************************

			Flags = 0;

			ZeroMemory(&AcceptOverlapped[nSockIndex],sizeof(WSAOVERLAPPED));

			char buffer[DATA_BUFSIZE];
			ZeroMemory(buffer,DATA_BUFSIZE);

			DataBuf[nSockIndex].len = DATA_BUFSIZE;
			DataBuf[nSockIndex].buf = buffer;

			// 将WSAOVERLAPPED结构指定为一个参数,在套接字上投递一个异步WSARecv()请求
			// 并提供下面的作为完成例程的CompletionRoutine回调函数
			if(WSARecv(
				sockArray[nSockIndex],
				&DataBuf[nSockIndex],
				1,
				&dwRecvBytes,
				&Flags,
				&AcceptOverlapped[nSockIndex],
				CompletionRoutine) == SOCKET_ERROR)
			{
				if(WSAGetLastError() != WSA_IO_PENDING)
				{
					ReleaseSocket(nSockIndex);

					continue;
				}
			}
		}

		////////////////////////////////////////////////////////////////////////////////
		// 等待重叠请求完成,自动回调完成例程函数
		DWORD dwIndex = WSAWaitForMultipleEvents(1,EventArray,FALSE,10,TRUE);


		///////////////////////////////////////////////////////////////////////////////////
		// 返回WAIT_IO_COMPLETION表示一个重叠请求完成例程例结束。继续为更多的完成例程服务
		if(dwIndex == WAIT_IO_COMPLETION)
		{
			
			TRACE("重叠操作完成...\n");

			//************************************************************************
			//
			//				现在开始投递后续的WSARecv请求! 
			//
			//**********************************************************************

			// 前一个完成例程结束以后,开始在此套接字上投递下一个WSARecv,代码和前面的一模一样^_^

			if(nCurSockIndex != NULLSOCKET)                          // 这个nCurSockIndex来自于前面完成例程得到的那个
			{
				Flags = 0;

				ZeroMemory(&AcceptOverlapped[nCurSockIndex],sizeof(WSAOVERLAPPED));

				char buffer[DATA_BUFSIZE];
				ZeroMemory(buffer,DATA_BUFSIZE);

				DataBuf[nCurSockIndex].len = DATA_BUFSIZE;
				DataBuf[nCurSockIndex].buf = buffer;

				/////////////////////////////////////////////////////////////////////////////////////
				// 将WSAOVERLAPPED结构制定为一个参数,在套接字上投递一个异步WSARecv()请求
				// 并提供下面作为完成例程的CompletionRoutine回调函数
				if(WSARecv(
					sockArray[nCurSockIndex],
					&DataBuf[nCurSockIndex],
					1,
					&dwRecvBytes,
					&Flags,
					&AcceptOverlapped[nCurSockIndex],
					CompletionRoutine                                // 注意这个回调函数
					) == SOCKET_ERROR)
				{
					if(WSAGetLastError() != WSA_IO_PENDING)          // 出现错误,关闭SOCKET
					{
						ReleaseSocket(nCurSockIndex);

						continue;
					}
				}

				// 这里最好添加一个步骤,去掉数组中无效的SOCKET
				// 因为非正常关闭的客户端,比如拔掉网线等,这里是不会接到通知的
			}

			continue;
		}
		else  
		{
			if(dwIndex == WAIT_TIMEOUT)                              // 继续等待
				continue;
			else                                                     // 如果出现其他错误就坏事了 
			{ 

⌨️ 快捷键说明

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