Domanda

Sto scrivendo il codice PHP per essere un client di gioco. Esso utilizza zoccolo; socket_create seguita da socket_connect e poi socket_read. Funziona bene, ma il problema è che il server può inviare un pacchetto in qualsiasi momento, il che significa che le esigenze socket_read da accadendo costantemente in un "ciclo di gioco". Quindi, qualcosa di simile a questo:

<?php 
$reply = ""; 
do { 
     $recv = ""; 
     $recv = socket_read($socket, '1400'); 
     if($recv != "") { 
         $reply .= $recv; 
     } 
} while($recv != ""); 

echo($reply); 
?>

non funziona perché si è bloccato nel ciclo (server non termina la connessione fino a quando gioco è uscire dal client) e le esigenze di codice PHP per gestire la roba pacchetto come si entra.

Quindi PHP non hanno davvero threading. Qual è il modo migliore di gestire questo?

È stato utile?

Soluzione

Fondamentalmente ogni piattaforma software sta andando a confinare contro questo problema. La maggior parte, come hai capito, risolvere con filettatura. Mentre Threading è possibile in PHP. Richiede MAJORHAXXX. Come ad esempio il lancio di un filo di comando php all'interno di php.

E 'davvero non finiscono per essere l'ideale.

Tuttavia, ci sono altri modi per aggirare questo.

Ma è necessario controllare tutti i segni di questa lista prima:

[] - Il mio gioco non ha bisogno di sempre mantenere il controllo del server, come ad esempio per le posizioni del giocatore o movimenti complessi. Tutto ciò al di là di un livello di chat-room di velocità di trasferimento e di aggiornamento dei dati dovrebbe lasciare questa casella deselezionata.

[] - Il mio gioco non ha bisogno di essere detto dal nulla SERVER. E 'perfettamente accettabile per il cliente di chiedere nulla di cui ha bisogno, forse una volta al secondo o meglio una volta al minuto.

[] - Il mio gioco non ha bisogno di mantenere una simulazione costante di un mondo complesso in esecuzione sul server più a lungo di quello necessario per completare una richiesta. Monitoraggio di chat è una cosa, fare fisica e grafica modifiche è un altro.

Se è stata selezionata tutte queste scatole, allora PHP è ancora in gioco! Altrimenti. Non preoccupatevi.

In sostanza, quello che sto dicendo qui è che PHP è grande per i giochi che non sono realmente in multiplayer, e che sono a turni o almeno non molto interattivo. Ma una volta che hai per mantenere le cose senza che il giocatore, PHP cade sulla sua faccia.

VOODOO LIVELLO

Ma se si deve semplicemente fare questo. Ci sono modi per aggirare l'ostacolo.

A - Crea una Daemon PHP che esegue il mondo, il tubo tutto il resto del traffico, o un file di richiesta getter o setter che interagisce con il database. Quindi, è possibile richiedere un ottenendo dello stato del gioco mondo, o impostare un valore che il giocatore eseguito. Tutte le cose che riguardano altri giochi in tutto il mondo possono essere gestiti dal daemon e il gioco stesso si svolge nel database.

B - Utilizzo cron, non un demone. (Pericoloso, ma abbiamo già stabilito come un acquirente di rischio, giusto?)

C - TRY solo un demone e l'ascolto di prese di corrente, quindi l'invio di fili (tramite exec ()) per rispondere. Un po 'come l'idea di AndreKR sopra, solo che non hanno bisogno di sonno. Problema qui è sarà quasi sempre finiscono per cose mancanti o altrimenti ottenere cut off. E il tutto potrebbe esplodere se run del get Daemon due volte in qualche modo ..

Altri suggerimenti

Si può fare, ma sono d'accordo con @Andrey e @ DampeS8N, non è la scelta migliore. Se si è determinata a fare questo, controlla questo libro: Si vuole fare COSA con PHP?

PHP non ha multithreading, così si dovrebbe davvero prendere in considerazione di usare un linguaggio più adatto (come Andrey menzionato nel suo commento).

Se davvero vuole fare questo, è necessario il sonno per qualche tempo, controllare la presa, il sonno di nuovo, controllare la presa ...

Per controllare la presa senza bloccare è necessario utilizzare non-blocking I / O che si può ottenere con il socket_set_nonblock() o socket_recv() che ha una bandiera DONTWAIT.

TCP implementazioni tendono a frammentarsi e si uniscono i messaggi; non si può dire la quantità di dati o come molti frammenti di messaggi di una presa di ricezione tornerà. Hai bisogno di sapere dove un estremità del messaggio e uno nuovo comincia (che può accadere più volte nei dati restituiti da una sola lettura). Alcune soluzioni semplici:

  • Usa un qualche tipo di delimitatore. Terminare ogni messaggio da '\ 0'.
  • Invia la dimensione del messaggio con il messaggio. Iniziare ogni messaggio con "Content-length: 42 \ n". O due byte dimensioni (0x00 0x42)
  • Usa XML. <message> inizia e finisce </message> un messaggio.

parser XML di PHP non piace XMLs incomplete, anche se così la terza opzione è fuori a meno che non si desidera far corrispondere i tag di inizio e fine manualmente. Utilizzare la prima opzione se il protocollo si basa su ASCII, la seconda se si tratta di binario, terzo se è già XML.

Ora, ricordate è possibile ottenere qualsiasi numero di messaggi per pacchetto. Nel caso più complesso, si potrebbe avere la fine di un precedente messaggio seguito da un numero di messaggi completi e l'inizio di un altro messaggio in un singolo pacchetto.

Una soluzione completa sarebbe in queste righe:

while (connected) {
    while (messages in buffer < 1) {
        read from socket;
        add to buffer;
    }

    while (messages in buffer > 0) {
        extract message from buffer;
        process message;
    }
}

... anche se si tratta di un ciclo di messaggi asincrono. Lascio il "se c'è un messaggio disponibile, restituirlo, altrimenti, di attesa per una" implementazione sincrona come esercizio. (Suggerimento:. Avrete bisogno di una classe per costruire e buffer messaggi)

Tutto quello che dovete fare è quello di utilizzare la funzione socket_select():

http://php.net/manual/en/function.socket- select.php

Si metterà il vostro script per il sonno e svegliarlo quando ci sono dati sulla presa da leggere. E 'mooolto più efficiente che il sonno periodico / lettura, gli script cron e tutte le altre soluzioni proposte.

@aib fatto un punto valido. La potenza del server ha inviato un "messaggio gioco" completa divisa in diversi pacchetti. Non aspettatevi di ottenere tutti i dati in un exceution singe di blocco di codice dopo ritorna socket_select().

Invece di scrivere questo ciclo di polling maleodorante blocco, controlla alcune sistema evento basato attorno al modello di reattore come Python ritorto o rubino EventMachine.

Credo che il sapore PHP è chiamata PHP-MIO: http://thethoughtlab.blogspot.com/2007/04/non-blocking-io-with-php-mio.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top