Jump to content

Sockets - Client closing connection


Biganon

Recommended Posts

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...  :P)

 

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  :)

Link to comment
Share on other sites

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  :-[

Link to comment
Share on other sites

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  ;D Now the arrays are $tab_utile and $tab_envois, for example.

 

Thanks, ++

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.