void NetworkApp::ReceiverMainLoopIteration() { server->Process(); NetworkServer::ConnectionMap connections = server->GetConnections(); Ptr(MessageConnection) clientConnection = (connections.size() > 0) ? server->GetConnections().begin()->second : Ptr(MessageConnection)(); if (!clientConnection) { QApplication::exit(); return; } if (clientConnection->IsReadOpen()) { if (statsPrintTimer.Test()) { const tick_t sendFinishTick = Clock::Tick(); double timespan = (float)Clock::TimespanToSecondsD(transferStartTick, sendFinishTick); LOG(LogUser, "Have received %d fragments (+%d out-of-order) (%.2f%%). Elapsed: %.2f seconds. Bytes received: %d. Transfer rate: %s/sec.", nextFragment, fragments.size(), (nextFragment + fragments.size()) * 100.f / totalFragments, (float)timespan, bytesReceived, FormatBytes((bytesReceived/timespan)).c_str()); clientConnection->DumpStatus(); statsPrintTimer.StartMSecs((float)printIntervalMSecs); } QTimer::singleShot(10, this, SLOT(ReceiverMainLoopIteration())); } else { if (nextFragment == totalFragments) { LOG(LogUser, "Finished receiving all fragments. File '%s' saved to disk, size: %d bytes. Closing connection.", filename.c_str(), bytesReceived); } else { clientConnection->DumpStatus(); LOG(LogUser, "Error: Sender specified the file '%s' to contain %d fragments, but the connection was closed after " "receiving %d fragments. Received a partial file of %d bytes.", filename.c_str(), totalFragments, nextFragment, bytesReceived); } clientConnection->Close(15000); QApplication::quit(); } }
void KristalliProtocolModule::Update(f64 frametime) { // Update method for multiconnection. if (!serverConnection_map_.isEmpty()) connectionArrayUpdate(); // Pulls all new inbound network messages and calls the message handler we've registered // for each of them. if (serverConnection) serverConnection->Process(); // Note: Calling the above serverConnection->Process() may set serverConnection to null if the connection gets disconnected. // Therefore, in the code below, we cannot assume serverConnection is non-null, and must check it again. // Our client->server connection is never kept half-open. // That is, at the moment the server write-closes the connection, we also write-close the connection. // Check here if the server has write-closed, and also write-close our end if so. if (serverConnection && !serverConnection->IsReadOpen() && serverConnection->IsWriteOpen()) serverConnection->Disconnect(0); // Process server incoming connections & messages if server up if (server) { server->Process(); // In Tundra, we *never* keep half-open server->client connections alive. // (the usual case would be to wait for a file transfer to complete, but Tundra messaging mechanism doesn't use that). // So, bidirectionally close all half-open connections. NetworkServer::ConnectionMap connections = server->GetConnections(); for(NetworkServer::ConnectionMap::iterator iter = connections.begin(); iter != connections.end(); ++iter) if (!iter->second->IsReadOpen() && iter->second->IsWriteOpen()) iter->second->Disconnect(0); } if ((!serverConnection || serverConnection->GetConnectionState() == ConnectionClosed || serverConnection->GetConnectionState() == ConnectionPending) && serverIp.length() != 0) { const int cReconnectTimeout = 5 * 1000.f; if (reconnectTimer.Test()) { if (reconnectAttempts) { PerformConnection(); --reconnectAttempts; } else { LogInfo("Failed to connect to " + serverIp + ":" + ToString(serverPort)); // If connection fails we just ignore it. Client has no use for information if initial connection failed. //framework_->GetEventManager()->SendEvent(networkEventCategory, Events::CONNECTION_FAILED, 0); reconnectTimer.Stop(); serverIp = ""; } } else if (!reconnectTimer.Enabled()) reconnectTimer.StartMSecs(cReconnectTimeout); } // If connection was made, enable a larger number of reconnection attempts in case it gets lost if (serverConnection && serverConnection->GetConnectionState() == ConnectionOK) { // save succesfully established connection to messageconnection array with all connection properties. for (unsigned short connection = 0;; connection++) { if (!serverConnection_map_.contains(connection)) { // Associative QMap stores all items sorted by Key. If array has one item terminated, // we fill it with next succesfull connection. Same is done in client. serverConnection_map_.insert(connection, serverConnection); serverIp_list_.insert(connection,serverIp); serverPort_list_.insert(connection,serverPort); serverTransport_list_.insert(connection, serverTransport); reconnectAttempts_list_.insert(connection, cReconnectAttempts); reconnectTimer.Reset(); reconnectTimer_list_.insert(connection,reconnectTimer); serverConnection = 0; serverIp = ""; serverPort = 0; break; } } } RESETPROFILER; }
void KristalliProtocolModule::Update(f64 /*frametime*/) { // Pulls all new inbound network messages and calls the message handler we've registered // for each of them. if (serverConnection) { PROFILE(KristalliProtocolModule_kNet_client_Process); serverConnection->Process(); } // Note: Calling the above serverConnection->Process() may set serverConnection to null if the connection gets disconnected. // Therefore, in the code below, we cannot assume serverConnection is non-null, and must check it again. // Our client->server connection is never kept half-open. // That is, at the moment the server write-closes the connection, we also write-close the connection. // Check here if the server has write-closed, and also write-close our end if so. if (serverConnection && !serverConnection->IsReadOpen() && serverConnection->IsWriteOpen()) serverConnection->Disconnect(0); // Process server incoming connections & messages if server up if (server) { PROFILE(KristalliProtocolModule_kNet_server_Process); server->Process(); // In Tundra, we *never* keep half-open server->client connections alive. // (the usual case would be to wait for a file transfer to complete, but Tundra messaging mechanism doesn't use that). // So, bidirectionally close all half-open connections. NetworkServer::ConnectionMap connections = server->GetConnections(); for(NetworkServer::ConnectionMap::iterator iter = connections.begin(); iter != connections.end(); ++iter) if (!iter->second->IsReadOpen() && iter->second->IsWriteOpen()) iter->second->Disconnect(0); } if ((!serverConnection || serverConnection->GetConnectionState() == ConnectionClosed || serverConnection->GetConnectionState() == ConnectionPending) && serverIp.length() != 0) { const int cReconnectTimeout = 5 * 1000.f; if (reconnectTimer.Test()) { if (reconnectAttempts) { PerformConnection(); --reconnectAttempts; } else { ::LogInfo(QString("Failed to connect to %1:%2").arg(serverIp.c_str()).arg(serverPort)); emit ConnectionAttemptFailed(); reconnectTimer.Stop(); serverIp = ""; } } else if (!reconnectTimer.Enabled()) reconnectTimer.StartMSecs(cReconnectTimeout); } // If connection was made, enable a larger number of reconnection attempts in case it gets lost if (serverConnection && serverConnection->GetConnectionState() == ConnectionOK) reconnectAttempts = cReconnectAttempts; }