Jump to content

Recommended Posts

Hello all!

 

To make a long story short, and to explain what I'm asking about, I'll give some background about what I can do, what I've done, and what I'm looking to do.

Just started a while a go to deal with PHP, used to work alot with ASP, made some apps with VB6 (similar to ASP), and I am a flash actionscript programmer in general.

I am working on a chat/games multi player platform, where I'm building the server part in PHP (the last app of this type of made with a VB6 bases server app).

My methods for doing this includes an xmlsocket that the client (flash) uses to connect to the PHP page that hold the code for the server, and that, in turn, runs in a content loop, getting the data from the connected users, and send the data back to the correct user (private msg), or all users (public msg).

So far so good, and it all works fine, but I have a problem.

I need to save some data about the users in the PHP that holds the server, like users names and id's, but it would seem that the arrays I create for saving this data are recreated every time a user calls to the page in order to connect, which would make sense, since each call to the PHP page as the socket target initiate the variables I use.

But... the sockets that are open, and bind, are always accessible to the PHP to send a message through, to all connected clients, one socket at a time.

My question is, should you choose to read it (ha ha), is if there is a way to save the users data (name, id) into an array that will not be initiated every time a users connects through the PHP page, such as the array holding the socket connections is saved in some global sort of way?

 

If my question is unclear, let me know, I will clarify, and if you want, I'll paste the code I'm using, and include a fake code depicting what I'm trying to do, just to explain better my problem.

 

Hope some one here could sort that little hurdle up for me, so I could continue working on the app, and of course, when it's up and running, I will be more then willing to post up both the full PHP code, as well as the flash client, for all to see and use as they see fit.

 

Thanks,

 

Yuval Lahav,

Rome, Italy.

Well, I'm still pretty new at this but I'll give you my input as to what I think the case is. That is assuming I understood your problem properly.

 

php will not store data for several different users "in itself". Each page request is unique to each user - and so your arrays within those pages will be unique to each user as well, they are not shared between users. There is a way to store each users info across different pages via sessions (http://nz.php.net/session) but again, that session information is only really accessible by the user for which it was created.

 

It sounds like you will need to implement some sort of database backend to store user information so that you can then make a call to the database for information for any page.

 

Sorry if this sounds very basic, I'm just assuming you are very new to php even though it seems like you know what you are doing in other languages.

 

Hope this helps, it's after midnight now and I need sleep so good luck.

Well, thanks for the answer, but it didn't help much, since I am trying to avoid using external files, or a DB, to keep this as simple as possible.

I know that variables and arrays are unique to each instance of the page, but the fact is that the socket object, put into an array holding many sockets, can be accessed by all the users connected, or else passing messages from user to user would not be possible.

My question is if the is a type of an object, like, for example, the stack of sockets I create using the single PHP, that will allow me to update it with information that I could access with the other user, some type of global php object that is visible to all php pages in the site/server ("application" level equivalent in ASP, for example).

 

Thanks again.

 

Yuval Lahav.

Or... maybe... is there a part, or an element, within the socket object, that allows me to put in my own data into it, for future reference, enabling me to read that information as I loop over all my sockets, reading that information from the socket object when needed?

 

Yuval Lahav.

if the user has a concurrent server connection you can try using sessions.

However from what I am seeing in yuor method (and correct me if i'm wrong) you are using a standalone flash file to run your game which means they aren't using a browser such as IE,FF therefor sessions are not compliant with the pseudo browser of "flash player" since the server contact is done in the background and response text is streamed via a socket their client has no direct connection.

 

Now if they are using a browser you are all set to use sessions.

 

Also flash might have its own version of "sessions" in which you could use a combo of mysql + flash

MySQL would create dynamic rows for each "session" and then everytime the flash game requested to your server data it would pass via GET/POST their mysql data's Row.  Then you can query the row for any data in turn opening up more data.

 

then simply put an expatriation date on the MySQL data saying it dies when it isn't requested in say X minutes and thus logging out a user.

OK, lets take this apart:

 

"if the user has a concurrent server connection you can try using sessions." - Sessions will not help me, as I need to store data concerning all the users, and not about the current user.

 

"However from what I am seeing in yuor method (and correct me if i'm wrong) you are using a standalone flash file to run your game which means they aren't using a browser such as IE,FF therefor sessions are not compliant with the pseudo browser of "flash player" since the server contact is done in the background and response text is streamed via a socket their client has no direct connection." - The client will be placed on an html platform, to be accessed via IE or FF (or opera, or any other supported browser), but again, since I need to save the data of all users for all users to use, saving information in the session will not realy help me with anything.

 

 

To make this point clear, I will give an example of what I need to do:

1 - user "A" connects to the "chat", via xmlsocket connection, the connection on the php page is approved and is binded to the ip+port given, and added to the stack of sockets.

2 - user "A" receives a message via the socket telling it is connected.

3 - user "A" sends via the socket his information (name, id).

4 - user "A" receives back his message with the data sent, as a confirmation for the connection.

 

5 - user "B" connects to the "chat", via xmlsocket connection, the connection on the php page is approved and is binded to the ip_port given, and added to the stack of sockets.

6 - user "B" receives a message via the socket telling it is connected.

7 - user "B" sends via the socket his information (name, id).

8 - user "B" receive back his message with the data sent, as a confirmation for the connection.

 

9 - user "A" receive "B"'s message with the data sent, as a confirmation for "B"'s connection.

 

And here, I need to add a 10th step:

 

10 - user "B" receives a message from the server with the information of all the users already connected to the "chat" (in this case, of "A"'s).

 

To be able to send user "B" the information that was sent initially by user "A" (name, id), I would need to store that information in a place that will be accessible always, and the big question is, can that be done without a DB, even as simple as a temporary SQL DB? the same way the stack of sockets is always accessible to all the users connected to the "chat", is there a way to store an array, or variable, that could be updated, and accessed? again, I'm looking for a solution much like the stack of sockets, or, if it's possible, add my own information to the socket object itself, thus solving my problem, since if my sockets connections are always accessible, any data they hold within them will be accessible.

 

I hope this clarify the issue.

 

Thanks again,

 

Yuval Lahav.

I don't do a ton of work with sockets and I can see the issue with having to "query on demand" because you want instant gratification of a user's message.

 

I think what you need to do is make some sacrifices.

The WhoIsOnline system will need to be managed via MySQL because php has no way to manage variables after a page execution. 

The flash system will request updates from the MySQL every N seconds and then store the data locally in the end users flash variable saved location (that is a flash thing I'm sure it exist I don't know how to use it I don't do flash).

 

The dictating of who gets what messages the php script should be able to manage using the data in the WhoIsOnline to send messages properly.

I.e

 

User wants to send a message to user C so they click use C on the WhoIsOnline list which in turn builds the packet for socket saying send to "this IP this Port" php then can extract it and send it on execution.

 

MySQL storse all the What physical username has which IP/Port etc data and constantly repushes it to the end user.

 

I don't know how yuor specific socket setup works but I'm sure if you use somethign like this you should be fine.

The php script simply takes in 3 parts of data

1) the message

2) The from Ip/port

3) The to IP(s)/Port(s)

 

It sends back to the To IP(s)/Port(s) all the data it received less additional recipients of the data in the to portion.

Flash then reverts the IPs back into screennames, handles, usernames etc. via the mysql dependencies it has in its possession.

Sorry, but again, there is a big misunderstanding here, maybe because you have not done that much work with sockets, and probably because I'm trying to use flash and VB lingo to describe what I'm doing, and what I want to do.

Before I paste my code, I will try to make this, again, a little clearer:

1 - I don't care about the ip, or port, of each users, the ip+port I have talked about, are the ip+port of the server (hence "ip") where my PHP reside, and the post to listen to for incoming connection (hence "port").

I have no need to a user's ip, or port, to send a message from a specific user to another specific user, since the sockets of the user=>server is open constantly, and not need to reopen with every message sent, so in that view, lets forget client to client communication, and think of this only as a client to all other clients type of chat, or, as you would, a public chat room.

 

The players:

1 flash client (swf file, on, or off, an html platform).

1 php page, on a server.

 

The action:

(all this is already working, no problems there, code will be posted at the end of the explanation).

 

1 - php file, when first activated (command line or via browser), creates a socket object, which listens (to do this, he needs 2 pieces of information, IP of the server, and an open port number) for incoming connection requests.

2 - a flash client sends a connection request using the IP of the server, and the port (note that he does not call the php itself, but he calls the server, and the post, where our socket is listening).

3 - the socket object receives the connection request, and create a socket object in a stack, binding the socket to the relevant ip and port, and send the client a message saying the connection is approved, the original socket object keeps on listening for new connections.

4 - the client receives the connection approval, and from this point on, the connection from the client, to the socket object in the stack, is constant, until the server, or the client, has terminated the connection (on server restart, client shutdown, manual closing, atc'), and once the connection has established, a short xml message is sent via the socket to the server with the user's data (name, id).

5 - consider 5 other users have already done this process, and are connected to their sockets, meaning, with the new client connection, we have a stack of 6 active connections, + 1 socket objects

6 - the server (in this case, not the physical machine, but our little php application), holding the new socket, receives the xml message from the client, and loops on all the sockets in the stack of sockets, delivering the message to each client in it's turn.

 

As you can see, the connection is constant, not recreated every time someone wants to send a message.

Also, just to explain, the php file is "stuck" in a loop, using "while(true)", which constantly checks the status of all the active sockets, when the status of one of the sockets is changed, from idle to, as an example, to "data", then the data is intercepted, and is sent to all the sockets in the stack. if the new socket status is "dead", the server knows the user has disconnected, and can inform all the users of the disconnection.

 

as you can tell from what I told you, the php page is called upon just once in this whole process, to start it up, other then that activation calling, all the information occurs within the system of sockets on the server (in this case, the actual machine).

 

My problem is, that although, for example, the array holding the sockets is accessible at all times when users send/receive message, an array I create on that same page, which I want to populate with the users data, seems to be re-initialized every time a client is sending a connection request to the server.

 

How to I make that work, what is the problem with these arrays?

 

and now, for the code, drumroll please......:

 

<?php
error_reporting(E_ALL);

set_time_limit(0);

$address = '127.0.0.1';
$port = 9000;

function get_attribute($str,$find){
$pos1 = strpos($str,$find."='")+strlen($find."='");
$pos2 = strpos($str,"'",$pos1);
$attribute = substr($str,$pos1,$pos2-$pos1);
return $attribute;
}

function get_value($str){
$pos1 = strpos($str,">")+1;
$pos2 = strpos($str,"<",$pos1);
$value = substr($str,$pos1,$pos2-$pos1);
return $value;
}

function handle_client($allclient, $socket, $buf, $bytes, $index, $client) {	
$msgtype = get_attribute($buf,"type");

if($msgtype == 1){ //new user's data
	$uname = get_attribute($buf,"uname");
	$uid = get_attribute($buf,"uid");

	$users_names[$index] = $uname;
	$users_ids[$index] = $uid;
}

foreach($allclient as $client) {		
        socket_write($client, $buf);
    }
}

if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
   //echo "socket_create() failed: reason: " . socket_strerror($master) . "\n";
}
                                                                                
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);

if (($ret = socket_bind($master, $address, $port)) < 0) {
    //echo "socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
}

if (($ret = socket_listen($master, 5)) < 0) {
    //echo "socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
}

$read_sockets = array($master);

$users_names = array();
$users_ids = array();

while (true) {
    $changed_sockets = $read_sockets;
    $num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
    foreach($changed_sockets as $socket) {
        if ($socket == $master) {
            if (($client = socket_accept($master)) < 0) {
                //Socket rejected
                continue;
            } else {
                array_push($read_sockets, $client);
            }
        } else {
            $bytes = socket_recv($socket, $buffer, 2048, 0);
            if ($bytes == 0) {
                $index = array_search($socket, $read_sockets);

			unset($read_sockets[$index]);
			socket_close($socket);
            } else {
			///// look for index of user...
			$index = array_search($socket, $read_sockets);
			///// end look for index of user...
                $allclients = $read_sockets;
                array_shift($allclients);    // remove master
                handle_client($allclients, $socket, $buffer, $bytes, $index, $client);
            }
        }
       
    }
}

?>

 

To finish this off, I hope, the problem is that the 2 arrays I create never seem to keep the data in them, but, simple reinitialize every time I connect to the application with a new user.

If that can't be solved, and I tried to, is there some other way of saving the information using the same methods described before, to store the data to be accessible when needed?

 

I hope this finaly is clear enough.

 

Thanks again,

 

Yuval Lahav.

Ok, here is the updated code, with added comments:

 

<?php
//error reporting
error_reporting(E_ALL);
//no time limit please
set_time_limit(0);
//address of server, set for local machine atm
$address = '127.0.0.1';
//port to listen to
$port = 9000;
//this function will parse some string for me, that comes in formated as xml
function get_attribute($str,$find){
$pos1 = strpos($str,$find."='")+strlen($find."='");
$pos2 = strpos($str,"'",$pos1);
$attribute = substr($str,$pos1,$pos2-$pos1);
return $attribute;
}
//this function will parse some string for me, that comes in formated as xml
function get_value($str){
$pos1 = strpos($str,">")+1;
$pos2 = strpos($str,"<",$pos1);
$value = substr($str,$pos1,$pos2-$pos1);
return $value;
}
//this function handles the message received from the client, and send it to all connected clients
function handle_client($allclient, $socket, $buf, $bytes, $index, $client) {
//I get the message type, so I'll know what to do, in the future this will be used also to tell private message from public message
$msgtype = get_attribute($buf,"type");
//if the message type is 1, then....
if($msgtype == 1){//type 1 is the first message sent from a client to the server after the connection was approved
	//here I am starting to create the message with the list of connected users to be sent to the new connected client.
	$conmsg = "<MSG type='2' count='".count($users)."' index='".$index."'>";
	//here I am looping over the users array, putting the user data into xml nodes
	foreach($users as $i){
		$conmsg = $conmsg."<USER uname='".$i["name"]."' uid='".$i["id"]."'/>";
	}
	//finished all the users, closing the message
	$conmsg = $conmsg."</MSG>".chr(0);
	//sending the message back to the client, this message is sent "privatly" to the newly connected client
	socket_write($client,$conmsg);
	//adding the information of the new user to the array of users, using the index value of the socket as a place holder for the information, as this value is unique
	$users[$index]["name"] = get_attribute($buf,"uname");
	$users[$index]["id"] = get_attribute($buf,"uid");
}
//looping over all connected clients
foreach($allclient as $client) {
//sending each client in his turn the message received from the client		
        socket_write($client, $buf);
    }
}

//creating the master socket!!
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
   //echo "socket_create() failed: reason: " . socket_strerror($master) . "\n";
}
//setting socket options                                        
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
//binding the socket to the server's ip, and the port we chose
if (($ret = socket_bind($master, $address, $port)) < 0) {
    //echo "socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
}
//telling the socket to listen
if (($ret = socket_listen($master, 5)) < 0) {
    //echo "socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
}
//creating our now famose sockets stack
$read_sockets = array($master);
//creating the non working for some reason users array
$users = array();

while (true) {
    //blablabla
    $changed_sockets = $read_sockets;
    //blablabla
    $num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
    //loop over the sockets
    foreach($changed_sockets as $socket) {
        //if the change came from the master socket....
        if ($socket == $master) {
            //create the new socket to be put in the stack
            if (($client = socket_accept($master)) < 0) {
                //Socket rejected
                continue;
            } else {
                //and push it into the stack.
                array_push($read_sockets, $client);
            }
        } else {
            //if the changed socket stat was of another socket but the master, then read information
            $bytes = socket_recv($socket, $buffer, 2048, 0);
            //if no information has arrived, but the socket status has changed non the less
            if ($bytes == 0) {
                //find the socket who's stat had changes, but no data has arrived
                $index = array_search($socket, $read_sockets);
			//remove the socket from the stack, it has closed.
			unset($read_sockets[$index]);
			socket_close($socket);

			// remove user from users array		
			array_splice($users,$index,1);
                
            } else {
			///// look for index of user...
			$index = array_search($socket, $read_sockets);
			///// end look for index of user...
                //make a list of active sockets
                $allclients = $read_sockets;
                //remove master socket from the list, we don't need to send him anything
                array_shift($allclients);    // remove master
                //handle the sending of the message to all connected users
                handle_client($allclients, $socket, $buffer, $bytes, $index, $client);
            }
        }
       
    }
}

 

So thats the code, and it works perfectly, except that every time a user connects, the users array length is 0, after the users array has been updated, it's length is 1, and that is the problem, what causes that array specifically to loose the information between users connecting?

 

Thanks,

 

Yuval Lahav.

Ok!!

 

Forget about everything....

 

It would seem my problems all rose from trying to update and array which is in the global scope of the php from within a function, without bothering to tell the function the array is in the global scope.

 

Thanks for all your help! this day at work wouldn't have passed quite as fast as it did without me writing out my problems like this :)

 

Yuval Lahav.

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.