Ejemplo n.º 1
0
void NetAcceptor::Accepts()
{
    _pendingAccepts.resize(NETWORK_DEFAULT_OVERLAPPED_COUNT, nullptr);

    for (int i = 0; i < NETWORK_DEFAULT_OVERLAPPED_COUNT; ++i)
    {
        _pendingAccepts[i] = new AcceptBuffer;
        PostAccept(_pendingAccepts[i]);
    }
}
Ejemplo n.º 2
0
///函数:绑定套接字,并投递 accept 请求。
void 
EasyIocp::InitListenSocket()
{
	//创建listen socket 并bind和listen,然后投递accept请求
	SOCKET listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	if(listenSock == INVALID_SOCKET) {
		ErrorSockMessage("EasyIocp::InitListenSocket: create listen socket failed.");
		assert(FALSE);
	}

	//将listen socket绑定到completion port
	compListen_.SetSocket(listenSock);
	if( !CreateIoCompletionPort((HANDLE)(listenSock), hCompPort_, (ULONG_PTR)&compListen_, 0) ) {
		ErrorSysMessage("EasyIocp::InitListenSocket: associate listen socket failed.");
		assert(FALSE);
	}

	if( bind(listenSock, (sockaddr*)&bindAddr_, sizeof(bindAddr_)) != 0 ) {
		ErrorSockMessage("EasyIocp::InitListenSocket: bind failed.");
		assert(FALSE);
	}
	print("EasyIocp::InitListenSocket: bind to %s:%d.", inet_ntoa(bindAddr_.sin_addr), ntohs(bindAddr_.sin_port));

	if( listen(listenSock, EASYIOCP_LISTEN_NUM) != 0 ) {
		ErrorSockMessage("EasyIocp::InitListenSocket: listen failed.");
		assert(FALSE);
	}
	print("EasyIocp::InitListenSocket: listening.");

	//开始投递accept请求
	GUID guidAcceptEx = WSAID_ACCEPTEX;  
	GUID guidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;

	if( !GetExtendSockFunc(listenSock, &guidAcceptEx, sizeof(guidAcceptEx), &funcAcceptEx_, sizeof(funcAcceptEx_)) ) {
		ErrorSockMessage("EasyIocp::InitListenSocket: get AcceptEx failed.");
		assert(FALSE);
	}
	if( !GetExtendSockFunc(listenSock, &guidGetAcceptExSockAddrs, sizeof(guidGetAcceptExSockAddrs), 
		&funcGetAcceptExSockAddrs_, sizeof(funcGetAcceptExSockAddrs_)) ) {
		ErrorSockMessage("EasyIocp::InitListenSocket: get funcGetAcceptExSockkAddrs_ failed.");
		assert(FALSE);
	}

	for(int i = 0; i < EASYIOCP_ACCEPT_NUM; ++i) {
		PostAccept(&compListen_, i);
	}
	print("EasyIocp::InitListenSocket: post %d recv.", EASYIOCP_ACCEPT_NUM);

	return;
}
Ejemplo n.º 3
0
void 
EasyIocp::DoAccept(CompListenKey *listenKey, OVERLAPPED *ov,  DWORD transBytes)
{
	assert(listenKey != NULL);

	int index = listenKey->GetIndex(ov);
	if(index == -1) {
		print("EasyIocp::DoAccept: no index.");
		return;
	}

	//获取地址
	sockaddr_in *localAddr, *remoteAddr;
	int locLen = sizeof(sockaddr_in), remoteLen = sizeof(sockaddr_in),
		inLocLen = sizeof(sockaddr_in) + 16, inRemoteLen = sizeof(sockaddr_in) + 16;
	EasyIocpBuffer *iocpBuffer = listenKey->GetOneBuffer(index);
	if(!iocpBuffer) {
		print("EasyIocp::DoAccept: invalid buffer, index is %d.", index);
		return;
	}
	iocpBuffer->AddTransBytes(transBytes);
	WSABUF *pBuf = iocpBuffer->GetWSABuf();

	funcGetAcceptExSockAddrs_(pBuf->buf, pBuf->len - inLocLen - inRemoteLen,
		inLocLen, inRemoteLen, (sockaddr**)&localAddr, &locLen, (sockaddr**)&remoteAddr, &remoteLen);
	print("EasyIocp::DoAccept: new client from %s:%d on %s:%d.",
		inet_ntoa(remoteAddr->sin_addr), ntohs(remoteAddr->sin_port),
		inet_ntoa(localAddr->sin_addr), ntohs(localAddr->sin_port));

	if(transBytes == 0) {	//未接收到数据
		DoAcceptWithoutData(listenKey, index, localAddr, remoteAddr);
	}else {		//接收到数据
		DoAcceptWithData(listenKey, index, iocpBuffer, localAddr, remoteAddr);
	}

	//再次投递Accept
	PostAccept(listenKey, index);
}
Ejemplo n.º 4
0
void NetAcceptor::OnAccept(std::weak_ptr<NetConnection> clientObj, NetCompletionOP* bufObj)
{
    auto con = clientObj.lock();
    if (!con.get())
        return;

    // Associate the new connection to our completion port
    HANDLE hrc = CreateIoCompletionPort(
        (HANDLE)bufObj->client,
        _comPort,
        (ULONG_PTR)con.get(),
        0);
    if (hrc == NULL)
    {
        DebugPrint("OnAccept failed: %s", SocketGetLastErrorString().c_str());
        return;
    }

    con->OnConnected();

    // Re-post the AcceptEx
    AcceptBuffer* acceptObj = reinterpret_cast<AcceptBuffer*>(bufObj);
    PostAccept(acceptObj);
}
int MightyTCPCompletionPortServer::acceptSocketObject()
{
	int i=0;
	for(i=0; i<5; i++)
	{
		PCompletionPort_BufObj pUseBuf=AllocateBuffer(m_pListenObj,4096);
		InsertPendingAccept(pUseBuf);
		PostAccept(pUseBuf);
	}
	// 构建事件对象数组,以便在上面调用WSAWaitForMultipleEvents函数
	HANDLE hWaitEvents[2 + MAX_THREAD];
	int nEventCount = 0;
	hWaitEvents[nEventCount ++] =m_hAcceptEvent;
	hWaitEvents[nEventCount ++] =m_hRepostEvent;

	// 创建指定数量的工作线程在完成端口上处理I/O
	for(i=0; i<MAX_THREAD; i++)
	{
		HandleIOCompletionPortServer * pIOThread=new HandleIOCompletionPortServer();
		pIOThread->start(this);
		pIOThread->setExecuteSignal();
		m_tdPoolIndex++;
		hWaitEvents[nEventCount ++] =pIOThread->GetThreadHandle();
	}

	// 下面进入无限循环,处理事件对象数组中的事件
	while(TRUE)
	{
		int nIndex = ::WSAWaitForMultipleEvents(nEventCount, hWaitEvents, FALSE, 60*1000, FALSE);

		// 首先检查是否要停止服务
		if((m_exitNotify==1) || (nIndex == WSA_WAIT_FAILED))
		{
			// 关闭所有连接
			//CloseAllConnections();
			::Sleep(0);		// 给I/O工作线程一个执行的机会
			// 关闭监听套节字
			::closesocket(m_ListenSock);
			m_ListenSock= INVALID_SOCKET;
			::Sleep(0);		// 给I/O工作线程一个执行的机会

			// 通知所有I/O处理线程退出
			for(int i=2; i<MAX_THREAD + 2; i++)
			{	
				::PostQueuedCompletionStatus(m_hCompletionPort, -1, 0, NULL);
			}

			// 等待I/O处理线程退出
			/*::WaitForMultipleObjects(MAX_THREAD, &hWaitEvents[2], TRUE, 5*1000);

			for(i=2; i<MAX_THREAD + 2; i++)
			{	
				::CloseHandle(hWaitEvents[i]);
			}*/
			unsigned long leftIndex,RightIndex;
			RightIndex=m_pThreadPool.size();
			for (leftIndex=0;leftIndex<RightIndex;leftIndex++)
			{
				delete ((HandleIOCompletionPortServer *)m_pThreadPool[leftIndex]);
				Sleep(10);
			}
				

			::CloseHandle(m_hCompletionPort);


			::ExitThread(0);
		}	

		//定时检查所有未返回的AcceptEx I/O的连接建立了多长时间
		if(nIndex == WSA_WAIT_TIMEOUT)
		{
			CheckPostAcceptTimeOut();
		}
		else
		{
			nIndex = nIndex - WAIT_OBJECT_0;
			WSANETWORKEVENTS ne;
			int nLimit=0;
			if(nIndex == 0)
			{
				::WSAEnumNetworkEvents(m_ListenSock,hWaitEvents[nIndex], &ne);
				if(ne.lNetworkEvents & FD_ACCEPT)
				{
					nLimit = 50;  // 增加的个数,这里设为50个
				}
			}
			else if(nIndex == 1)
			{
				nLimit = InterlockedExchange(&m_nRepostCount, 0);
			}
			else if(nIndex > 1)		// I/O服务线程退出,说明有错误发生,关闭服务器
			{
				m_exitNotify=1;
				continue;
			}

			// 投递nLimit个AcceptEx I/O请求
			int i = 0;
			while(i++<nLimit)
			{
				PCompletionPort_BufObj pBeforeHandBuf=AllocateBuffer(m_pListenObj,4096);
				if (pBeforeHandBuf!=NULL)
				{
					InsertPendingAccept(pBeforeHandBuf);
					PostAccept(pBeforeHandBuf);
				}

			}
		}
	}
	return 0;
}
Ejemplo n.º 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;
}
Ejemplo n.º 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;
	}

}
Ejemplo n.º 8
0
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();
                }
            }
        }
    }
}
Ejemplo n.º 9
0
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;
}