/** * Hauptschleife. * * @author FloSoft */ void LobbyClient::Run(void) { if(state == CS_STOPPED) return; SocketSet set; // erstmal auf Daten überprüfen set.Clear(); // zum set hinzufügen set.Add(socket); if(set.Select(0, 0) > 0) { // nachricht empfangen if(!recv_queue.recv(socket)) { LOG.lprintf("Receiving Message from server failed\n"); ServerLost(); return; } } // nun auf Fehler prüfen set.Clear(); // zum set hinzufügen set.Add(socket); // auf fehler prüfen if(set.Select(0, 2) > 0) { if(set.InSet(socket)) { // Server ist weg LOG.lprintf("Error on socket to server\n"); ServerLost(); return; } } // maximal 10 Pakete verschicken if(!send_queue.send(socket, 10)) { ServerLost(); return; } // recv-queue abarbeiten while(recv_queue.count() > 0) { recv_queue.front()->run(this, 0xFFFFFFFF); recv_queue.pop(); } }
/** * * * @author FloSoft */ Message* Message::recv(Socket& sock, int& error, bool wait, Message * (*createfunction)(unsigned short)) { error = -1; unser_time_t time = TIME.CurrentTick(); unser_time_t timeout = time; unsigned int received; SocketSet set; while(true) { // Warten wir schon 5s auf Antwort? if(time - timeout > 15000) wait = false; time = TIME.CurrentTick(); // SocketSet "saubermachen" set.Clear(); // Socket hinzufgen set.Add(sock); // liegen Daten an? int retval = set.Select(0, 0); if(retval <= 0) { if(wait) continue; if(retval != -1) error = 0; return NULL; } // liegen diese Daten an unserem Socket, bzw wieviele Bytes liegen an? if(!set.InSet(sock) || sock.BytesWaiting(&received) != 0) { if(wait) continue; error = 1; return NULL; } // socket ist geschlossen worden if(received == 0) return NULL; // haben wir schon eine vollständige nachricht? (kleinste nachricht: 6 bytes) if(received < 6) { if(wait) continue; error = 2; return NULL; } break; } int read = -1; char block[6]; unsigned short* id = (unsigned short*)&block[0]; unsigned int* length = (unsigned int*)&block[2]; // block empfangen read = sock.Recv(block, 6, false); if(read != 6) { LOG.write("recv: block: only got %d bytes instead of %d, waiting for next try\n", read, 6); if(read != -1) error = 3; return NULL; } read = sock.BytesWaiting(); static unsigned int blocktimeout = 0; if(read < (signed)((*length) + 6) ) { ++blocktimeout; LOG.write("recv: block-waiting: not enough input (%d/%d) for message (0x%04X), waiting for next try\n", read, (*length) + 6, *id); if(blocktimeout < 120 && read != -1) error = 4; return NULL; } blocktimeout = 0; // Block nochmals abrufen (um ihn aus dem Cache zu entfernen) read = sock.Recv(block, 6); if(read != 6) { LOG.lprintf("recv: id,length: only got %d bytes instead of %d\n", read, 2); return NULL; } Message* msg = createfunction(*id); if(!msg) return NULL; // Daten abrufen msg->recv(sock, *length); return msg; }
/** * verarbeitet alle Nachrichten der Clients. * * @author FloSoft */ bool LobbyServer::ProcessMessages() { SocketSet set; // In einem SocketSet alle Clients hinzufügen und gucken, ob etwas empfangen wurde for(LobbyPlayerMapIterator it = players.begin(); it != players.end(); ++it) { LobbyPlayer& p = it->second; if(!p.isFree()) p.addToSet(set); } if(set.Select(0, 0) > 0) { for(LobbyPlayerMapIterator it = players.begin(); it != players.end(); ++it) { LobbyPlayer& p = it->second; if(p.inSet(set) && !p.Receive()) Disconnect(p); } } set.Clear(); // In einem SocketSet alle Clients hinzufügen und gucken, ob fehler aufgetreten sind for(LobbyPlayerMapIterator it = players.begin(); it != players.end(); ++it) { LobbyPlayer& p = it->second; if(!p.isFree()) p.addToSet(set); } if(set.Select(0, 2) > 0) { LOG.write("Error on Sockets\n"); for(LobbyPlayerMapIterator it = players.begin(); it != players.end(); ++it) { LobbyPlayer& p = it->second; if( p.inSet(set) ) { LOG.write("Player %d: Connection lost\n") % p.getId(); Disconnect(p); } } } // Nachrichten-Queues der Spieler abschicken (max 10 Nachrichten pro Spieler pro Runde) for(LobbyPlayerMapIterator it = players.begin(); it != players.end(); ++it) { LobbyPlayer& p = it->second; if(!p.Send()) Disconnect(p); else p.Run(this); } return true; }