int MightyTCPEventSelectServer::acceptSocketObject()
{
	while(TRUE)
	{
		int nRet = ::WaitForSingleObject(m_ListenEvent,5*1000);
		if(nRet == WAIT_FAILED)
		{
			return -1;
		}
		else if(nRet == WSA_WAIT_TIMEOUT)	// 定时显式状态信息
		{
			
			continue;
		}
		else								// 有新的连接未决
		{
			::ResetEvent(m_ListenEvent);
			// 循环处理所有未决的连接请求
			while(TRUE)
			{
				sockaddr_in si;
				int nLen = sizeof(si);
				SOCKET sNew = ::accept(m_ListenSock, (sockaddr*)&si, &nLen);
				if(sNew == SOCKET_ERROR)
					break;
				PSOCKET_OBJ pSocket = GetSocketObj(sNew);
				pSocket->addrRemote = si;
				::WSAEventSelect(pSocket->s, pSocket->event, FD_READ|FD_CLOSE|FD_WRITE);
				AssignToFreeThread(pSocket);
			}
		}
	}
}
Example #2
0
int main()
{
	USHORT nPort = 4567;	// 此服务器监听的端口号

	// 创建监听套节字
	SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(nPort);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;
	if(::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf(" Failed bind() \n");
		return -1;
	}
	::listen(sListen, 200);

	// 创建事件对象,并关联到监听的套节字
	WSAEVENT event = ::WSACreateEvent();
	::WSAEventSelect(sListen, event, FD_ACCEPT|FD_CLOSE);

	::InitializeCriticalSection(&g_cs);

	// 处理客户连接请求,打印状态信息
	while(TRUE)
	{
		int nRet = ::WaitForSingleObject(event, 5*1000);
		if(nRet == WAIT_FAILED)
		{
			printf(" Failed WaitForSingleObject() \n");
			break;
		}
		else if(nRet == WSA_WAIT_TIMEOUT)	// 定时显式状态信息
		{
			printf(" \n");
			printf("   TatolConnections: %d \n", g_nTatolConnections);
			printf(" CurrentConnections: %d \n", g_nCurrentConnections);
			continue;
		}
		else								// 有新的连接未决
		{
			::ResetEvent(event);
			// 循环处理所有未决的连接请求
			while(TRUE)
			{
				sockaddr_in si;
				int nLen = sizeof(si);
				SOCKET sNew = ::accept(sListen, (sockaddr*)&si, &nLen);
				if(sNew == SOCKET_ERROR)
					break;
				PSOCKET_OBJ pSocket = GetSocketObj(sNew);
				pSocket->addrRemote = si;
				::WSAEventSelect(pSocket->s, pSocket->event, FD_READ|FD_CLOSE|FD_WRITE);
				AssignToFreeThread(pSocket);
			}
		}
	}
	::DeleteCriticalSection(&g_cs);
	return 0;
}
void MightyTCPCompletionPortServer::HandleIO(DWORD dwKey, PCompletionPort_BufObj pBuffer, DWORD dwTrans, int nError)
{
	PCompletionPortIOObject pContext = (PCompletionPortIOObject)dwKey;

	//首先减少套节字上的未决I/O计数
	if(pContext != NULL)
	{
		if(pBuffer->nOperation == OP_READ)
			pContext->nOutstandingRecv --;
		else if(pBuffer->nOperation == OP_WRITE)
			pContext->nOutstandingSend --;



		// 检查套节字是否已经被我们关闭
		if(pContext->nCondition) 
		{

			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				RemoveSocketObj(pContext);
			}
			// 释放已关闭套节字的未决I/O
			ReleaseBuffer(pBuffer);	
			return;
		}
	}
	else
	{
		RemovePendingAccept(pBuffer);
	}

	//检查套节字上发生的错误,如果有的话,通知用户,然后关闭套节字
	if(nError != NO_ERROR)
	{
		if(pBuffer->nOperation != OP_ACCEPT)
		{
			//if(nError==ERROR_NETNAME_DELETED)
			RemoveSocketObj(pContext);
			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				//ReleaseContext(pContext);
			}

		}
		else // 在监听套节字上发生错误,也就是监听套节字处理的客户出错了
		{
			// 客户端出错,释放I/O缓冲区
			if(pBuffer->sAccept!= INVALID_SOCKET)
			{
				::closesocket(pBuffer->sAccept);
				pBuffer->sAccept= INVALID_SOCKET;
			}		
		}

		ReleaseBuffer(pBuffer);
		return;
	}


	// 开始处理
	if(pBuffer->nOperation == OP_ACCEPT)
	{
		if(dwTrans == 0)
		{
			if(pBuffer->sAccept!= INVALID_SOCKET)
			{
				::closesocket(pBuffer->sAccept);
				pBuffer->sAccept= INVALID_SOCKET;
			}
		}
		else
		{
			// 为新接受的连接申请客户上下文对象
			PCompletionPortIOObject pClient =GetSocketObj(pBuffer->sAccept);
			if(pClient != NULL)
			{
				if(InsertSocketObj(pClient)==0)
				{	
					// 取得客户地址
					int nLocalLen, nRmoteLen;
					LPSOCKADDR pLocalAddr, pRemoteAddr;
					m_lpfnGetAcceptExSockaddrs(
						pBuffer->buff,
						pBuffer->nLen - ((sizeof(sockaddr_in) + 16) * 2),
						sizeof(sockaddr_in) + 16,
						sizeof(sockaddr_in) + 16,
						(SOCKADDR **)&pLocalAddr,
						&nLocalLen,
						(SOCKADDR **)&pRemoteAddr,
						&nRmoteLen);
					memcpy(&pClient->addrLocal, pLocalAddr, nLocalLen);
					memcpy(&pClient->addrRemote, pRemoteAddr, nRmoteLen);

					// 关联新连接到完成端口对象
					::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletionPort, (DWORD)pClient, 0);

					// 通知用户
					pBuffer->nLen = dwTrans;
					

					m_pNotifyCallBack->OnRecvData(pBuffer->buff,dwTrans,pClient->identityIDKey);

					// 向新连接投递几个Read请求,这些空间在套节字关闭或出错时释放
					for(int i=0; i<5; i++)
					{
						PCompletionPort_BufObj p = AllocateBuffer(pClient,2048);
						if(p != NULL)
						{
							if(!PostRecv(p))
							{
								RemoveSocketObj(pClient);
								break;
							}
						}
					}
				}
				else	// 连接数量已满,关闭连接
				{
					RemoveSocketObj(pClient);
					
				}
			}
			else
			{
				// 资源不足,关闭与客户的连接即可
				::closesocket(pBuffer->sAccept);
				pBuffer->sAccept= INVALID_SOCKET;
			}
		}

		// Accept请求完成,释放I/O缓冲区
		ReleaseBuffer(pBuffer);	

		// 通知监听线程继续再投递一个Accept请求
		::InterlockedIncrement(&m_nRepostCount);
		::SetEvent(m_hRepostEvent);
	}
	else if(pBuffer->nOperation == OP_READ)
	{
		if(dwTrans == 0)	// 对方关闭套节字
		{
			// 先通知用户
			pBuffer->nLen = 0;
			RemoveSocketObj(pContext);
			// 释放客户上下文和缓冲区对象
			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				//ReleaseContext(pContext);
			}
			//ReleaseBuffer(pBuffer);	
		}
		else
		{
			pBuffer->nLen = dwTrans;
			// 按照I/O投递的顺序读取接收到的数据
			PCompletionPort_BufObj pNextIO = GetNextReadBuffer(pContext, pBuffer);
			while(pNextIO != NULL)
			{
				

				m_pNotifyCallBack->OnRecvData(pNextIO->buff,dwTrans,pContext->identityIDKey);
				// 增加要读的序列号的值
				::InterlockedIncrement((LONG*)&pContext->nCurrentReadSequence);
				// 释放这个已完成的I/O
				ReleaseBuffer(pNextIO);
				pNextIO= GetNextReadBuffer(pContext, NULL);
			}

			// 继续投递一个新的接收请求
			pBuffer = AllocateBuffer(pContext,4096);
			if(pBuffer == NULL || !PostRecv(pBuffer))
			{
				//closeAConnection(pContext);
			}
		}
	}
	else if(pBuffer->nOperation == OP_WRITE)
	{

		if(dwTrans == 0)	// 对方关闭套节字
		{
			// 先通知用户
			pBuffer->nLen = 0;
			RemoveSocketObj(pContext);
			// 再关闭连接
			//CloseAConnection(pContext);

			// 释放客户上下文和缓冲区对象
			if(pContext->nOutstandingRecv == 0 && pContext->nOutstandingSend == 0)
			{		
				//ReleaseContext(pContext);
			}
			//ReleaseBuffer(pBuffer);	
		}
		else
		{
			// 写操作完成,通知用户
			pBuffer->nLen = dwTrans;
			//OnWriteCompleted(pContext, pBuffer);
			// 释放SendText函数申请的缓冲区
			ReleaseBuffer(pBuffer);
		}
	}
}
bool MightyTCPCompletionPortServer::Create(const unsigned short & usPort)
{
		/*if (!(P2PUtilTools::is2KOS())) 
		{
			return false;
		}*/

		m_ListenPort=usPort;
		m_ListenSock = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
		SOCKADDR_IN si;
		si.sin_family = AF_INET;
		si.sin_port = ::ntohs(usPort);
		si.sin_addr.S_un.S_addr = INADDR_ANY;

		if(::bind(m_ListenSock, (sockaddr*)&si, sizeof(si)) == SOCKET_ERROR)
		{
			return false;
		}
		::listen(m_ListenSock, 200);

		m_pListenObj= GetSocketObj(m_ListenSock);
		// 创建完成端口对象
		m_hCompletionPort = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);

		// 加载扩展函数AcceptEx
		GUID GuidAcceptEx = WSAID_ACCEPTEX;
		DWORD dwBytes;
		::WSAIoctl(m_ListenSock, 
			SIO_GET_EXTENSION_FUNCTION_POINTER, 
			&GuidAcceptEx, 
			sizeof(GuidAcceptEx),
			&m_lpfnAcceptEx, 
			sizeof(m_lpfnAcceptEx), 
			&dwBytes, 
			NULL, 
			NULL);

		// 加载扩展函数GetAcceptExSockaddrs
		GUID GuidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
		::WSAIoctl(m_ListenSock,
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&GuidGetAcceptExSockaddrs,
			sizeof(GuidGetAcceptExSockaddrs),
			&m_lpfnGetAcceptExSockaddrs,
			sizeof(m_lpfnGetAcceptExSockaddrs),
			&dwBytes,
			NULL,
			NULL
			);


		// 将监听套节字关联到完成端口,注意,这里为它传递的CompletionKey为0
		::CreateIoCompletionPort((HANDLE)m_ListenSock, m_hCompletionPort, (DWORD)0, 0);

		// 注册FD_ACCEPT事件。
		// 如果投递的AcceptEx I/O不够,线程会接收到FD_ACCEPT网络事件,说明应该投递更多的AcceptEx I/O
		WSAEventSelect(m_ListenSock, m_hAcceptEvent, FD_ACCEPT);

		startWork();

		return 0;
}
Example #5
0
//---------------------------------------------------------------------------------------------------------------------------
//CLConnect()
//NULL - connect failed .
//---------------------------------------------------------------------------------------------------------------------------
SOCKET_OBJ * CIocpServer::CLConnect(const char * ip,const char *port,int flag)
{
	SOCKET_OBJ *sockobj = NULL;
	BUFFER_OBJ *recvobj = NULL;
	struct addrinfo *res=NULL;
	bool   bFlag = false;

	res = ResolveAddress(ip, port, AF_INET,SOCK_STREAM, IPPROTO_TCP);
	if (res == NULL)
	{
		fprintf(stderr, "CLConnect ResolveAddress failed to return any addresses!\n");
		return NULL;
	}

	sockobj = GetSocketObj(INVALID_SOCKET);

	// create the socket
	sockobj->s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sockobj->s == INVALID_SOCKET)
	{
		fprintf(stderr,"CLConnect socket failed: %d\n", WSAGetLastError());
		FreeSocketObj(sockobj);
		return NULL;
	}

#ifdef ENABLE_UNLIMIT_PORT
	SOCKADDR_IN local_addr={0};
	local_addr.sin_family = AF_INET;
	local_addr.sin_addr.s_addr  = ADDR_ANY;
	BOOL optvar = true;
	for(int i=0;i<40;i++)
	{
		local_addr.sin_port = htons(m_UnlimitPort);
		setsockopt(sockobj->s,SOL_SOCKET,SO_REUSEADDR,(char*)&optvar,sizeof(optvar));

		if(bind(sockobj->s,(SOCKADDR *)&local_addr,sizeof(SOCKADDR)) == -1)
		{
			if(m_UnlimitPort < UNLIMIT_PORT_END) 
				m_UnlimitPort++;
			else
				m_UnlimitPort = UNLIMIT_PORT_START;

			if(WSAGetLastError() != WSAEADDRINUSE )
			{ //bind出错了
				fprintf(stderr,"bind() failed: %d\n", WSAGetLastError());
				closesocket(sockobj->s);
				sockobj->s = INVALID_SOCKET;
				FreeSocketObj(sockobj);
				return NULL;
			}

		}
		else
			break;
	}

	if(m_UnlimitPort < UNLIMIT_PORT_END) 
		m_UnlimitPort++;
	else
		m_UnlimitPort = UNLIMIT_PORT_START;

#endif

	if( connect(sockobj->s,res->ai_addr,(int)res->ai_addrlen)!=SOCKET_ERROR )
	{
		if( CreateIoCompletionPort((HANDLE)sockobj->s, CLCompletionPort, (ULONG_PTR)sockobj, 0) == NULL)
			fprintf(stderr, "CLConnect : CLCreateIoCompletionPort failed: %d\n", GetLastError());
		else 
			bFlag = true;
	}

#ifdef LOG_LEVEL2
	if(!bFlag)
		Log_Server.Write("CLConnect失败: %d\n",WSAGetLastError());
#endif

	if(bFlag)
	{
		recvobj = GetBufferObj();

#ifdef DEBUG_IOCP
		recvobj->sclient = sockobj->s;
#endif

		LOCK(&sockobj->cs);

		if (PostRecv(sockobj, recvobj) != NO_ERROR)
		{
			UNLOCK(&sockobj->cs);
			FreeBufferObj(recvobj);
		}
		else
		{
			sockobj->flag = flag;
			sockobj->flag_accept = 1;
			sockobj->flag_close = 1;

			sockobj->recvobj = recvobj;

#ifdef ENABLE_KEEPALIVE
			AddAlive(sockobj,GetTickCount());
#endif

#ifdef DEBUG_IOCP
			sockobj->freeed = 0;
			sockobj->onclosed = 0;
#endif
			UNLOCK(&sockobj->cs);

			CLOnConnect(sockobj,sockobj->flag);

			return sockobj;
		}
	}

	closesocket(sockobj->s);
	sockobj->s = INVALID_SOCKET;
	FreeSocketObj(sockobj);

	return NULL;
}
Example #6
0
//---------------------------------------------------------------------------------------------------------------------------
//StartServer()
//start  listen
//---------------------------------------------------------------------------------------------------------------------------
int  CIocpServer::StartServer(const char *local_ip,const char *local_port)
{
	if(!m_Inited)
	{
		fprintf(stderr, "Run Init() first !\n");
		return -1;
	}

	SOCKET_OBJ      *sockobj=NULL;
	HANDLE           hrc;
	int              endpointcount=0,
					 rc,
					 i;
	HANDLE			 event_accept; 

	struct addrinfo *res=NULL,
		*ptr=NULL;


#ifdef LOG_LEVEL2
	printf("LOG_LEVEL2");
#else 
//
#ifdef LOG_LEVEL1
	printf("LOG_LEVEL1");
#else
	printf("LOG_NONE");
#endif
//
#endif

	printf("\n\n连接线程:%d: 监听线程:%d; 平均连接数:%d ; ",
		m_CLThreads,m_Threads,AVERAGE_CONNECTIONS);
	printf("IOCP版本: %s;\n",IOCP_VERSION);

#ifdef ENABLE_KEEPALIVE
	printf("心跳检测:开启; ");
#else
	printf("心跳检测:关闭; ");
#endif
	printf("心跳超时:%d; 关闭延时:%d\n",KEEPALIVE_TIME,CLOSE_DELAY);


	res = ResolveAddress(local_ip, local_port, AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (res == NULL)
	{
		fprintf(stderr, "ResolveAddress failed to return any addresses!\n");
		return -1;
	}

	ptr = res;
	if (ptr)
	{
		sockobj = GetSocketObj(INVALID_SOCKET);
		// create the socket
		sockobj->s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (sockobj->s == INVALID_SOCKET)
		{
			fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
			return -1;
		}

		// Associate the socket and its SOCKET_OBJ to the completion port
		hrc = CreateIoCompletionPort((HANDLE)sockobj->s, CompletionPort, (ULONG_PTR)sockobj, 0);
		if (hrc == NULL)
		{
			fprintf(stderr, "CreateIoCompletionPort failed: %d\n", GetLastError());
			return -1;
		}

		// bind the socket to a local address and port
		rc = bind(sockobj->s, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (rc == SOCKET_ERROR)
		{
			fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
			return -1;
		}

		BUFFER_OBJ *acceptobj=NULL;
		GUID        guidAcceptEx = WSAID_ACCEPTEX;
		GUID	    guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
		DWORD       bytes;

		// Need to load the Winsock extension functions from each provider
		//    -- e.g. AF_INET and AF_INET6. 
		rc = WSAIoctl(
			sockobj->s,
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&guidAcceptEx,
			sizeof(guidAcceptEx),
			&lpfnAcceptEx,
			sizeof(lpfnAcceptEx),
			&bytes,
			NULL,
			NULL
			);
		if (rc == SOCKET_ERROR)
		{
			fprintf(stderr, "WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER failed: %d\n",
				WSAGetLastError());
			return -1;
		}

		rc = WSAIoctl(
			sockobj->s,
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&guidGetAcceptExSockaddrs,
			sizeof(guidGetAcceptExSockaddrs),
			&lpfnGetAcceptExSockaddrs,
			sizeof(lpfnGetAcceptExSockaddrs),
			&bytes,
			NULL,
			NULL
			);
		if (rc == SOCKET_ERROR)
		{
			fprintf(stderr, "WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER faled: %d\n",
				WSAGetLastError());
			return -1;
		}

		// For TCP sockets, we need to "listen" on them
		rc = _(sockobj->s, 32);
		if (rc == SOCKET_ERROR)
		{
			fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
			return -1;
		}
		
		event_accept =  CreateEvent(NULL, TRUE, FALSE, NULL);
		if(event_accept == NULL)
		{
			fprintf(stderr,"event_accept CreateEvent failed: %d\n",GetLastError());
			return -1;
		}

		rc = WSAEventSelect(sockobj->s,event_accept,FD_ACCEPT);
		if (rc == SOCKET_ERROR)
		{
			fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
			return -1;
		}

        
		// Post the AcceptEx(s)
		for(i=0; i < DEFAULT_ACCEPTEX_COUNT ;i++)
		{
			acceptobj = GetBufferObj();
			sockobj->recvobj = acceptobj;
			if(PostAccept(sockobj, acceptobj) != 0)
			{
				FreeBufferObj(acceptobj);
				fprintf(stderr, "PostAccept failed: %d\n", WSAGetLastError());
				return -1;
			}
		}


		endpointcount++;
		ptr = ptr->ai_next;
	}
	// free the addrinfo structure for the 'bind' address
	freeaddrinfo(res);

	DWORD sleeptime = CLOSE_DELAY / 2;				 //每次sleep的时间

#ifdef LOG_STATUS
	long		sock=0;
	long		buf=0;
#endif

	if(sleeptime < 50) //限制在50ms以外
		sleeptime = 50;

	DWORD time_ontimer=GetTickCount();
	DWORD time_close = time_ontimer;
	DWORD time_alive = time_ontimer;
	DWORD newtime;
	BUFFER_OBJ *acceptobj;

	printf("\n>>> 服务器地址: %s: 端口号: %s <<<\n\n",
		local_ip, local_port);

	while (1)
	{
		rc = WaitForSingleObject(event_accept,sleeptime);
		if(rc == WAIT_FAILED)
		{
			fprintf(stderr,"WaitForSingleObject Failed:%d\n",GetLastError());
			break;
		} 
		else if(rc != WAIT_TIMEOUT) //GOT FD_ACCEPT
		{
		//	acceptobj = GetBufferObj();
		//	PostAccept(sockobj,acceptobj);
			if(m_accept_count < DEFAULT_ACCEPTEX_COUNT /2)
			{
				for(int i=0;i<DEFAULT_ACCEPTEX_COUNT/2;i++)
				{
					acceptobj = GetBufferObj();
					PostAccept(sockobj,acceptobj);
				}
			}
			ResetEvent(event_accept);
		}

		newtime = GetTickCount();

		if(newtime - time_ontimer > 3000) // 3秒
		{ 
			OnTimer();  //call virtual timer();
			time_ontimer = newtime;			
#ifdef LOG_STATUS		//显示服务器状态
			if(sock != gTotalSock || buf != gTotalBuf)
			{
				Log_Server.Write("服务器状态 : sock : %d ; buf : %d ; IoCount : %d ;",gTotalSock,gTotalBuf,gIoCount);

				sock = gTotalSock;
				buf = gTotalBuf;
			}
#endif

		}

		//Check Close
		if(newtime - time_close > sleeptime)
		{
			time_close = newtime;
			CheckClose();
		}

		if(newtime - time_alive > KEEPALIVE_TIME / 3)
		{
			CheckAlive();
			time_alive = newtime;
		}

	}

	WSACleanup();

	return 0;
}
Example #7
0
//---------------------------------------------------------------------------------------------------------------------------
//HanelIO()
//---------------------------------------------------------------------------------------------------------------------------
void CIocpServer::HandleIo(SOCKET_OBJ *sock, BUFFER_OBJ *buf, 
						   HANDLE CompPort, DWORD BytesTransfered, DWORD error,
						   ADOConn *pAdo,bool isClient)
{

#ifdef LOG_STATUS
	InterlockedDecrement(&gIoCount);
#endif

	switch(buf->operation) 
	{	
	case OP_ACCEPT:		//处理AcceptEx的返回	
		LOCK(&sock->cs);//加锁
		{
			if(error == 0)
			{			
				SOCKET_OBJ *clientobj = GetSocketObj(buf->sclient);//创建一个客户端sockobj
				HANDLE hrc = CreateIoCompletionPort(	           //将sockobj添加到完成端口处理列表	
					(HANDLE)buf->sclient,
					CompPort,
					(ULONG_PTR)clientobj,
					0
					);

				if (hrc != NULL) 
				{
					//读取ip地址
					SOCKADDR *local=NULL;
					SOCKADDR *remote=NULL;
					int local_len;
					int remote_len;

					lpfnGetAcceptExSockaddrs(buf->buf,0,sizeof(SOCKADDR_STORAGE) + 16
						,sizeof(SOCKADDR_STORAGE) + 16,
						&local,&local_len,&remote,&remote_len);
					clientobj->addr = ((SOCKADDR_IN *)remote)->sin_addr;

#ifdef LOG_LEVEL1
					Log_Server.Write("--新连接 ip = %s , sock = %d ",GetAddress(clientobj),
						clientobj->s);
#endif

					BUFFER_OBJ *recvobj = GetBufferObj();
//禁用发送缓冲
#ifdef SEND_BUF_DISABLE
					BOOL sndbuf=0;
					setsockopt(buf->sclient,SOL_SOCKET,SO_SNDBUF,(char *)&sndbuf,sizeof(sndbuf));
#endif
					LOCK(&clientobj->cs);

					if(PostRecv(clientobj,recvobj) == 0)
					{ 
#ifdef DEBUG_IOCP
						clientobj->sockfd = clientobj->s;
						recvobj->sclient = clientobj->s;
#endif
						clientobj->recvobj = recvobj;
						AddAlive(clientobj,GetTickCount()); //把他添加到心跳列表,如果一个客户端连上来以后不发数据,会被踢掉
					}
					else
					{
						FreeBufferObj(recvobj);
						closesocket(clientobj->s);     //注意关闭句柄,clientobj->s的句柄在PostAccept时候创建
						clientobj->s = INVALID_SOCKET;
						FreeSocketObj(clientobj);
					}

					UNLOCK(&clientobj->cs);
				} 
				else
				{	//创建完成端口失败,像new失败一样,基本上不会出现
#ifdef LOG_LEVEL2
					Log_Server.Write("CreateIoCompletionPort 错误:%d",GetLastError());
#endif
					closesocket(clientobj->s);
					clientobj->s = INVALID_SOCKET;
					FreeSocketObj(clientobj);
				}
			}
			else	//如果AcceptEx返回出错,说明有一个客户端连了一半就退了,需要把他的句柄关了.
				closesocket(buf->sclient);

			InterlockedDecrement(&m_accept_count);
			// 一般情况下重新PostAccept
			if(m_accept_count < DEFAULT_ACCEPTEX_COUNT *2)
			{
				if(PostAccept(sock,buf)!=0)
					FreeBufferObj(buf);
			}
		}

		UNLOCK(&sock->cs);
		break;
	case OP_READ: //收到数据了
		{
			LOCK(&sock->cs); //锁一下

			bool bflag = false;
			_ASSERTE(buf == sock->recvobj);

			if(error == 0 && BytesTransfered > 0 )
			{ 
#ifdef LOG_LEVEL1  
				char head[256];
				sprintf(head,"(%d) :接收",sock->s);
				if(isClient)
					strcat(head,"CL");
				Log_Server.WriteHex(buf->buf+buf->buflen,BytesTransfered,head,(int)strlen(head));
#endif

				buf->buflen += BytesTransfered; 
				int nret = 0; 

				if(isClient)
				{	//调用可以重载的虚函数
					//开锁,否则在On系列函数中调用Send(),CloseSock()时候会死锁!
					UNLOCK(&sock->cs);
					nret = CLOnRead(sock,buf->buf,buf->buflen,sock->flag,pAdo);
					LOCK(&sock->cs);
				}
				else if(sock->flag_accept == 1)	
				{
					UNLOCK(&sock->cs);
					nret = OnRead(sock,buf->buf,buf->buflen,pAdo);
					LOCK(&sock->cs);
				}
				else
				{
					sock->flag_close = 1;  //设置允许标志,否则调用Send将会失败
					sock->flag_accept = 1; //设置accept标志
#ifndef ENABLE_KEEPALIVE		//没有启用KeepAlive	
					DeleteAlive(sock);
#endif
#ifdef DEBUG_IOCP
					sock->freeed = 0;
					sock->onclosed = 0;
#endif
					UNLOCK(&sock->cs);
					nret = OnAccept(sock,buf->buf,buf->buflen,pAdo);
					LOCK(&sock->cs);
				}

				_ASSERTE(nret >= 0 && nret <= buf->buflen);
				if(nret < 0 || nret > buf->buflen)
				{
#ifdef LOG_LEVEL2
					Log_Server.Write("指令处理出错啦\n");
					nret = buf->buflen; //强制设置为完全处理
#endif 
				}

#ifdef ENABLE_KEEPALIVE
				sock->timeAlive = GetTickCount(); //设置新的心跳时间
#endif
				buf->buflen -= nret;
				if(nret > 0 && buf->buflen > 0)
					memmove(buf->buf,buf->buf+nret,buf->buflen);

				if(PostRecv(sock,buf) == 0) //重新递交一个接收操作
					bflag = true;
			}

			if(!bflag)	
			{
				DeleteClose(sock); //看看是否存在于延时关闭列表中
				DeleteAlive(sock); //看看是否存在于心跳列表中

				if(sock->s != INVALID_SOCKET) {
					closesocket(sock->s);
					sock->s = INVALID_SOCKET;
				}

				sock->flag_close = 0; //设置关闭标志

				FreeBufferObj(buf);

				if( sock->flag_accept == 1) 
				{
					UNLOCK(&sock->cs);

					if(!isClient)
						OnClose(sock,pAdo); //调用一次OnClose(),告诉上层的程序,不要再去用这个sock了
					else
						CLOnClose(sock,sock->flag,pAdo);

					LOCK(&sock->cs);
#ifdef DEBUG_IOCP
					sock->onclosed = 1; //调试时设置关闭标志,用于检测是否存在逻辑问题
#endif
				}

				sock->recvobj = NULL;
				if(sock->recvobj == NULL && sock->sendobj == NULL) 
				{
					UNLOCK(&sock->cs);
					FreeSocketObj(sock); //释放该客户端对应的sockobj对象
					return;
				}
			}

			UNLOCK(&sock->cs);
		}
		break;
	case OP_WRITE:
		LOCK(&sock->cs);
		{
			_ASSERTE(buf == sock->sendobj);
			bool bflag = false;
			BUFFER_OBJ *tmpobj = sock->sendobj;
			sock->sendobj = sock->sendobj->next;

			if(error == 0 && BytesTransfered > 0) //前一个发送已经完成
			{ 
#ifdef LOG_LEVEL1
				char head[256];
				sprintf(head,"(%d) :发送",sock->s);
				if(isClient)
					strcat(head,"CL");
				Log_Server.WriteHex(buf->buf,BytesTransfered,head,(int)strlen(head));
#endif

				//检查发送队列
				if(sock->sendobj == NULL)
					bflag = true;
				else if(PostSend(sock,sock->sendobj) == 0) 
					bflag = true;				
			}

			FreeBufferObj(tmpobj);

			if(!bflag)
			{
				sock->flag_close = 0; //设置关闭标志
				while(sock->sendobj)
				{
					tmpobj = sock->sendobj;
					sock->sendobj = sock->sendobj->next;
					FreeBufferObj(tmpobj); 
				}

				if(sock->recvobj == NULL && sock->sendobj == NULL)
				{
					UNLOCK(&sock->cs);
					FreeSocketObj(sock); //如果OP_READ时,sock->sendobj!=NULL,那么需要在这里释放客户端的SocketOBJ
					return;
				}
			}
		}

		UNLOCK(&sock->cs);
		break;
	}

}
//
// Function: main
//
// Description:
//      This is the main program. It parses the command line and creates
//      the main socket. For UDP this socket is used to receive datagrams.
//      For TCP the socket is used to accept incoming client connections.
//      Each client TCP connection is handed off to a worker thread which
//      will receive any data on that connection until the connection is
//      closed.
//
int __cdecl main(int argc, char **argv)
{
    WSADATA          wsd;
    THREAD_OBJ      *thread=NULL;
    SOCKET_OBJ      *sockobj=NULL,
                    *newsock=NULL;
    int              index,
                     rc;
    struct addrinfo *res=NULL,
                    *ptr=NULL;

    // Validate the command line
    ValidateArgs(argc, argv);

    // Load Winsock
    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
    {
        fprintf(stderr, "unable to load Winsock!\n");
        return -1;
    }

    printf("Local address: %s; Port: %s; Family: %d\n",
            gBindAddr, gBindPort, gAddressFamily);

    res = ResolveAddress(gBindAddr, gBindPort, gAddressFamily, gSocketType, gProtocol);
    if (res == NULL)
    {
        fprintf(stderr, "ResolveAddress failed to return any addresses!\n");
        return -1;
    }

    thread = GetThreadObj();

    // For each local address returned, create a listening/receiving socket
    ptr = res;
    while (ptr)
    {
        PrintAddress(ptr->ai_addr, ptr->ai_addrlen); printf("\n");

        sockobj = GetSocketObj(INVALID_SOCKET, (gProtocol == IPPROTO_TCP) ? TRUE : FALSE);

        // create the socket
        sockobj->s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (sockobj->s == INVALID_SOCKET)
        {
            fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
            return -1;
        }

        InsertSocketObj(thread, sockobj);

        // bind the socket to a local address and port
        rc = bind(sockobj->s, ptr->ai_addr, ptr->ai_addrlen);
        if (rc == SOCKET_ERROR)
        {
            fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
            return -1;
        }

        if (gProtocol == IPPROTO_TCP)
        {
            rc = listen(sockobj->s, 200);
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
                return -1;
            }

            // Register events on the socket
            rc = WSAEventSelect(
                    sockobj->s,
                    sockobj->event,
                    FD_ACCEPT | FD_CLOSE
                    );
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
                return -1;
            }
        }
        else
        {
            // Register events on the socket
            rc = WSAEventSelect(
                    sockobj->s,
                    sockobj->event,
                    FD_READ | FD_WRITE | FD_CLOSE
                    );
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
                return -1;
            }
        }

        ptr = ptr->ai_next;
    }
    // free the addrinfo structure for the 'bind' address
    freeaddrinfo(res);

    gStartTime = gStartTimeLast = GetTickCount();

    while (1)
    {
        rc = WaitForMultipleObjects(
                thread->SocketCount + 1,
                thread->Handles,
                FALSE,
                5000
                );
        if (rc == WAIT_FAILED)
        {
            fprintf(stderr, "WaitForMultipleObjects failed: %d\n", GetLastError());
            break;
        }
        else if (rc == WAIT_TIMEOUT)
        {
            PrintStatistics();
        }
        else
        {
            index = rc - WAIT_OBJECT_0;

            sockobj = FindSocketObj(thread, index-1);

            if (gProtocol == IPPROTO_TCP)
            {
                SOCKADDR_STORAGE sa;
                WSANETWORKEVENTS ne;
                SOCKET           sc;
                int              salen;

                rc = WSAEnumNetworkEvents(
                        sockobj->s,
                        thread->Handles[index],
                       &ne
                        );
                if (rc == SOCKET_ERROR)
                {
                    fprintf(stderr, "WSAEnumNetworkEvents failed: %d\n", WSAGetLastError());
                    break;
                }

                while (1)
                {
                    sc = INVALID_SOCKET;
                    salen = sizeof(sa);

                    //
                    // For TCP, accept the connection and hand off the client socket
                    // to a worker thread
                    //

                    sc = accept(
                            sockobj->s, 
                            (SOCKADDR *)&sa,
                            &salen
                               );
                    if ((sc == INVALID_SOCKET) && (WSAGetLastError() != WSAEWOULDBLOCK))
                    {
                        fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
                        break;
                    }
                    else if (sc != INVALID_SOCKET)
                    {
                        newsock = GetSocketObj(INVALID_SOCKET, FALSE);

                        // Copy address information
                        memcpy(&newsock->addr, &sa, salen);
                        newsock->addrlen = salen;

                        newsock->s = sc;

                        InterlockedIncrement(&gTotalConnections);
                        InterlockedIncrement(&gCurrentConnections);

                        /*
                           printf("Accepted connection from: ");
                           PrintAddress((SOCKADDR *)&newsock->addr, newsock->addrlen);
                           printf("\n");
                         */

                        // Register for read, write and close on the client socket
                        rc = WSAEventSelect(
                                newsock->s,
                                newsock->event,
                                FD_READ | FD_WRITE | FD_CLOSE
                                           );
                        if (rc == SOCKET_ERROR)
                        {
                            fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
                            break;
                        }

                        AssignToFreeThread(newsock);

                    }
                    else
                    {
                        // Failed with WSAEWOULDBLOCK -- just continue
                        break;
                    }
                }


            }
            else
            {
                // For UDP all we have to do is handle events on the main
                //    threads.
                if (HandleIo(thread, sockobj) == SOCKET_ERROR)
                {
                    RenumberThreadArray(thread);
                }
            }
        }
    }

    WSACleanup();
    return 0;
}
//
// Function: main
//
// Description:
//      This is the main program. It parses the command line and creates
//      the main socket. For UDP this socket is used to receive datagrams.
//      For TCP the socket is used to accept incoming client connections.
//      Each client TCP connection is handed off to a worker thread which
//      will receive any data on that connection until the connection is
//      closed.
//
int __cdecl main(int argc, char **argv)
{
    WSADATA          wsd;
    SOCKET_OBJ      *sockobj=NULL,
                    *sptr=NULL,
                    *tmp=NULL;
    HANDLE           hThread;
    ULONG            lastprint=0;
    MSG              msg;
    int              rc;
    struct addrinfo *res=NULL,
                    *ptr=NULL;

    ValidateArgs(argc, argv);

    InitializeCriticalSection(&gSocketCritSec);

    // Load winsock
    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
    {
        fprintf(stderr, "unable to load Winsock!\n");
        return -1;
    }

    gWorkerWindow = MakeWorkerWindow();

    printf("Local address: %s; Port: %s; Family: %d\n",
            gBindAddr, gBindPort, gAddressFamily);

    res = ResolveAddress(gBindAddr, gBindPort, gAddressFamily, gSocketType, gProtocol);
    if (res == NULL)
    {
        fprintf(stderr, "ResolveAddress failed to return any addresses!\n");
        return -1;
    }

    // For each local address returned, create a listening/receiving socket
    ptr = res;
    while (ptr)
    {
        PrintAddress(ptr->ai_addr, ptr->ai_addrlen); printf("\n");

        sockobj = GetSocketObj(INVALID_SOCKET);

        // create the socket
        sockobj->s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (sockobj->s == INVALID_SOCKET)
        {
            fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
            return -1;
        }


        InsertSocketObj(sockobj);

        // bind the socket to a local address and port
        rc = bind(sockobj->s, ptr->ai_addr, ptr->ai_addrlen);
        if (rc == SOCKET_ERROR)
        {
            fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
            return -1;
        }

        if (gProtocol == IPPROTO_TCP)
        {
            rc = listen(sockobj->s, 200);
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
                return -1;
            }

            // Register for notification
            rc = WSAAsyncSelect(
                    sockobj->s,
                    gWorkerWindow,
                    WM_SOCKET,
                    FD_ACCEPT | FD_CLOSE
                    );
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "WSAAsyncSelect failed: %d\n", WSAGetLastError());
                return -1;
            }
        }
        else
        {
            // Register for notification
            rc = WSAAsyncSelect(
                    sockobj->s,
                    gWorkerWindow,
                    WM_SOCKET,
                    FD_READ | FD_WRITE | FD_CLOSE
                    );
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "WSAAsyncSelect failed: %d\n", WSAGetLastError());
                return -1;
            }
        }

        ptr = ptr->ai_next;
    }
    // free the addrinfo structure for the 'bind' address
    freeaddrinfo(res);

    gStartTime = gStartTimeLast = lastprint = GetTickCount();

    // Start a thread to print statistics
    hThread = CreateThread(NULL, 0, StatisticsThread, NULL, 0, NULL);
    if (hThread == NULL)
    {
        fprintf(stderr, "CreateThread failed: %d\n", WSAGetLastError());
        return -1;
    }
    CloseHandle(hThread);

    while(rc = GetMessage(&msg, NULL, 0, 0))
    {
        if (rc == -1)
        {
            fprintf(stderr, "GetMessage() failed with error %d\n", GetLastError());
            return -1;
        }

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    WSACleanup();

    DeleteCriticalSection(&gSocketCritSec);

    return 0;
}
// 
// Function: WindowProc
//
// Description:
//    This is the window procedure which handles the window messages for
//    our hidden window. It handles all the WM_SOCKET messages and performs
//    the correct actions for each message type (FD_READ, FD_WRITE, etc.).
//
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SOCKET_OBJ  *sockobj=NULL,
                *newsock=NULL;
    int          rc;

    if (uMsg == WM_SOCKET)
    {
        // Check for an error on the socket
        if (WSAGETSELECTERROR(lParam))
        {
            // An error occured on the socket, close it down
            fprintf(stderr, "Socket failed with error %d\n", WSAGETSELECTERROR(lParam));
            closesocket(wParam);
            RemoveSocketObjByHandle(wParam);
        }
        else
        {
            // Find the socket object for this event
            sockobj = FindSocketObj(wParam);
            if (sockobj == NULL)
                return 0;

            switch (WSAGETSELECTEVENT(lParam))
            {
                case FD_ACCEPT:

                    // Get a new object for the client socket
                    newsock = GetSocketObj(INVALID_SOCKET);

                    newsock->s = accept(
                            wParam, 
                            (SOCKADDR *)&newsock->addr, 
                           &newsock->addrlen
                            );
                    if (newsock->s == INVALID_SOCKET)
                    {
                        fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
                        break;
                    }

                    InterlockedIncrement(&gCurrentConnections);

                    // Create a socket information structure to associate with the
                    // socket for processing I/O.
                    InsertSocketObj(newsock);

                    /*
                    printf("Accepted connection from: ");
                    PrintAddress((SOCKADDR *)&newsock->addr, newsock->addrlen);
                    printf("\n");
                    */

                    rc = WSAAsyncSelect(
                            newsock->s, 
                            hwnd, 
                            WM_SOCKET, 
                            FD_READ | FD_WRITE | FD_CLOSE
                            );
                    if (rc == SOCKET_ERROR)
                    {
                        fprintf(stderr, "WSAAsyncSelect failed: %d\n", WSAGetLastError());
                        return -1;
                    }

                    break;
                case FD_READ:
                    rc = ReceivePendingData(sockobj);
                    if (rc == -1)
                    {
                        RemoveSocketObj(sockobj);
                        break;
                    }
                    else if (rc != WSAEWOULDBLOCK)
                    {
                        PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
                    }
                    //
                    // Don't break fall through and attempt to send data
                    //
                case FD_WRITE:
                    //
                    // Send routine automatically tries to send all queued buffers.
                    //
                    rc = SendPendingData(sockobj);
                    if (rc == -1)
                    {
                        RemoveSocketObj(sockobj);
                    }
                    break;
                case FD_CLOSE:
                    sockobj->closing = TRUE;
                    //
                    // Post an FD_READ message to force another receive
                    //    This is to ensure we recv() until 0 is returned.
                    //
                    PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
                    break;
                default:
                    printf("Unknown message received: %d\n", WSAGETSELECTEVENT(lParam));
                    break;
            }
        }
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void main()
{
    // 创建监听套节字,绑定到本地端口,进入监听模式
    int nPort = 4567;
    SOCKET sListen = ::WSASocket(
                         AF_INET, SOCK_STREAM, IPPROTO_TCP, //此三个参数与标准socket相同
                         NULL, //指定下层服务提供者,可以是NULL
                         0,    //保留
                         WSA_FLAG_OVERLAPPED); //指定socket属性,要使用重叠I/O模型,必须指定WSA_FLAG_OVERLAPPED
    //如果使用socket则默认指定WSA_FLAG_OVERLAPPED
    //绑定并监听IP和端口
    SOCKADDR_IN si;
    si.sin_family = AF_INET;
    si.sin_port = ::ntohs(nPort);
    si.sin_addr.S_un.S_addr = INADDR_ANY;
    ::bind(sListen, (sockaddr*)&si, sizeof(si));
    ::listen(sListen, 200);

    // 为监听套节字创建一个SOCKET_OBJ对象 GetSocketObj函数仅仅开辟一个PSOCKET_OBJ内存并将套接字传入,
    PSOCKET_OBJ pListen = GetSocketObj(sListen);

    // 加载扩展函数AcceptEx
    GUID GuidAcceptEx = WSAID_ACCEPTEX;
    DWORD dwBytes;
    //套接字选项和I/O控制命令  此处用来获取AcceptEx函数指针
    WSAIoctl(pListen->s,
             SIO_GET_EXTENSION_FUNCTION_POINTER,
             &GuidAcceptEx,
             sizeof(GuidAcceptEx),
             &pListen->lpfnAcceptEx,
             sizeof(pListen->lpfnAcceptEx),
             &dwBytes,
             NULL,
             NULL);

    g_pfnGetAcceptExSockaddrs = (LPFN_GETACCEPTEXSOCKADDRS)GetExtensionFuncPtr(pListen->s);
    // 创建用来重新建立g_events数组的事件对象
    g_events[0] = ::WSACreateEvent();

    // 在此可以投递多个接受I/O请求  投递5个接受连接请求
    for(int i=0; i<5; i++)
    {
        PostAccept(GetBufferObj(pListen, BUFFER_SIZE));
    }
    ::WSASetEvent(g_events[0]);

    while(TRUE)
    {
        int nIndex =
            ::WSAWaitForMultipleEvents(g_nBufferCount + 1, g_events, FALSE, WSA_INFINITE, FALSE);
        if(nIndex == WSA_WAIT_FAILED)
        {
            printf("WSAWaitForMultipleEvents() failed \n");
            break;
        }
        nIndex = nIndex - WSA_WAIT_EVENT_0;
        for(int i=0; i<=nIndex; i++)
        {
            int nRet = ::WSAWaitForMultipleEvents(1, &g_events[i], TRUE, 0, FALSE);
            if(nRet == WSA_WAIT_TIMEOUT)
                continue;
            else
            {
                ::WSAResetEvent(g_events[i]);
                // 重新建立g_events数组
                if(i == 0)
                {
                    RebuildArray();
                    continue;
                }

                // 处理这个I/O
                PBUFFER_OBJ pBuffer = FindBufferObj(g_events[i]);
                if(pBuffer != NULL)
                {
                    if(!HandleIO(pBuffer))
                        RebuildArray();
                }
            }
        }
    }
}
BOOL HandleIO(PBUFFER_OBJ pBuffer)
{
    PSOCKET_OBJ pSocket = pBuffer->pSocket; // 从BUFFER_OBJ对象中提取SOCKET_OBJ对象指针,为的是方便引用
    pSocket->nOutstandingOps --;

    DWORD dwTrans;   //用于取得实际传输字节的数量
    DWORD dwFlags;   //用于取得完成状态
    // 获取重叠操作结果 true 重叠操作成功  false 套接字上有错误发生
    BOOL bRet = ::WSAGetOverlappedResult(pSocket->s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags);
    if(!bRet)
    {
        // 在此套节字上有错误发生,因此,关闭套节字,移除此缓冲区对象。
        // 如果没有其它抛出的I/O请求了,释放此缓冲区对象,否则,等待此套节字上的其它I/O也完成
        if(pSocket->s != INVALID_SOCKET)
        {
            ::closesocket(pSocket->s);
            pSocket->s = INVALID_SOCKET;
        }

        if(pSocket->nOutstandingOps == 0)
            FreeSocketObj(pSocket);

        FreeBufferObj(pBuffer);
        return FALSE;
    }

    // 没有错误发生,处理已完成的I/O
    switch(pBuffer->nOperation)
    {
    case OP_ACCEPT:	// 接收到一个新的连接,并接收到了对方发来的第一个封包
    {
        // 为新客户创建一个SOCKET_OBJ对象
        PSOCKET_OBJ pClient = GetSocketObj(pBuffer->sAccept);

        // 为收发数据创建一个BUFFER_OBJ对象,这个对象会在套节字出错或者关闭时释放
        PBUFFER_OBJ pSend = GetBufferObj(pClient, BUFFER_SIZE);
        if(pSend == NULL)
        {
            printf(" Too much connections! \n");
            FreeSocketObj(pClient);
            return FALSE;
        }

        SOCKADDR_IN LocalSockAddr;
        SOCKADDR_IN RemoteSockAddr;
        int nLocalLen, nRmoteLen;
        LPSOCKADDR pLocalAddr, pRemoteAddr;
        g_pfnGetAcceptExSockaddrs(
            pBuffer->buff,
            pBuffer->nLen - ((sizeof(sockaddr_in) + 16) * 2),
            sizeof(sockaddr_in) + 16,
            sizeof(sockaddr_in) + 16,
            (SOCKADDR **)&pLocalAddr,
            &nLocalLen,
            (SOCKADDR **)&pRemoteAddr,
            &nRmoteLen);

        memcpy(&LocalSockAddr, pLocalAddr, nLocalLen);
        memcpy(&RemoteSockAddr, pRemoteAddr, nRmoteLen);
        printf("Local Accepted client:%s:%d\n", inet_ntoa(LocalSockAddr.sin_addr), ntohs(LocalSockAddr.sin_port));
        printf("Remote Accepted client:%s:%d\n", inet_ntoa(RemoteSockAddr.sin_addr), ntohs(RemoteSockAddr.sin_port));

        RebuildArray();

        // 将数据复制到发送缓冲区
        pSend->nLen = dwTrans;
        memcpy(pSend->buff, pBuffer->buff, dwTrans);

        // 投递此发送I/O(将数据回显给客户)
        if(!PostSend(pSend))
        {
            // 万一出错的话,释放上面刚申请的两个对象
            FreeSocketObj(pSocket);
            FreeBufferObj(pSend);
            return FALSE;
        }
        // 继续投递接受I/O
        PostAccept(pBuffer);
    }
    break;
    case OP_RECV:	// 接收数据完成
    {
        if(dwTrans > 0)
        {
            // 创建一个缓冲区,以发送数据。这里就使用原来的缓冲区
            PBUFFER_OBJ pSend = pBuffer;
            printf("收到:%s\r\n", pBuffer->buff);
            pSend->nLen = dwTrans;

            // 投递发送I/O(将数据回显给客户)
            PostSend(pSend);
        }
        else	// 套节字关闭
        {

            // 必须先关闭套节字,以便在此套节字上投递的其它I/O也返回
            if(pSocket->s != INVALID_SOCKET)
            {
                ::closesocket(pSocket->s);
                pSocket->s = INVALID_SOCKET;
            }

            if(pSocket->nOutstandingOps == 0)
                FreeSocketObj(pSocket);

            FreeBufferObj(pBuffer);
            return FALSE;
        }
    }
    break;
    case OP_SEND:		// 发送数据完成
    {
        if(dwTrans > 0)
        {
            // 继续使用这个缓冲区投递接收数据的请求
            pBuffer->nLen = BUFFER_SIZE;
            PostRecv(pBuffer);
        }
        else	// 套节字关闭
        {
            // 同样,要先关闭套节字
            if(pSocket->s != INVALID_SOCKET)
            {
                ::closesocket(pSocket->s);
                pSocket->s = INVALID_SOCKET;
            }

            if(pSocket->nOutstandingOps == 0)
                FreeSocketObj(pSocket);

            FreeBufferObj(pBuffer);
            return FALSE;
        }
    }
    break;
    }
    return TRUE;
}