Biganon Posted February 16, 2009 Share Posted February 16, 2009 Hi everybody, I've got a problem with a PHP script I'm trying to make work (sorry for my strange language, I'm Swiss ) Here is my code (http://paste-it.net/public/sae1180/ to see it better) : <?php set_time_limit(0); $address = '87.98.146.113'; $port = 17622; if(($creation = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { echo "Unable to create the socket : "."socket_strerror(socket_last_error())"."\n"; exit(); } else { echo "Creation ok.\n"; } if(($option = socket_set_option($creation, SOL_SOCKET, SO_REUSEADDR, 1)) === false) { echo "Unable to modifiy the option SO_REUSEADDR : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Modification ok.\n"; } if(($binding = socket_bind($creation, $address, $port)) === false) { echo "Unable to bind the socket : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Binding ok.\n"; } if(($listening = socket_listen($creation,10)) === false) { echo "Unable to listen to the socket : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Listening ok.\n"; } $real_array = array($creation); while(true) { $sockets = $real_array; socket_select($sockets, $reading = NULL, $except = NULL, NULL); foreach($sockets as $sock) { if($sock == $creation) { if(($client = socket_accept($sock)) === false) { echo "Unable to accept the client : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Client accepted.\n"; } array_push($real_array,$client); } else { socket_recv($sock, $buffer, 2048, 0); echo "Message sent : $buffer\n"; $broadcast_array = $real_array; array_shift($broadcast_array); envoi_message($broadcast_array,$buffer); } } } function envoi_message($destis,$content) { foreach($destis as $desti) { @socket_write($desti,$content); } } ?> (I had to translate my variables name for you to understand their aim better... ) It's an adaptation I made of a code I found in a PDF written by Thibault Imbert, called "Pratique d'ActionScript 3". As you can see, it's a socket server which listens to clients (my clients are Flash chat applications) and broadcasts what it receives to all the other clients connected. I launch it (using screen, to keep it alive) with php -f socket3.php on my Ubuntu Server. It works perfect. BUT there is one problem, which bores me. I'll try to describe the events chronologically : 1) I launch the server with the command I wrote above => The terminal tells me it's launched, listening, binded, everything. 2) I connect with the Flash client, pick a nickname => The terminal tells me : "Client accepted". 3) I send a few messages with the Flash client => The XML nodes containing the message and the nickname appear on the terminal. 4) I close the Flash client => The terminal displays : "Message sent : Message sent : Message sent : Message sent : ..." Again and again, an infinity of "Message sent : " !! To avoid the terminal to display that, I first put an "if" which checked if $buffer was NULL. If it was, nothing was done. With it, everything went well, for the client and for the terminal. But something is telling me that it's not normal... And indeed, the problem is clear : I do not "remove" the clients that are not connected anymore ! With my modifications it's doesn't appear to be very serious, but when I imagine many people connecting and the server having being running for a long long time, I guess that it will get much slower ! And it could even crash ! Because ALL the clients will be kept by the server ! So I want it to be cleaner, to remove clients that are not connected anymore. And that's why I'm posting : I don't know how to do. I tried to do this : Remember my "if" that checked if $buffer was NULL ? Well, I tried to make that, when the $buffer was NULL, then the client HAD to be disconnected. Why ? Because a NULL $buffer happened only in that case. Even with an empty nickname and en empty message, the XML structure of the broadcast string still appears, so it's not NULL. I thought it could be the solution... But I couldn't make it work. Here's what I did : when the $buffer was NULL, I just did socket_shutdown and then socket_close to the $sock on which the foreach loop was working. But then I got that message on the terminal, when closing the Flash client : Warning: socket_select(): 5 is not a valid Socket resource in /home/pluton/socket3.php on line 37 So I don't know what to do And I think my method (checking if $buffer is NULL) is not a good method... How would you manage to remove disconnected users, for $real_array to contain the EXACT connected clients, and no ghosts (except during a few seconds, the lag doesn't matter at all) ? Thank you very much Quote Link to comment Share on other sites More sharing options...
btherl Posted February 16, 2009 Share Posted February 16, 2009 After closing the socket did you remove it from the $sockets array? Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 16, 2009 Author Share Posted February 16, 2009 After closing the socket did you remove it from the $sockets array? Well I've tried to ! But all I could do was : ...blablabla... if($buffer != NULL) { echo "Message sent : $buffer\n"; $broadcast_array = $real_array; array_shift($broadcast_array); envoi_message($broadcast_array,$buffer); } else { socket_shutdown($sock,2); socket_close($sock); for($s=0;$s<count($real_array);$s++) { if($real_array[$s] == $sock) { array_slice($real_array,$s,1); } } } ...blablibloblu... And I still get the same error :\ I tried to talk between several Flash clients... It works, but WOW, I get the Warning a lot of times ! Once for every message shared, and many times otherwise, without any reason... I'm lost Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 16, 2009 Author Share Posted February 16, 2009 And with array "$socket" instead of "$real_array", it's the same :\ Quote Link to comment Share on other sites More sharing options...
btherl Posted February 16, 2009 Share Posted February 16, 2009 You can delete from arrays like this: foreach ($array as $key => $val) { unset($array[$key]); } Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 16, 2009 Author Share Posted February 16, 2009 Thanks but it doesn't work better :\ Quote Link to comment Share on other sites More sharing options...
btherl Posted February 16, 2009 Share Posted February 16, 2009 Can you post your latest code? Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 16, 2009 Author Share Posted February 16, 2009 Yes sir, here it is : <?php set_time_limit(0); $adresse = '87.98.146.113'; $port = 17622; if(($creation = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { echo "Impossible de créer la socket : "."socket_strerror(socket_last_error())"."\n"; exit(); } else { echo "Création de la socket réussie.\n"; } if(($option = socket_set_option($creation, SOL_SOCKET, SO_REUSEADDR, 1)) === false) { echo "Impossible de modifier l'option SO_REUSEADDR : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Modification de SO_REUSEADDR réussie.\n"; } if(($liaison = socket_bind($creation, $adresse, $port)) === false) { echo "Impossible de lier la socket : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Liaison de la socket réussie.\n"; } if(($ecoute = socket_listen($creation,10)) === false) { echo "Impossible d'écouter la socket : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Ecoute de la socket réussie.\n"; } $tab_utile = array($creation); while(true) { $sockets = $tab_utile; socket_select($sockets, $lecture = NULL, $except = NULL, NULL); foreach($sockets as $sock) { if($sock == $creation) { if(($client = socket_accept($sock)) === false) { echo "Impossible d'accepter le client : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Client accepté.\n"; } array_push($tab_utile,$client); } else { socket_recv($sock, $buffer, 2048, 0); if($buffer != NULL) { echo "Message transmis : $buffer\n"; $tab_envois = $tab_utile; array_shift($tab_envois); envoi_message($tab_envois,$buffer); } else { socket_shutdown($sock,2); socket_close($sock); foreach ($sockets as $key =>$sock) { unset($array[$key]); } } } } } function envoi_message($destis,$contenu) { foreach($destis as $desti) { @socket_write($desti,$contenu); } } ?> Oh and I'm tired to always translate it into English... So don't worry if the variables names aren't the same Now the arrays are $tab_utile and $tab_envois, for example. Thanks, ++ Quote Link to comment Share on other sites More sharing options...
btherl Posted February 17, 2009 Share Posted February 17, 2009 This is what I meant. I have marked the changes. Two lines were changed. while(true) { $sockets = $tab_utile; socket_select($sockets, $lecture = NULL, $except = NULL, NULL); foreach($sockets as $key => $sock) { # <--- change if($sock == $creation) { if(($client = socket_accept($sock)) === false) { echo "Impossible d'accepter le client : ".socket_strerror(socket_last_error())."\n"; exit(); } else { echo "Client accepté.\n"; } array_push($tab_utile,$client); } else { socket_recv($sock, $buffer, 2048, 0); if($buffer != NULL) { echo "Message transmis : $buffer\n"; $tab_envois = $tab_utile; array_shift($tab_envois); envoi_message($tab_envois,$buffer); } else { socket_shutdown($sock,2); socket_close($sock); unset($sockets[$key]); # <-- change } } } } Can you try this code and tell me what happens? Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 17, 2009 Author Share Posted February 17, 2009 I tried it with your code, it still tells me Warning: socket_select(): 5 is not a valid Socket resource in /home/pluton/socket4.php on line 38 Line 38 is : socket_select($sockets, $lecture = NULL, $except = NULL, NULL); Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 17, 2009 Author Share Posted February 17, 2009 PHP Version 5.2.4-2ubuntu5.5 I put an "@" before socket_select to stop being flooded, and I could see that other Warnings were coming before, here is the complete log, the information you asked is after the ">>>>>>>>>" : Création de la socket réussie. Modification de SO_REUSEADDR réussie. Liaison de la socket réussie. Ecoute de la socket réussie. Client accepté. Message transmis : <root><messag pseudo="Biga" contenu="lol" /></root> >>>>>>>>>>>>>> 0 Warning: socket_recv(): 5 is not a valid Socket resource in /home/pluton/socket4.php on line 49 Warning: socket_shutdown(): 5 is not a valid Socket resource in /home/pluton/socket4.php on line 56 Warning: socket_close(): 5 is not a valid Socket resource in /home/pluton/socket4.php on line 57 >>>>>>>>>>>>>> 1 Quote Link to comment Share on other sites More sharing options...
Biganon Posted February 17, 2009 Author Share Posted February 17, 2009 No idea ? ??? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.