Exemplo n.º 1
0
//=============================================================================
/// 完成端口线程函数
void CTcpIocpServer::CompletePortFunc(void)
{
	DWORD dwNumberOfBytes = 0;
	CTcpContext *lpTcpContext = NULL;
	CTcpContext* lpNewContext = NULL;

	LPWSAOVERLAPPED lpOverlapped = NULL;
	OVERLAPPEDPLUS *lpOverlapPlus = NULL;

	int32_t nRet = 0;
	uint32_t nFlags = 0;

	struct sockaddr_in* LocalAddr = NULL;
	struct sockaddr_in* RemoteAddr = NULL;
	int32_t LocalAddrLen = 0;
	int32_t RemoteAddrLen = 0;

	while (TRUE)
	{
		lpOverlapped = NULL;
		BOOL bResult = GetQueuedCompletionStatus(m_hIocp, &dwNumberOfBytes, 
			(ULONG *)&lpTcpContext, &lpOverlapped, INFINITE);

		// 如果是退出标志,则退出工作线程
		if(THREAD_EXIT_CODE == (DWORD)lpTcpContext)
		{
			break;
		}

		if (NULL == lpOverlapped)
		{
			continue;
		}

		if(bResult)
		{
			lpOverlapPlus = (OVERLAPPEDPLUS *)lpOverlapped;
			switch(lpOverlapPlus->m_enIOType)
			{
			case IO_WRITE:
				{	
					//注意:在这里不能访问lpTcpContext
					FreeOverlap(lpOverlapPlus);
					break;
				}
			case IO_READ:
				{
					// 接收数据长度为零,释放lpOverlapPlus和lpTcpContext    
					if (0 == dwNumberOfBytes)
					{
						RemoveTcpContext(lpTcpContext);
						FreeOverlap(lpOverlapPlus);
						continue;
					}

					//分析处理数据
					if (!DealRecvData(lpOverlapPlus->m_szBuffer, dwNumberOfBytes, lpTcpContext))
					{
						//释放lpOverlapPlus和lpTcpContext
						RemoveTcpContext(lpTcpContext);
						FreeOverlap(lpOverlapPlus);
						continue;
					}

					nRet = WSARecv(lpTcpContext->m_hSocket, &lpOverlapPlus->m_wsaBuffer,
						1, &dwNumberOfBytes, (DWORD*)&nFlags, (OVERLAPPED*)lpOverlapPlus, NULL);
					if (nRet == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
					{
						//释放lpOverlapPlus和lpTcpContext
						RemoveTcpContext(lpTcpContext);
						FreeOverlap(lpOverlapPlus);						
					}

					break;
				}
			case IO_ACCEPT:
				{
					if(!RemoveAcceptEx(lpOverlapPlus))
					{
						continue;
					}

					//若已投递的ACCEPT数小于100,则补充ACCEPT请求
					if(m_hListenSocket != INVALID_SOCKET && GetAcceptExCount() < 100)
					{
						OVERLAPPEDPLUS* pOverlap = MallocOverlap(IO_ACCEPT);
						if(NULL != pOverlap)
						{
							if(!AddAcceptEx(pOverlap))
							{
								FreeOverlap(pOverlap);
							}
						}
					}

					if (0 == dwNumberOfBytes)
					{
						closesocket(lpOverlapPlus->m_hSocket);
						lpOverlapPlus->m_hSocket = INVALID_SOCKET;
						FreeOverlap(lpOverlapPlus);
						continue;
					}

					//取得对方IP
					m_lpfnGetAcceptExSockAddrs(lpOverlapPlus->m_szBuffer,
						lpOverlapPlus->m_wsaBuffer.len - ((sizeof(SOCKADDR_IN) + 16) * 2),
						sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16,
						(SOCKADDR **)&LocalAddr, &LocalAddrLen,
						(SOCKADDR **)&RemoteAddr, &RemoteAddrLen);

					//申请单句柄内容,然后把socket和完成端口关联起来
					lpNewContext = CreateContext();
					if (!lpNewContext)
					{
						closesocket(lpOverlapPlus->m_hSocket);
						lpOverlapPlus->m_hSocket = INVALID_SOCKET;
						FreeOverlap(lpOverlapPlus);
						continue;
					}

					lpNewContext->m_hSocket = lpOverlapPlus->m_hSocket;
					lpNewContext->m_oSocketAddr.sin_addr.s_addr = RemoteAddr->sin_addr.s_addr;
					lpNewContext->m_oSocketAddr.sin_port = RemoteAddr->sin_port;

					//添加到保存客户端连接的列表里
					AddTcpContext(lpNewContext);

					//将新建立的套接字关联到完成端口
					if (!CreateIoCompletionPort((HANDLE)lpNewContext->m_hSocket,\
						m_hIocp, (DWORD)lpNewContext, 0))
					{
						RemoveTcpContext(lpNewContext);
						FreeOverlap(lpOverlapPlus);							
						continue;
					}

					//分析处理数据
					if (!DealRecvData(lpOverlapPlus->m_szBuffer, dwNumberOfBytes, lpNewContext))
					{
						RemoveTcpContext(lpNewContext);
						FreeOverlap(lpOverlapPlus);
						continue;
					}

					lpOverlapPlus->m_enIOType = IO_READ;	
					nRet = WSARecv(lpNewContext->m_hSocket, 	&lpOverlapPlus->m_wsaBuffer,
						1, &dwNumberOfBytes, (DWORD*)&nFlags, (OVERLAPPED*)lpOverlapPlus, NULL);
					if (nRet == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
					{
						RemoveTcpContext(lpNewContext);
						FreeOverlap(lpOverlapPlus);
					}					
					break;
				}
			}
		}
		else
		{
			lpOverlapPlus = (OVERLAPPEDPLUS *)lpOverlapped;
			
			//注意:lpTcpContext可能无效,不能访问
			//释放lpOverlapPlus和lpTcpContext
			switch(lpOverlapPlus->m_enIOType)
			{				
			case IO_READ:
				RemoveTcpContext(lpTcpContext); //从检查列表中移除
				FreeOverlap(lpOverlapPlus);
				break;
			case IO_WRITE:
				FreeOverlap(lpOverlapPlus);
				break;
			case IO_ACCEPT:
				if(RemoveAcceptEx(lpOverlapPlus))
				{
					closesocket(lpOverlapPlus->m_hSocket);
					lpOverlapPlus->m_hSocket = INVALID_SOCKET;
					FreeOverlap(lpOverlapPlus);
				}
				break;              
			}
		}
	}
}
Exemplo n.º 2
0
/// 完成端口线程函数
void CTcpEpollServer::EpollWaitFunc(void)
{
	int32_t nEventCount = 0;
	struct epoll_event EpollEvent[128];	//epoll事件对象

	while(-1 != m_hEpollHandle)
	{
		nEventCount = epoll_wait(m_hEpollHandle, EpollEvent, 128, 500);
        if (nEventCount == -1)
        {
            continue;
        }

		for (uint32_t nIndex = 0; nIndex < nEventCount; ++nIndex)
		{
		    struct epoll_event* pEpollEvent = &EpollEvent[nIndex];
			CTcpContext* lpContext = (CTcpContext*)pEpollEvent->data.ptr;
			SOCKET hSocket = lpContext->m_hSocket;

			if (hSocket == m_hListenSocket)
			{
				SOCKET hAcceptSocket = INVALID_SOCKET;
				struct sockaddr_in oAddr;
				socklen_t nAddrSize = sizeof(sockaddr_in);

				do
				{
					uint32_t nAddrLen = sizeof(sockaddr_in);
					hAcceptSocket = accept(m_hListenSocket, (sockaddr*)&oAddr, &nAddrSize);
					if(INVALID_SOCKET == hAcceptSocket)
					{
						//当端口是非阻塞时,accept返回-1,并设置errno为EAGAIN,此时应该继续接受连接
						//当端口是非阻塞时,非阻塞套接字上不能立即完成的操作返回,设置errno为EWOULDBLOCK,此时应该继续接受连接
						if (errno != EAGAIN && errno != EWOULDBLOCK)
						{
						}
						break;
					}

					if(!EpollAcceptSocket(hAcceptSocket, oAddr))
					{
						DestroySocket(hAcceptSocket);
					}
				}while(hAcceptSocket != INVALID_SOCKET);
			}
			else
			{
				if (pEpollEvent->events & EPOLLIN)
				{
					int32_t nRecvSize = 0;
					char szRecvBuff[MAX_PACK_BUFFER_SIZE];

					do
					{
						nRecvSize = recv(hSocket, szRecvBuff, MAX_PACK_BUFFER_SIZE, MSG_NOSIGNAL);
						if(nRecvSize > 0)
						{
							DealRecvData(szRecvBuff, nRecvSize, lpContext);
						}
						//接收数据长度为0,说明连接断开了
						else if(nRecvSize == 0)
						{
							// 关闭连接
							RemoveTcpContext(lpContext);
							break;
						}
						else
						{
							//当端口是非阻塞时,recv返回-1,并设置errno为EAGAIN,此时应该是数据读完了,
							//当端口是非阻塞时,非阻塞套接字上不能立即完成的操作返回,设置errno为EWOULDBLOCK,此时应该是数据读完了
							if (errno != EAGAIN && errno != EWOULDBLOCK)
							{
								// 关闭连接
								RemoveTcpContext(lpContext);
							}
						}
					}while(nRecvSize > 0);
				}

				if(pEpollEvent->events & EPOLLOUT)
				{
					m_SendQueue.SendPacket(hSocket);
				}
			}
		}
	}
}
void CTCPClient::Run()
{
	fd_set fdRead;
	int nRet;
	//定义事件等待时间
	TIMEVAL tvTime;
	tvTime.tv_sec = 1;
	tvTime.tv_usec = 0;
	while (TRUE)
	{
		if (m_bIsconnected == FALSE)
		{
			TRACE("连接失败");
				Sleep(500);
				continue;
		}

		SendData();
		//收到退出事件,结束线程
		//if (WaitForSingleObject(m_hExitThreadEvent, 0) == WAIT_OBJECT_0)
		//{
		//	break;
		//}
		//置fdRead事件为空
		FD_ZERO(&fdRead);
		//给客户端Socket设置读事件
		FD_SET(this->m_Socket, &fdRead);
		//调用select函数,判断是否有读事件发生
		nRet = select(10, &fdRead, NULL, NULL, &tvTime);

		if (nRet == SOCKET_ERROR)
		{
			WSAGetLastError();
			//读取文件描述符失败
			TRACE("读取文件描述符失败\n");
			//关闭客户端socket
			closesocket(m_Socket);
			WSACleanup();
			m_bIsconnected = FALSE;
			m_pDataP->m_vectPlc[GetPlcClassIndex()].SetConectedState(FALSE);
			//break;
		}

		if (nRet > 0)
		{
			if (FD_ISSET(m_Socket, &fdRead))
			{
				//检查fdset联系的文件句柄fd是否可读写,当>0表示可读写,则
				//发生读事件
				char cRecvBuf[RECEIVE_BUFF_SIZE];
				int nRecvLen;
				ZeroMemory(cRecvBuf, RECEIVE_BUFF_SIZE);
				TRACE("数据读取事件触发,执行读操作\n");
				//接收数据
				nRecvLen = recv(m_Socket, cRecvBuf, RECEIVE_BUFF_SIZE, 0);
				if (nRecvLen == SOCKET_ERROR)
				{
					int nError = WSAGetLastError();
					//数据接收操作失败
					TRACE("数据接收操作失败\n");
					//关闭客户端socket
					closesocket(m_Socket);
					m_bIsconnected = FALSE;
					m_pDataP->m_vectPlc[GetPlcClassIndex()].SetConectedState(FALSE);
					//break;
				}
				else if (nRecvLen == 0)
				{
					//触发断开连接事件
					TRACE("数据接收等待过程中网络中断\n");
					//关闭客户端socket
					closesocket(m_Socket);
		
					m_bIsconnected = FALSE;
					m_pDataP->m_vectPlc[GetPlcClassIndex()].SetConectedState(FALSE);
					//break;
				}
				else
				{
					//触发数据接收事件采用sendmessage机制将接收的数组发送到父亲窗口
					//SetReadDataPacket(m_strRemoteHost, cRecvBuf);
					DealRecvData(cRecvBuf);
					m_bIsconnected = TRUE;
					m_pDataP->m_vectPlc[GetPlcClassIndex()].SetConectedState(TRUE);
					TRACE("%d 数据接收成功\n",m_pThread->GetThreadID());
				}
			}
		}

		Sleep(200);
	}
	

}