- attempt to do better lag handling (pause game up to 3 times for lagging clients then disconnect)

This commit is contained in:
SoftCoder 2014-01-02 13:56:37 -08:00
parent 5f1e67ec9b
commit ecdb229bdf
11 changed files with 362 additions and 156 deletions

View File

@ -84,6 +84,8 @@ Game::Game() : ProgramState(NULL) {
avgRenderFps=0;
currentAvgRenderFpsTotal=0;
paused=false;
networkPauseGameForLaggedClientsRequested=false;
networkResumeGameForLaggedClientsRequested=false;
pausedForJoinGame=false;
pausedBeforeJoinGame=false;
pauseRequestSent=false;
@ -254,6 +256,8 @@ void Game::resetMembers() {
currentAvgRenderFpsTotal=0;
tickCount=0;
paused= false;
networkPauseGameForLaggedClientsRequested=false;
networkResumeGameForLaggedClientsRequested=false;
pausedForJoinGame=false;
pausedBeforeJoinGame=false;
resumeRequestSent=false;
@ -1596,6 +1600,11 @@ void Game::init(bool initForPreviewOnly) {
printf("*Note: Monitoring Network CRC NORMAL synchronization...\n");
}
//NetworkRole role = networkManager.getNetworkRole();
if(role == nrServer) {
networkManager.initServerInterfaces(this);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] ==== START GAME ==== getCurrentPixelByteCount() = " MG_SIZE_T_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,renderer.getCurrentPixelByteCount());
if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled) SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,"=============================================\n");
@ -2181,7 +2190,9 @@ void Game::update() {
// Commander
chronoGamePerformanceCounts.start();
if(pendingQuitError == false) commander.signalNetworkUpdate(this);
if(pendingQuitError == false) {
commander.signalNetworkUpdate(this);
}
addPerformanceCount("ProcessNetworkUpdate",chronoGamePerformanceCounts.getMillis());
@ -2244,7 +2255,9 @@ void Game::update() {
}
//else if(role == nrClient) {
else {
if(pendingQuitError == false) commander.signalNetworkUpdate(this);
if(pendingQuitError == false) {
commander.signalNetworkUpdate(this);
}
if(playingStaticVideo == true) {
if(videoPlayer->isPlaying() == false) {
@ -2299,6 +2312,26 @@ void Game::update() {
// START - Handle joining in progress games
if(role == nrServer) {
if(this->networkPauseGameForLaggedClientsRequested == true) {
this->networkPauseGameForLaggedClientsRequested = false;
if(getPaused() == false) {
printf("[CMDR] Pausing game for lagging client(s), current world frame [%d]\n",world.getFrameCount());
commander.tryPauseGame(false,false);
}
}
else if(this->networkResumeGameForLaggedClientsRequested == true) {
this->networkResumeGameForLaggedClientsRequested = false;
if(getPaused() == true) {
printf("[CMDR] Resuming game after Pause for lagging client(s), current world frame [%d]\n",world.getFrameCount());
commander.tryResumeGame(false,false);
}
}
ServerInterface *server = NetworkManager::getInstance().getServerInterface();
if(server->getPauseForInGameConnection() == true) {
@ -5985,11 +6018,11 @@ void Game::setPaused(bool value,bool forceAllowPauseStateChange,bool clearCaches
}
}
//printf("Line: %d setPaused value: %d clearCaches: %d\n",__LINE__,value,clearCaches);
Lang &lang= Lang::getInstance();
if(value == false) {
console.addLine(lang.getString("GameResumed"));
bool wasPausedForJoinGame = pausedForJoinGame;
paused= false;
pausedForJoinGame = false;
pausedBeforeJoinGame = false;
@ -6008,13 +6041,9 @@ void Game::setPaused(bool value,bool forceAllowPauseStateChange,bool clearCaches
}
setupPopupMenus(false);
//!!!
//NetworkManager &networkManager= NetworkManager::getInstance();
if(networkManager.getNetworkRole() == nrClient) {
//ClientInterface *clientInterface = dynamic_cast<ClientInterface *>(networkManager.getClientInterface());
//if(clientInterface != NULL && clientInterface->getResumeInGameJoin() == true) {
if(networkManager.getNetworkRole() == nrClient &&
wasPausedForJoinGame == true) {
initialResumeSpeedLoops = true;
//}
}
commander.setPauseNetworkCommands(false);
@ -6028,7 +6057,6 @@ void Game::setPaused(bool value,bool forceAllowPauseStateChange,bool clearCaches
paused= true;
pausedForJoinGame = joinNetworkGame;
pauseStateChanged = true;
//!!!
if(clearCaches == true) {
//printf("Line: %d Clear Caches for resume in progress game\n",__LINE__);
@ -6273,6 +6301,18 @@ void Game::stopAllVideo() {
}
}
bool Game::clientLagHandler(int slotIndex,bool networkPauseGameForLaggedClients) {
if(networkPauseGameForLaggedClients == true) {
printf("**WARNING** Detected lag from client: %d networkPauseGameForLaggedClients: %d\n",slotIndex,networkPauseGameForLaggedClients);
}
else {
printf("==> Requested Resume Game after Pause for lagging client(s)...\n");
}
this->networkPauseGameForLaggedClientsRequested = networkPauseGameForLaggedClients;
this->networkResumeGameForLaggedClientsRequested = !networkPauseGameForLaggedClients;
return true;
}
void Game::saveGame(){
string file = this->saveGame(GameConstants::saveGameFilePattern);

View File

@ -60,7 +60,7 @@ enum LoadGameItem {
// Main game class
// =====================================================
class Game: public ProgramState, public FileCRCPreCacheThreadCallbackInterface,
public CustomInputCallbackInterface {
public CustomInputCallbackInterface, public ClientLagCallbackInterface {
public:
static const float highlightTime;
@ -215,6 +215,9 @@ private:
std::map<int,FowAlphaCellsLookupItem> teamFowAlphaCellsLookupItem;
std::map<string,int64> gamePerformanceCounts;
bool networkPauseGameForLaggedClientsRequested;
bool networkResumeGameForLaggedClientsRequested;
public:
Game();
Game(Program *program, const GameSettings *gameSettings, bool masterserverMode);
@ -398,6 +401,8 @@ private:
void checkWinnerStandardHeadlessOrObserver();
void checkWinnerStandardPlayer();
std::map<int, int> getTeamsAlive();
virtual bool clientLagHandler(int slotIndex,bool networkPauseGameForLaggedClients);
};
}}//end namespace

View File

@ -39,6 +39,10 @@ namespace Glest{ namespace Game{
const bool debugClientInterfacePerf = false;
const int ClientInterface::messageWaitTimeout = 10000; //10 seconds
const int ClientInterface::waitSleepTime = 10;
const int ClientInterface::maxNetworkCommandListSendTimeWait = 5;
// =====================================================
// class ClientInterfaceThread
// =====================================================
@ -84,6 +88,7 @@ void ClientInterfaceThread::execute() {
if(SystemFlags::VERBOSE_MODE_ENABLED) printf("ClientInterfaceThread::exec Line: %d\n",__LINE__);
time_t clientSimulationLagStartTime = 0;
Chrono chrono;
for(;this->clientInterface != NULL;) {
@ -106,6 +111,18 @@ void ClientInterfaceThread::execute() {
clientInterface != NULL) {
//printf("ClientInterfaceThread::exec Line: %d this->getQuitStatus(): %d\n",__LINE__,this->getQuitStatus());
// START: Test simulating lag for the client
int simulateLag = Config::getInstance().getInt("SimulateClientLag","0");
if(simulateLag > 0) {
if(clientSimulationLagStartTime == 0) {
clientSimulationLagStartTime = time(NULL);
}
if(difftime((long int)time(NULL),clientSimulationLagStartTime) <= Config::getInstance().getInt("SimulateClientLagDurationSeconds","0")) {
sleep(simulateLag);
}
}
// END: Test simulating lag for the client
clientInterface->updateNetworkFrame();
//printf("ClientInterfaceThread::exec Line: %d this->getQuitStatus(): %d\n",__LINE__,this->getQuitStatus());
@ -163,10 +180,6 @@ void ClientInterfaceThread::execute() {
// class ClientInterface
// =====================================================
const int ClientInterface::messageWaitTimeout = 10000; //10 seconds
const int ClientInterface::waitSleepTime = 10;
const int ClientInterface::maxNetworkCommandListSendTimeWait = 4;
ClientInterface::ClientInterface() : GameNetworkInterface() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] constructor for %p\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,this);
@ -443,7 +456,6 @@ void ClientInterface::update() {
}
double lastSendElapsed = difftime((long int)time(NULL),lastNetworkCommandListSendTime);
//printf("#1 Client send currentFrameCount = %d lastSendElapsed = %f\n",currentFrameCount,lastSendElapsed);
// If we are on a frame that should send packets or we have commands
// to send now, send it now.
@ -451,15 +463,14 @@ void ClientInterface::update() {
currentFrameCount % this->gameSettings.getNetworkFramePeriod() == 0) ||
networkMessageCommandList.getCommandCount() > 0) {
//printf("#2 Client send currentFrameCount = %d lastSendElapsed = %f\n",currentFrameCount,lastSendElapsed);
if(lastSentFrameCount < currentFrameCount ||
networkMessageCommandList.getCommandCount() > 0) {
//printf("#3 Client send currentFrameCount = %d lastSentFrameCount = %d\n",currentFrameCount,lastSentFrameCount );
lastSentFrameCount = currentFrameCount;
sendMessage(&networkMessageCommandList);
lastNetworkCommandListSendTime = time(NULL);
lastSendElapsed = difftime((long int)time(NULL),lastNetworkCommandListSendTime);
lastNetworkCommandListSendTime = time(NULL);
lastSendElapsed = 0;
}
}
@ -998,6 +1009,8 @@ void ClientInterface::updateNetworkFrame() {
void ClientInterface::updateFrame(int *checkFrame) {
//printf("#1 ClientInterface::updateFrame\n");
//printf("In updateFrame: %d\n",(checkFrame ? *checkFrame : -1));
if(isConnected() == true && getQuitThread() == false) {
//printf("#2 ClientInterface::updateFrame\n");
@ -1008,30 +1021,22 @@ void ClientInterface::updateFrame(int *checkFrame) {
}
int waitMicroseconds = (checkFrame == NULL ? 10 : 0);
int simulateLag = Config::getInstance().getInt("SimulateClientLag","0");
bool done= false;
while(done == false && getQuitThread() == false) {
//printf("BEFORE Client get networkMessageType\n");
//wait for the next message
NetworkMessageType networkMessageType = waitForMessage(waitMicroseconds);
//printf("AFTER Client got networkMessageType = %d\n",networkMessageType);
// START: Test simulating lag for the client
if(simulateLag > 0) {
if(clientSimulationLagStartTime == 0) {
clientSimulationLagStartTime = time(NULL);
}
if(difftime((long int)time(NULL),clientSimulationLagStartTime) <= Config::getInstance().getInt("SimulateClientLagDurationSeconds","0")) {
sleep(simulateLag);
}
}
// END: Test simulating lag for the client
//check we have an expected message
//NetworkMessageType networkMessageType= getNextMessageType();
//printf("Got Network networkMessageType: %d\n",networkMessageType);
switch(networkMessageType)
{
case nmtCommandList:
@ -1052,6 +1057,8 @@ void ClientInterface::updateFrame(int *checkFrame) {
throw megaglest_runtime_error("error retrieving nmtCommandList returned false!");
}
//printf("Client Thread getFrameCount(): %d getCommandCount(): %d\n",networkMessageCommandList.getFrameCount(),networkMessageCommandList.getCommandCount());
MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
cachedLastPendingFrameCount = networkMessageCommandList.getFrameCount();
//printf("cachedLastPendingFrameCount = %lld\n",(long long int)cachedLastPendingFrameCount);
@ -1095,6 +1102,11 @@ void ClientInterface::updateFrame(int *checkFrame) {
// give all commands
for(int i= 0; i < networkMessageCommandList.getCommandCount(); ++i) {
//pendingCommands.push_back(*networkMessageCommandList.getCommand(i));
//if(networkMessageCommandList.getCommand(i)->getNetworkCommandType() == nctPauseResume) {
//printf("Network cmd type: %d [%d] frame: %d\n",networkMessageCommandList.getCommand(i)->getNetworkCommandType(),nctPauseResume,networkMessageCommandList.getFrameCount());
//}
cachedPendingCommands[networkMessageCommandList.getFrameCount()].push_back(*networkMessageCommandList.getCommand(i));
if(cachedPendingCommandCRCs.find(networkMessageCommandList.getFrameCount()) == cachedPendingCommandCRCs.end()) {
@ -1315,6 +1327,8 @@ bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPending
uint64 frameCountAsUInt64 = frameCount;
timeClientWaitedForLastMessage = 0;
//printf("In getNetworkCommand: %d [%d]\n",frameCount,currentCachedPendingCommandsIndex);
if(getQuit() == false && getQuitThread() == false) {
Chrono chrono;
@ -1333,6 +1347,9 @@ bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPending
if(cachedPendingCommands.find(frameCount) != cachedPendingCommands.end()) {
Commands &frameCmdList = cachedPendingCommands[frameCount];
//printf("In getNetworkCommand frameCmdList.size(): %d\n",(int)frameCmdList.size());
if(frameCmdList.empty() == false) {
for(int index = 0; index < (int)frameCmdList.size(); ++index) {
pendingCommands.push_back(frameCmdList[index]);
@ -1402,6 +1419,8 @@ bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPending
void ClientInterface::updateKeyframe(int frameCount) {
currentFrameCount = frameCount;
//printf("In updateKeyFrame: %d\n",currentFrameCount);
if(getQuit() == false && getQuitThread() == false) {
if(networkCommandListThread == NULL) {
static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);

View File

@ -366,6 +366,7 @@ ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex
this->lastReceiveCommandListTime = 0;
this->receivedNetworkGameStatus = false;
this->autoPauseGameCountForLag = 0;
this->skipLagCheck = false;
this->joinGameInProgress = false;
this->canAcceptConnections = true;
@ -453,6 +454,14 @@ ConnectionSlot::~ConnectionSlot() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__);
}
int ConnectionSlot::getAutoPauseGameCountForLag() {
return autoPauseGameCountForLag;
}
void ConnectionSlot::incrementAutoPauseGameCountForLag() {
autoPauseGameCountForLag++;
}
bool ConnectionSlot::getGameStarted() {
bool result = false;
if(this->slotThreadWorker != NULL) {

View File

@ -162,10 +162,15 @@ private:
bool unPauseForInGameConnection;
bool sentSavedGameInfo;
int autoPauseGameCountForLag;
public:
ConnectionSlot(ServerInterface* serverInterface, int playerIndex);
~ConnectionSlot();
int getAutoPauseGameCountForLag();
void incrementAutoPauseGameCountForLag();
bool getGameStarted();
void setGameStarted(bool value);

View File

@ -40,6 +40,17 @@ namespace Glest{ namespace Game{
// class NetworkInterface
// =====================================================
//
// This interface describes the methods to notify when a client is lagging
//
class ClientLagCallbackInterface {
public:
virtual bool clientLagHandler(int slotIndex, bool networkPauseGameForLaggedClients) = 0;
virtual ~ClientLagCallbackInterface() {}
};
class ChatMsgInfo {
protected:

View File

@ -49,7 +49,7 @@ void NetworkManager::init(NetworkRole networkRole, bool publishEnabled) {
if(networkRole == nrServer) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] this->networkRole = %d, networkRole = %d, gameNetworkInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,this->networkRole,networkRole,gameNetworkInterface);
gameNetworkInterface = new ServerInterface(publishEnabled);
gameNetworkInterface = new ServerInterface(publishEnabled,NULL);
}
else {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] this->networkRole = %d, networkRole = %d, gameNetworkInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,this->networkRole,networkRole,gameNetworkInterface);
@ -61,6 +61,11 @@ void NetworkManager::init(NetworkRole networkRole, bool publishEnabled) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] this->networkRole = %d gameNetworkInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,this->networkRole,gameNetworkInterface);
}
void NetworkManager::initServerInterfaces(ClientLagCallbackInterface *intf) {
ServerInterface *server = getServerInterface();
server->setClientLagCallbackInterface(intf);
}
void NetworkManager::end() {
if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] this->networkRole = %d gameNetworkInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,this->networkRole,gameNetworkInterface);

View File

@ -49,6 +49,8 @@ public:
ServerInterface* getServerInterface(bool throwErrorOnNull=true);
ClientInterface* getClientInterface(bool throwErrorOnNull=true);
NetworkRole getNetworkRole() const { return networkRole; }
void initServerInterfaces(ClientLagCallbackInterface *intf);
};
}}//end namespace

View File

@ -1606,9 +1606,9 @@ bool NetworkMessageCommandList::receive(Socket* socket) {
bool result = false;
if(useOldProtocol == true) {
result = NetworkMessage::receive(socket, &data.header, commandListHeaderSize, true);
//printf("!!! =====> IN Network hdr cmd get frame: %d data.header.commandCount: %u\n",data.header.frameCount,data.header.commandCount);
}
else {
//fromEndianHeader();
buf = new unsigned char[getPackedSizeHeader()+1];
result = NetworkMessage::receive(socket, buf, getPackedSizeHeader(), true);
unpackMessageHeader(buf);
@ -1620,12 +1620,18 @@ bool NetworkMessageCommandList::receive(Socket* socket) {
if(result == true) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got header, messageType = %d, commandCount = %u, frameCount = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,data.header.messageType,data.header.commandCount,data.header.frameCount);
//printf("!!! =====> IN Network cmd get frame: %d data.header.commandCount: %u\n",data.header.frameCount,data.header.commandCount);
if(data.header.commandCount > 0) {
data.commands.resize(data.header.commandCount);
if(useOldProtocol == true) {
int totalMsgSize = (sizeof(NetworkCommand) * data.header.commandCount);
result = NetworkMessage::receive(socket, &data.commands[0], totalMsgSize, true);
// if(data.commands[0].getNetworkCommandType() == nctPauseResume) {
// printf("=====> IN Network cmd type: %d [%d] frame: %d\n",data.commands[0].getNetworkCommandType(),nctPauseResume,data.header.frameCount);
// }
}
else {
//int totalMsgSize = (sizeof(NetworkCommand) * data.header.commandCount);
@ -1676,6 +1682,7 @@ void NetworkMessageCommandList::send(Socket* socket) {
unsigned char *buf = NULL;
//bool result = false;
if(useOldProtocol == true) {
//printf("<===== OUT Network hdr cmd type: frame: %d totalCommand: %u [%u]\n",data.header.frameCount,totalCommand,data.header.commandCount);
NetworkMessage::send(socket, &data.header, commandListHeaderSize);
}
else {
@ -1693,6 +1700,9 @@ void NetworkMessageCommandList::send(Socket* socket) {
//bool result = false;
if(useOldProtocol == true) {
// if(data.commands[0].getNetworkCommandType() == nctPauseResume) {
// printf("<===== OUT Network cmd type: %d [%d] frame: %d totalCommand: %u [%u]\n",data.commands[0].getNetworkCommandType(),nctPauseResume,data.header.frameCount,totalCommand,data.header.commandCount);
// }
NetworkMessage::send(socket, &data.commands[0], (sizeof(NetworkCommand) * totalCommand));
}
else {

View File

@ -39,20 +39,28 @@ using namespace Shared::Map;
namespace Glest { namespace Game {
double maxFrameCountLagAllowed = 25;
double maxClientLagTimeAllowed = 30;
double maxFrameCountLagAllowedEver = 35;
double maxClientLagTimeAllowedEver = 45;
double warnFrameCountLagPercent = 0.65;
double LAG_CHECK_GRACE_PERIOD = 15;
double LAG_CHECK_INTERVAL_PERIOD = 6;
double MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = 2;
const int MAX_SLOT_THREAD_WAIT_TIME = 3;
const int MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS = 30;
double maxFrameCountLagAllowed = 30;
double maxClientLagTimeAllowed = 25;
double maxFrameCountLagAllowedEver = 30;
double maxClientLagTimeAllowedEver = 25;
ServerInterface::ServerInterface(bool publishEnabled) :GameNetworkInterface() {
double warnFrameCountLagPercent = 0.50;
double LAG_CHECK_GRACE_PERIOD = 15;
double LAG_CHECK_INTERVAL_PERIOD = 4;
const int MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = 15000;
const int MAX_CLIENT_PAUSE_FOR_LAG_COUNT = 3;
const int MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS = 1500;
const int MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS = 30;
const int maxNetworkCommandListSendTimeWaitWhenAutoPaused = 4000;
ServerInterface::ServerInterface(bool publishEnabled, ClientLagCallbackInterface *clientLagCallbackInterface) : GameNetworkInterface() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
this->clientLagCallbackInterface = clientLagCallbackInterface;
this->clientsAutoPausedDueToLag = false;
allowInGameConnections = false;
gameLaunched = false;
@ -719,12 +727,16 @@ std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot *connectionS
// END test
//printf("skipNetworkBroadCast [%d] clientLagCount [%f][%f][%f] clientLagTime [%f][%f][%f]\n",skipNetworkBroadCast,clientLagCount,(maxFrameCountLagAllowed * warnFrameCountLagPercent),maxFrameCountLagAllowed,clientLagTime,(maxClientLagTimeAllowed * warnFrameCountLagPercent),maxClientLagTimeAllowed);
// New lag check
if((maxFrameCountLagAllowed > 0 && clientLagCount > maxFrameCountLagAllowed) ||
(maxClientLagTimeAllowed > 0 && clientLagTime > maxClientLagTimeAllowed) ||
(maxFrameCountLagAllowedEver > 0 && clientLagCount > maxFrameCountLagAllowedEver) ||
( maxClientLagTimeAllowedEver > 0 && clientLagTime > maxClientLagTimeAllowedEver)) {
clientLagExceededOrWarned.first = true;
//printf("#1 Client Warned\n");
Lang &lang= Lang::getInstance();
const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
@ -771,7 +783,9 @@ std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot *connectionS
clientLagCount > (maxFrameCountLagAllowed * warnFrameCountLagPercent)) ||
(maxClientLagTimeAllowed > 0 && warnFrameCountLagPercent > 0 &&
clientLagTime > (maxClientLagTimeAllowed * warnFrameCountLagPercent)) ) {
clientLagExceededOrWarned.second = true;
//printf("#2 Client Warned\n");
if(connectionSlot->getLagCountWarning() == false) {
connectionSlot->setLagCountWarning(true);
@ -931,6 +945,108 @@ void ServerInterface::signalClientsToRecieveData(std::map<PLATFORM_SOCKET,bool>
}
}
void ServerInterface::checkForCompletedClientsUsingThreadManager(
std::map<int, bool> &mapSlotSignalledList, std::vector<string>& errorMsgList) {
masterController.waitTillSlavesTrigger(MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS);
masterController.clearSlaves(true);
for (int i = 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i));
ConnectionSlot* connectionSlot = slots[i];
if (connectionSlot != NULL && mapSlotSignalledList[i] == true) {
try {
std::vector<std::string> errorList =
connectionSlot->getThreadErrorList();
// Collect any collected errors from threads
if (errorList.empty() == false) {
for (int iErrIdx = 0; iErrIdx < (int) errorList.size();++iErrIdx) {
string &sErr = errorList[iErrIdx];
if (sErr != "") {
errorMsgList.push_back(sErr);
}
}
connectionSlot->clearThreadErrorList();
}
} catch (const exception &ex) {
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
errorMsgList.push_back(ex.what());
}
}
}
}
void ServerInterface::checkForCompletedClientsUsingLoop(
std::map<int, bool>& mapSlotSignalledList, std::vector<string> &errorMsgList,
std::map<int, ConnectionSlotEvent> &eventList) {
//time_t waitForThreadElapsed = time(NULL);
Chrono waitForThreadElapsed(true);
std::map<int, bool> slotsCompleted;
for (bool threadsDone = false; exitServer == false && threadsDone == false &&
waitForThreadElapsed.getMillis() <= MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS;) {
threadsDone = true;
// Examine all threads for completion of delegation
for (int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
ConnectionSlot *connectionSlot = slots[index];
if (connectionSlot != NULL && connectionSlot->isConnected() == true &&
mapSlotSignalledList[index] == true &&
connectionSlot->getJoinGameInProgress() == false &&
slotsCompleted.find(index) == slotsCompleted.end()) {
try {
std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
// Collect any collected errors from threads
if (errorList.empty() == false) {
for (int iErrIdx = 0; iErrIdx < (int) errorList.size();++iErrIdx) {
string &sErr = errorList[iErrIdx];
if (sErr != "") {
errorMsgList.push_back(sErr);
}
}
connectionSlot->clearThreadErrorList();
}
// Not done waiting for data yet
bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[index]) : true);
if (updateFinished == false) {
threadsDone = false;
break;
}
else {
slotsCompleted[index] = true;
}
}
catch (const exception &ex) {
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
errorMsgList.push_back(ex.what());
}
}
}
}
}
void ServerInterface::setClientLagCallbackInterface(ClientLagCallbackInterface *intf) {
this->clientLagCallbackInterface = intf;
}
bool ServerInterface::getClientsAutoPausedDueToLag() {
return this->clientsAutoPausedDueToLag;
}
void ServerInterface::checkForCompletedClients(std::map<int,bool> & mapSlotSignalledList,
std::vector <string> &errorMsgList,
std::map<int,ConnectionSlotEvent> &eventList) {
@ -939,99 +1055,43 @@ void ServerInterface::checkForCompletedClients(std::map<int,bool> & mapSlotSigna
const bool newThreadManager = Config::getInstance().getBool("EnableNewThreadManager","false");
if(newThreadManager == true) {
//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
//bool slavesCompleted = masterController.waitTillSlavesTrigger(1000 * MAX_SLOT_THREAD_WAIT_TIME);
masterController.waitTillSlavesTrigger(1000 * MAX_SLOT_THREAD_WAIT_TIME);
masterController.clearSlaves(true);
//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i));
ConnectionSlot* connectionSlot = slots[i];
if(connectionSlot != NULL && mapSlotSignalledList[i] == true) {
try {
std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
// Collect any collected errors from threads
if(errorList.empty() == false) {
for(int iErrIdx = 0; iErrIdx < (int)errorList.size(); ++iErrIdx) {
string &sErr = errorList[iErrIdx];
if(sErr != "") {
errorMsgList.push_back(sErr);
}
}
connectionSlot->clearThreadErrorList();
}
}
catch(const exception &ex) {
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
errorMsgList.push_back(ex.what());
}
}
}
//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
checkForCompletedClientsUsingThreadManager(mapSlotSignalledList, errorMsgList);
}
else {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
checkForCompletedClientsUsingLoop(mapSlotSignalledList, errorMsgList, eventList);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
time_t waitForThreadElapsed = time(NULL);
std::map<int,bool> slotsCompleted;
for(bool threadsDone = false;
exitServer == false && threadsDone == false &&
difftime((long int)time(NULL),waitForThreadElapsed) < MAX_SLOT_THREAD_WAIT_TIME;) {
void ServerInterface::checkForAutoPauseForLaggingClient(int index,ConnectionSlot* connectionSlot) {
threadsDone = true;
// Examine all threads for completion of delegation
for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
//printf("===> START slot %d [%p] - About to checkForCompletedClients\n",i,slots[i]);
MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
if (this->clientsAutoPausedDueToLag == false) {
if (connectionSlot != NULL && connectionSlot->isConnected() == true) {
if (connectionSlot->getAutoPauseGameCountForLag()< MAX_CLIENT_PAUSE_FOR_LAG_COUNT) {
if (this->clientLagCallbackInterface != NULL) {
//printf("===> IN slot %d - About to checkForCompletedClients\n",i);
if (this->clientsAutoPausedDueToLagTimer.isStarted() == false ||
this->clientsAutoPausedDueToLagTimer.getMillis() >= MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS) {
ConnectionSlot* connectionSlot = slots[index];
if(connectionSlot != NULL &&
connectionSlot->isConnected() == true &&
mapSlotSignalledList[index] == true &&
connectionSlot->getJoinGameInProgress() == false &&
slotsCompleted.find(index) == slotsCompleted.end()) {
connectionSlot->incrementAutoPauseGameCountForLag();
try {
std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
// Collect any collected errors from threads
if(errorList.empty() == false) {
for(int iErrIdx = 0; iErrIdx < (int)errorList.size(); ++iErrIdx) {
string &sErr = errorList[iErrIdx];
if(sErr != "") {
errorMsgList.push_back(sErr);
}
}
connectionSlot->clearThreadErrorList();
}
// Not done waiting for data yet
bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[index]) : true);
if(updateFinished == false) {
threadsDone = false;
break;
this->clientsAutoPausedDueToLag = true;
if (this->clientLagCallbackInterface->clientLagHandler(index, true) == false) {
connectionSlot->close();
}
else {
slotsCompleted[index] = true;
if (this->clientsAutoPausedDueToLagTimer.isStarted()== true) {
this->clientsAutoPausedDueToLagTimer.reset();
this->clientsAutoPausedDueToLagTimer.stop();
}
this->clientsAutoPausedDueToLagTimer.start();
}
}
catch(const exception &ex) {
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
errorMsgList.push_back(ex.what());
}
}
//printf("===> END slot %d - About to checkForCompletedClients\n",i);
}
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
void ServerInterface::checkForLaggingClients(std::map<int,bool> &mapSlotSignalledList,
@ -1041,14 +1101,16 @@ void ServerInterface::checkForLaggingClients(std::map<int,bool> &mapSlotSignalle
bool lastGlobalLagCheckTimeUpdate = false;
if(gameHasBeenInitiated == true) {
time_t waitForClientsElapsed = time(NULL);
time_t waitForThreadElapsed = time(NULL);
//time_t waitForClientsElapsed = time(NULL);
Chrono waitForClientsElapsed(true);
//time_t waitForThreadElapsed = time(NULL);
Chrono waitForThreadElapsed(true);
std::map<int,bool> slotsCompleted;
std::map<int,bool> slotsWarnedList;
for(bool threadsDone = false;
exitServer == false && threadsDone == false &&
difftime((long int)time(NULL),waitForThreadElapsed) < MAX_SLOT_THREAD_WAIT_TIME;) {
waitForThreadElapsed.getMillis() <= MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS;) {
threadsDone = true;
// Examine all threads for completion of delegation
@ -1100,26 +1162,14 @@ void ServerInterface::checkForLaggingClients(std::map<int,bool> &mapSlotSignalle
// If the client has exceeded lag and the server wants
// to pause while they catch up, re-trigger the
// client reader thread
if((clientLagExceededOrWarned.first == true &&
if((clientLagExceededOrWarned.second == true &&
gameSettings.getNetworkPauseGameForLaggedClients() == true)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, difftime(time(NULL),waitForClientsElapsed) = %.2f, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = %.2f\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,difftime((long int)time(NULL),waitForClientsElapsed),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, waitForClientsElapsed.getMillis() = %d, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,(int)waitForClientsElapsed.getMillis(),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS);
if(difftime((long int)time(NULL),waitForClientsElapsed) < MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE) {
if(connectionSlot != NULL) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second);
checkForAutoPauseForLaggingClient(index, connectionSlot);
bool socketTriggered = false;
PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
if(clientSocket > 0) {
socketTriggered = socketTriggeredList[clientSocket];
}
ConnectionSlotEvent &event = eventList[index];
mapSlotSignalledList[index] = signalClientReceiveCommands(connectionSlot,index,socketTriggered,event);
threadsDone = false;
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second);
}
slotsCompleted[index] = true;
}
else {
slotsCompleted[index] = true;
@ -1163,16 +1213,12 @@ void ServerInterface::checkForLaggingClients(std::map<int,bool> &mapSlotSignalle
// If the client has exceeded lag and the server wants
// to pause while they catch up, re-trigger the
// client reader thread
if((clientLagExceededOrWarned.first == true &&
if((clientLagExceededOrWarned.second == true &&
gameSettings.getNetworkPauseGameForLaggedClients() == true)) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, difftime(time(NULL),waitForClientsElapsed) = %.2f, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = %.2f\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,difftime((long int)time(NULL),waitForClientsElapsed),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE);
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, waitForClientsElapsed.getMillis() = %d, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,(int)waitForClientsElapsed.getMillis(),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS);
if(difftime((long int)time(NULL),waitForClientsElapsed) < MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE) {
if( connectionSlot != NULL && connectionSlot->isConnected() == true) {
threadsDone = false;
}
}
checkForAutoPauseForLaggingClient(index, connectionSlot);
}
}
}
@ -1387,6 +1433,23 @@ void ServerInterface::dispatchPendingUnMarkCellMessages(std::vector <string> &er
}
}
void ServerInterface::checkForAutoResumeForLaggingClients() {
if (this->clientsAutoPausedDueToLag == true &&
this->clientsAutoPausedDueToLagTimer.getMillis() >= MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS) {
//printf("this->clientsAutoPausedDueToLag: %d [%lld]\n",this->clientsAutoPausedDueToLag,(long long)this->clientsAutoPausedDueToLagTimer.getMillis());
if (this->clientLagCallbackInterface != NULL) {
this->clientsAutoPausedDueToLag = false;
this->clientLagCallbackInterface->clientLagHandler(-1, false);
this->clientsAutoPausedDueToLagTimer.reset();
this->clientsAutoPausedDueToLagTimer.stop();
this->clientsAutoPausedDueToLagTimer.start();
}
}
}
void ServerInterface::update() {
//printf("\nServerInterface::update -- A\n");
@ -1401,6 +1464,8 @@ void ServerInterface::update() {
processTextMessageQueue();
processBroadCastMessageQueue();
checkForAutoResumeForLaggingClients();
//printf("\nServerInterface::update -- C\n");
std::map<PLATFORM_SOCKET,bool> socketTriggeredList;
@ -1430,7 +1495,9 @@ void ServerInterface::update() {
std::map<int,bool> mapSlotSignalledList;
// Step #1 tell all connection slot worker threads to receive socket data
if(gameHasBeenInitiated == false) signalClientsToRecieveData(socketTriggeredList, eventList, mapSlotSignalledList);
if(gameHasBeenInitiated == false) {
signalClientsToRecieveData(socketTriggeredList, eventList, mapSlotSignalledList);
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #2\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
//printf("START Server update #2\n");
@ -1574,7 +1641,6 @@ void ServerInterface::update() {
}
}
}
//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
void ServerInterface::updateKeyframe(int frameCount) {
@ -1587,7 +1653,9 @@ void ServerInterface::updateKeyframe(int frameCount) {
}
while(requestedCommands.empty() == false) {
// First add the command to the broadcast list (for all clients)
if(networkMessageCommandList.addCommand(&requestedCommands.back())) {
// Add the command to the local server command list
pendingCommands.push_back(requestedCommands.back());
requestedCommands.pop_back();
}
@ -1608,11 +1676,26 @@ void ServerInterface::updateKeyframe(int frameCount) {
}
//broadcast commands
//printf("START Server send currentFrameCount = %d\n",currentFrameCount);
broadcastMessage(&networkMessageCommandList);
// Only send empty command list broadcasts when not paused
// or auto paused due to lag AND then only every X milliseconds
// where x = maxNetworkCommandListSendTimeWaitWhenAutoPaused
if(this->getClientsAutoPausedDueToLag() == false ||
(this->getClientsAutoPausedDueToLag() == true &&
(networkMessageCommandList.getCommandCount() > 0 ||
lastBroadcastCommandsTimer.isStarted() == false ||
lastBroadcastCommandsTimer.getMillis() >= maxNetworkCommandListSendTimeWaitWhenAutoPaused))) {
//printf("END Server send currentFrameCount = %d\n",currentFrameCount);
if(lastBroadcastCommandsTimer.isStarted() == false) {
lastBroadcastCommandsTimer.start();
}
else {
lastBroadcastCommandsTimer.stop();
lastBroadcastCommandsTimer.reset();
lastBroadcastCommandsTimer.start();
}
broadcastMessage(&networkMessageCommandList);
}
}
catch(const exception &ex) {
SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());

View File

@ -107,10 +107,17 @@ private:
Mutex *gameStatsThreadAccessor;
Stats *gameStats;
bool clientsAutoPausedDueToLag;
Chrono clientsAutoPausedDueToLagTimer;
Chrono lastBroadcastCommandsTimer;
ClientLagCallbackInterface *clientLagCallbackInterface;
public:
ServerInterface(bool publishEnabled);
ServerInterface(bool publishEnabled, ClientLagCallbackInterface *clientLagCallbackInterface);
virtual ~ServerInterface();
bool getClientsAutoPausedDueToLag();
void setClientLagCallbackInterface(ClientLagCallbackInterface *intf);
void setGameStats(Stats *gameStats);
virtual Socket* getSocket(bool mutexLock=true) {return &serverSocket;}
@ -254,6 +261,16 @@ private:
void processTextMessageQueue();
void processBroadCastMessageQueue();
void checkListenerSlots();
void checkForCompletedClientsUsingThreadManager(
std::map<int, bool>& mapSlotSignalledList,
std::vector<string>& errorMsgList);
void checkForCompletedClientsUsingLoop(
std::map<int, bool>& mapSlotSignalledList,
std::vector<string>& errorMsgList,
std::map<int, ConnectionSlotEvent>& eventList);
void checkForAutoPauseForLaggingClient(int index,
ConnectionSlot* connectionSlot);
void checkForAutoResumeForLaggingClients();
protected:
void signalClientsToRecieveData(std::map<PLATFORM_SOCKET,bool> & socketTriggeredList, std::map<int,ConnectionSlotEvent> & eventList, std::map<int,bool> & mapSlotSignalledList);