//============================================================================= /// 完成端口线程函数 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; } } } }
/// 完成端口线程函数 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); } }