//////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CIOCPServer::OnClientWriting // // DESCRIPTION: Called when client is writing // // INPUTS: // // NOTES: // // MODIFICATIONS: // // Name Date Version Comments // N T ALMOND 06042001 1.0 Origin // Ulf Hedlund 09062001 Changes for OVERLAPPEDPLUS //////////////////////////////////////////////////////////////////////////////// bool CIOCPServer::OnClientWriting(ClientContext* pContext, DWORD dwIoSize) { try { ////////////////////////////////////////////////////////////////////////// static DWORD nLastTick = GetTickCount(); static DWORD nBytes = 0; nBytes += dwIoSize; InterlockedExchangeT pInterlockedExchange=(InterlockedExchangeT)GetProcAddress(LoadLibrary("KERNEL32.dll"),"InterlockedExchange"); if (GetTickCount() - nLastTick >= 1000) { nLastTick = GetTickCount(); pInterlockedExchange((LPLONG)&(m_nSendKbps), nBytes); nBytes = 0; } ////////////////////////////////////////////////////////////////////////// ULONG ulFlags = MSG_PARTIAL; // Finished writing - tidy up pContext->m_WriteBuffer.Delete(dwIoSize); if (pContext->m_WriteBuffer.GetBufferLen() == 0) { pContext->m_WriteBuffer.ClearBuffer(); // Write complete SetEvent(pContext->m_hWriteComplete); return true; // issue new read after this one } else { OVERLAPPEDPLUS * pOverlap = new OVERLAPPEDPLUS(IOWrite); m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_TRANSMIT); pContext->m_wsaOutBuffer.buf = (char*) pContext->m_WriteBuffer.GetBuffer(); pContext->m_wsaOutBuffer.len = pContext->m_WriteBuffer.GetBufferLen(); int nRetVal = WSASend(pContext->m_Socket, &pContext->m_wsaOutBuffer, 1, &pContext->m_wsaOutBuffer.len, ulFlags, &pOverlap->m_ol, NULL); if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING ) { RemoveStaleClient( pContext, FALSE ); } } }catch(...){} return false; // issue new read after this one }
//////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CIOCPServer::OnClientWriting // // DESCRIPTION: Called when client is writing // // INPUTS: // // NOTES: // // MODIFICATIONS: // // Name Date Version Comments // N T ALMOND 06042001 1.0 Origin // Ulf Hedlund 09062001 Changes for OVERLAPPEDPLUS //////////////////////////////////////////////////////////////////////////////// bool CIOCPServer::OnClientWriting(ClientContext* pContext, DWORD dwIoSize) { try { ////////////////////////////////////////////////////////////////////////// static DWORD nLastTick = GetTickCount(); static DWORD nBytes = 0; nBytes += dwIoSize; if (GetTickCount() - nLastTick >= 1000) { nLastTick = GetTickCount(); InterlockedExchange((LPLONG)&(m_nSendKbps), nBytes); nBytes = 0; } ////////////////////////////////////////////////////////////////////////// ULONG ulFlags = MSG_PARTIAL; //send 时候的PostQueuedCompletionStatus 的第二个参数始终为0,所以这里的参数dwIoSize(上层获取的)也是0,所以永远也进不去if。 // Finished writing - tidy up //pContext->m_WriteBuf.Delete(dwIoSize); //if (pContext->m_WriteBuf.GetBufferLen() == 0) //{ // pContext->m_WriteBuf.ClearBuffer(); // // Write complete // SetEvent(pContext->m_hWriteComplete); // return true; // issue new read after this one //} //else { OVERLAPPEDPLUS * pOverlap = new OVERLAPPEDPLUS(IOWrite); m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_TRANSMIT); pContext->m_wsaOutBuffer.buf = (char*) pContext->m_WriteBuf.GetBuffer(); pContext->m_wsaOutBuffer.len = pContext->m_WriteBuf.GetBufferLen(); int nRetVal = WSASend(pContext->m_Socket, &pContext->m_wsaOutBuffer, 1, &pContext->m_wsaOutBuffer.len, ulFlags, &pOverlap->m_ol, NULL); if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING ) { RemoveStaleClient( pContext, FALSE ); } } }catch(...){} return false; // issue new read after this one }
//////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CIOCPServer::RemoveStaleClient // // DESCRIPTION: Client has died on us, close socket and remove context from our list // // INPUTS: // // NOTES: // // MODIFICATIONS: // // Name Date Version Comments // N T ALMOND 06042001 1.0 Origin // //////////////////////////////////////////////////////////////////////////////// void CIOCPServer::RemoveStaleClient(ClientContext* pContext, BOOL bGraceful) { CLock cs(m_cs, "RemoveStaleClient"); TRACE("CIOCPServer::RemoveStaleClient\n"); LINGER lingerStruct; // // If we're supposed to abort the connection, set the linger value // on the socket to 0. // if ( !bGraceful ) { lingerStruct.l_onoff = 1; lingerStruct.l_linger = 0; setsockopt( pContext->m_Socket, SOL_SOCKET, SO_LINGER, (char *)&lingerStruct, sizeof(lingerStruct) ); } // // Free context structures if (m_listContexts.Find(pContext)) { // // Now close the socket handle. This will do an abortive or graceful close, as requested. CancelIo((HANDLE) pContext->m_Socket); closesocket( pContext->m_Socket ); pContext->m_Socket = INVALID_SOCKET; while (!HasOverlappedIoCompleted((LPOVERLAPPED)pContext)) Sleep(0); m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_CLIENT_DISCONNECT); MoveToFreePool(pContext); } }
//////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CIOCPServer::OnClientReading // // DESCRIPTION: Called when client is reading // // INPUTS: // // NOTES: // // MODIFICATIONS: // // Name Date Version Comments // N T ALMOND 06042001 1.0 Origin // Ulf Hedlund 09062001 Changes for OVERLAPPEDPLUS //////////////////////////////////////////////////////////////////////////////// bool CIOCPServer::OnClientReading(ClientContext* pContext, DWORD dwIoSize) { CLock cs(CIOCPServer::m_cs, "OnClientReading"); try { ////////////////////////////////////////////////////////////////////////// static DWORD nLastTick = GetTickCount(); static DWORD nBytes = 0; nBytes += dwIoSize; InterlockedExchangeT pInterlockedExchange=(InterlockedExchangeT)GetProcAddress(LoadLibrary("KERNEL32.dll"),"InterlockedExchange"); if (GetTickCount() - nLastTick >= 1000) { nLastTick = GetTickCount(); pInterlockedExchange((LPLONG)&(m_nRecvKbps), nBytes); nBytes = 0; } ////////////////////////////////////////////////////////////////////////// if (dwIoSize == 0) { RemoveStaleClient(pContext, FALSE); return false; } if (dwIoSize == FLAG_SIZE && memcmp(pContext->m_byInBuffer+8, m_bPacketFlag, FLAG_SIZE) == 0) { // 重新发送 Send(pContext, pContext->m_ResendWriteBuffer.GetBuffer(), pContext->m_ResendWriteBuffer.GetBufferLen()); // 必须再投递一个接收请求 PostRecv(pContext); return true; } // Add the message to out message // Dont forget there could be a partial, 1, 1 or more + partial mesages pContext->m_CompressionBuffer.Write(pContext->m_byInBuffer,dwIoSize); m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_RECEIVE); // Check real Data while (pContext->m_CompressionBuffer.GetBufferLen() > HDR_SIZE) { BYTE bPacketFlag[FLAG_SIZE]; MoveMemory(bPacketFlag, pContext->m_CompressionBuffer.GetBuffer(8), sizeof(bPacketFlag)); if (memcmp(m_bPacketFlag, bPacketFlag, sizeof(m_bPacketFlag)) != 0) throw "bad buffer"; int nSize = 0; MoveMemory(&nSize, pContext->m_CompressionBuffer.GetBuffer(0), sizeof(int)); // Update Process Variable pContext->m_nTransferProgress = pContext->m_CompressionBuffer.GetBufferLen() * 100 / nSize; if (nSize && (pContext->m_CompressionBuffer.GetBufferLen()) >= nSize) { int nUnCompressLength = 0; // Read off header // pContext->m_CompressionBuffer.Read((PBYTE) bPacketFlag, sizeof(bPacketFlag)); pContext->m_CompressionBuffer.Read((PBYTE) &nSize, sizeof(int)); pContext->m_CompressionBuffer.Read((PBYTE) &nUnCompressLength, sizeof(int)); pContext->m_CompressionBuffer.Read((PBYTE) bPacketFlag, sizeof(bPacketFlag)); //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// // SO you would process your data here // // I'm just going to post message so we can see the data int nCompressLength = nSize - HDR_SIZE; PBYTE pData = new BYTE[nCompressLength]; PBYTE pDeCompressionData = new BYTE[nUnCompressLength]; if (pData == NULL || pDeCompressionData == NULL) throw "bad Allocate"; pContext->m_CompressionBuffer.Read(pData, nCompressLength); ////////////////////////////////////////////////////////////////////////// unsigned long destLen = nUnCompressLength; int nRet = uncompress(pDeCompressionData, &destLen, pData, nCompressLength); ////////////////////////////////////////////////////////////////////////// if (nRet == Z_OK) { pContext->m_DeCompressionBuffer.ClearBuffer(); pContext->m_DeCompressionBuffer.Write(pDeCompressionData, destLen); m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_RECEIVE_COMPLETE); } else { throw "bad buffer"; } delete [] pData; delete [] pDeCompressionData; pContext->m_nMsgIn++; } else break; } // Post to WSARecv Next PostRecv(pContext); }catch(...) { pContext->m_CompressionBuffer.ClearBuffer(); // 要求重发,就发送0, 内核自动添加数包标志 Send(pContext, NULL, 0); PostRecv(pContext); } return true; }
//////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CIOCPServer::OnAccept // // DESCRIPTION: Listens for incoming clients // // INPUTS: // // NOTES: // // MODIFICATIONS: // // Name Date Version Comments // N T ALMOND 06042001 1.0 Origin // Ulf Hedlund 09072001 Changes for OVERLAPPEDPLUS //////////////////////////////////////////////////////////////////////////////// void CIOCPServer::OnAccept() { SOCKADDR_IN SockAddr; SOCKET clientSocket; int nRet; int nLen; if (m_bTimeToKill || m_bDisconnectAll) return; // // accept the new socket descriptor // nLen = sizeof(SOCKADDR_IN); clientSocket = accept(m_socListen, (LPSOCKADDR)&SockAddr, &nLen); if (clientSocket == SOCKET_ERROR) { nRet = WSAGetLastError(); if (nRet != WSAEWOULDBLOCK) { // // Just log the error and return // TRACE(_T("accept() error\n"),WSAGetLastError()); return; } } // Create the Client context to be associted with the completion port ClientContext* pContext = AllocateContext(); // AllocateContext fail if (pContext == NULL) return; pContext->m_Socket = clientSocket; // Fix up In Buffer pContext->m_wsaInBuffer.buf = (char*)pContext->m_byInBuffer; pContext->m_wsaInBuffer.len = sizeof(pContext->m_byInBuffer); // Associate the new socket with a completion port. if (!AssociateSocketWithCompletionPort(clientSocket, m_hCompletionPort, (DWORD) pContext)) { delete pContext; pContext = NULL; closesocket( clientSocket ); closesocket( m_socListen ); return; } // 关闭nagle算法,以免影响性能,因为控制时控制端要发送很多数据量很小的数据包,要求马上发送 // 暂不关闭,实验得知能网络整体性能有很大影响 const char chOpt = 1; // int nErr = setsockopt(pContext->m_Socket, IPPROTO_TCP, TCP_NODELAY, &chOpt, sizeof(char)); // if (nErr == -1) // { // TRACE(_T("setsockopt() error\n"),WSAGetLastError()); // return; // } // Set KeepAlive 开启保活机制 if (setsockopt(pContext->m_Socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&chOpt, sizeof(chOpt)) != 0) { TRACE(_T("setsockopt() error\n"), WSAGetLastError()); } // 设置超时详细信息 tcp_keepalive klive; klive.onoff = 1; // 启用保活 klive.keepalivetime = m_nKeepLiveTime; klive.keepaliveinterval = 1000 * 10; // 重试间隔为10秒 Resend if No-Reply WSAIoctl ( pContext->m_Socket, SIO_KEEPALIVE_VALS, &klive, sizeof(tcp_keepalive), NULL, 0, (unsigned long *)&chOpt, 0, NULL ); CLock cs(m_cs, "OnAccept" ); // Hold a reference to the context m_listContexts.AddTail(pContext); // Trigger first IO Completion Request // Otherwise the Worker thread will remain blocked waiting for GetQueuedCompletionStatus... // The first message that gets queued up is ClientIoInitializing - see ThreadPoolFunc and // IO_MESSAGE_HANDLER OVERLAPPEDPLUS *pOverlap = new OVERLAPPEDPLUS(IOInitialize); PostQueuedCompletionStatusT pPostQueuedCompletionStatus=(PostQueuedCompletionStatusT)GetProcAddress(LoadLibrary("KERNEL32.dll"),"PostQueuedCompletionStatus"); BOOL bSuccess = pPostQueuedCompletionStatus(m_hCompletionPort, 0, (DWORD) pContext, &pOverlap->m_ol); if ( (!bSuccess && GetLastError( ) != ERROR_IO_PENDING)) { RemoveStaleClient(pContext,TRUE); return; } m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_CLIENT_CONNECT); // Post to WSARecv Next PostRecv(pContext); }