socket_read question, probleme

dorian
Invité n'ayant pas de compte PHPfrance

06 déc. 2012, 00:50

Bonjour,

Je travaille sur un projet perso, et j'ai un souci au niveau de la gestion de socket en multi client.

d'aprés php.net, il est possible de passer a la fonction socket_read(), soit une socket créé par socket_create soit accepté par socket_accept.

Si je comprend bien, celle renvoyé par socket_create est la socket serveur, et celles renvoyés par socket_accept sont les socket client, est ça ?

Si oui sa m'arrangerai de mettre ma socket serveur en parametre de socket_read pour attendre que un client parmi plusieurs ecrive dans la socket.

Plus clairement, j'accepte 4 clients et attende que l'un d'entre eux ecrive, mais je ne peux pas mettre un une socket client precise dans socket_read vu que je sais pas qui va ecrire ...

Et quand je met la socket serveur sa plante...

Code : Tout sélectionner

if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { echo "socket_create() a échoué : raison : " . socket_strerror(socket_last_error()) . "\n"; } if (socket_bind($sock, $this->address, $this->port) === false) { echo "socket_bind() a échoué : raison : " . socket_strerror(socket_last_error($sock)) . "\n"; } if (socket_listen($sock, 5) === false) { echo "socket_listen() a échoué : raison : " . socket_strerror(socket_last_error($sock)) . "\n"; } /*Accepte client */ for($i=0;$i<$this->maxClient;$i++){ if(($client = socket_accept($sock)) === false){ echo "socket_accept() a échoué : raison : " . socket_strerror(socket_last_error($sock)) . "\n"; break; }else echo "<br/>Client $client[$i] has connected\n"; /*on stock les clients(socket) dans un membre de l'objet joueur*/ $this->joueurs[$i] = new Joueur($client,$i); } while($start){ $messageClient = socket_read($sock , 1024);//PHP_NORMAL_READ /*suite .....*/

ViPHP
xTG
ViPHP | 7331 Messages

06 déc. 2012, 09:57

Tu ne peux pas utiliser une seule socket pour 3 connexions en même temps.
Il faut la fermer entre deux et attendre la seconde connexion, ect.

dorian
Invité n'ayant pas de compte PHPfrance

06 déc. 2012, 13:42

Euuh je suis pas sur d'avoir bien compris, mais l'acceptation des clients marche trés bien, c'est lors du read que sa plante !?

ViPHP
xTG
ViPHP | 7331 Messages

06 déc. 2012, 14:14

Bah oui, tu réécrases une connexion à chaque fois.
Donc quand la socket reçois de force un message d'une adresse qui n'est pas celle qu'elle avait enregistré (la dernière) elle comprend plus trop ce qui lui arrive. ;)

si tu préfères le accept va stocker dans une structure l'adresse distante du client connecté.
Donc trois accept => une seule adresse => celle du dernier accept.
Réception d'un message en provenant du second client => socket = WTF ?

dorian
Invité n'ayant pas de compte PHPfrance

06 déc. 2012, 14:17

que dois-je aire alors ? un socket_close($client) à la fin de ma boucle d'acceptation ? si c'est sa j'ai essayer vite fait sa n'a pas marché,

Je dois y aller je revien dans 2heures si tu est toujours la ...

ps : Merci de m"avoir répondu !

ViPHP
xTG
ViPHP | 7331 Messages

06 déc. 2012, 14:26

Bah il te faudrait une socket pour chaque client => un array de socket.
$socket = array();
for( $i = 0; $i < $this->maxClient; $i++){
if (($sock[] = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
            echo "socket_create() a échoué : raison : " . socket_strerror(socket_last_error()) . "\n";
            exit(); // en cas d'erreur sur la création de socket il ne faut pas faire de bind et compagnie !
         }
 
         if (socket_bind($sock[$i], $this->address, $this->port) === false) {
            echo "socket_bind() a échoué : raison : " . socket_strerror(socket_last_error($sock[$i])) . "\n";
         }
 
         if (socket_listen($sock[$i], 5) === false) {
            echo "socket_listen() a échoué : raison : " . socket_strerror(socket_last_error($sock[$i])) . "\n";
         }
}

for($i=0;$i<$this->maxClient;$i++){
 
            if(($client = socket_accept($sock[$i])) === false){
                echo "socket_accept() a échoué : raison : " . socket_strerror(socket_last_error($sock[$i])) . "\n";
                break;
            }else echo "<br/>Client $client[$i] has connected\n";
 
            /*on stock les clients(socket) dans un membre de l'objet joueur*/
            $this->joueurs[$i] = new Joueur($client,$i);
         }

while($start){
    for($i=0;$i<$this->maxClient;$i++){
         $messageClient = socket_read($sock[$i] , 1024);//PHP_NORMAL_READ
          echo $messageClient;
    }
}
Je n'ai pas testé mais le principe est là.
Le mieux aurait été de faire un thread par socket client mais PHP n'est pas vraiment un langage fait pour cela...

dorian
Invité n'ayant pas de compte PHPfrance

06 déc. 2012, 18:22

Hul merci,

Je vois le principe, c'est qu'on retrouve sur internet.

Ma premiere question est est ce que socket_read est bloquant ? si oui, il va y avoir un souci puisque n'importe quel clients peut ecrire a n'importe quel moment du coup php va attendre que le premier client ecrive alors qu'il peut ne jamais ecrire, a l'inverse le client suivant (dans la boucle) serai suscptible d'ecrire mais socket_read va attendre sur le premier client du tableau de socket qui peut comme je disait ne jamais ecrire !?

Je dois me forcement me tromper à un endroit...

D'aprés ce que je comprend je dois creer un socket "local" ou "serveur" pour chaque client ? enplus d'avoir une socket par client renvoyé socket_accept().

Dans mon cas je pensse que l'ideal serai que socket_read ne soit pas bloquant pour pouvoir lire toute les socket en permanence non ?

Merci

Avatar du membre
Mammouth du PHP | 1609 Messages

06 déc. 2012, 21:00

Salut, pareil je suis à côté de la plaque mais il me semble bien que socket_read est une fonction bloquante dont le retour ne se fait que quand des données sont reçues ou que la connexion est interrompue.

A priori tu ne peux pas surveiller plusieurs socket à la fois dans un seul script php. Si tu ne peux pas le faire autrement qu'en php il faudrait exécuter un script par socket.
Développeur web depuis + de 20 ans

dorian
Invité n'ayant pas de compte PHPfrance

06 déc. 2012, 21:35

mmmh c'est pas mal embattent sa ! personne n'a une autres alternative à proposer par hasard^^ ?

ViPHP
xTG
ViPHP | 7331 Messages

07 déc. 2012, 10:29

Tu peux essayer avec socket_recv avec le flag MSG_DONTWAIT.
Ou bien voir de ce côté :
- pthreads (je viens de voir ça en cherchant les PCNTL, faudrait voir ce que c'est vraiment)
- PCNTL
Mais PHP n'est vraiment pas un langage fait pour faire tourner plusieurs tâches...