Sockets in PHP; Chat with multiple rooms: how to?

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
heinzel
Forum Newbie
Posts: 9
Joined: Mon Apr 09, 2007 7:40 am

Sockets in PHP; Chat with multiple rooms: how to?

Post by heinzel »

Hi all,

I have written a multiplayer online game that includes a chat. The backend is a PHP script on the server. Players are connected to the game via PHP sockets. The game contains a chat, which I am mentioning because it is the best-known application for this sort of stuff. It all runs stable as long as there is only one group of people playing. But I want several games to be playable at the same time --> I.e. multiple chat rooms. The way I tried to implement this did not work.

My question is: How is this generally done? Do people assign a different socket for each room? Or is there some other way of separating group of people 1 from group of people 2? I don't require code, I have more fun making my own when I know the general idea. So anything would help: A tutorial, or maybe a couple of sentences like "try this, try that".

Thanks guys!
Heinzel
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

You can keep the same sockets, but the logic of differentiating people needs to be done server/client side. You need to transfer data between the client/server signifying which chat room they're sending the command in, and then the server interprets that, and makes sure to respond with the same information to let the client know which room the response came from.

IE:

User 1 is in Room A and B
User 2 is in Room A
User 3 is in Room B

User 1 types "Hello world" in A, Server responds by sending out "Hello world" to all clients in Room A
User 1 and User 2 see 1's "Hello world" message
User 3 says "Anyone there?" in B, Server responds by sending out "Anyone there?" to all clients in Room B
User 1 and User 3 see 3's "Anyone there?" message

It's all a matter of how you encode each command/response to deal with multiple rooms. You don't need multiple sockets for each user.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

Players are connected to the game via PHP sockets.
Puzzling. Could you should some code as to how you do this.
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post by superdezign »

ole wrote:
Players are connected to the game via PHP sockets.
Puzzling. Could you should some code as to how you do this.
Whew, I thought this was common knowledge here or something. As least it's not just me. :-p
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post by s.dot »

I tried PHP socket chat a while back, and got no where -- really fast. I'd be interested in seeing the code, as well. Also, what kind of GUI for the chat?
User avatar
onion2k
Jedi Mod
Posts: 5263
Joined: Tue Dec 21, 2004 5:03 pm
Location: usrlab.com

Post by onion2k »

ole wrote:
Players are connected to the game via PHP sockets.
Puzzling. Could you should some code as to how you do this.
Run this from the command line:

Code: Select all

<?php

    $host = "127.0.0.1";
    $port = 112233;

    set_time_limit(0);

    $sock = socket_create(AF_INET, SOCK_STREAM, 0);
    socket_bind($sock, $host, $port);
    socket_listen($sock, 3);

    $child = socket_accept($sock);
    socket_write($child, "Electric boogaloo!", strlen("Electric boogaloo!"));
    socket_close($child);

    socket_close($sock);

?>
Then telnet to 127.0.0.1:112233 ... it'll write "Electric boogaloo!" to your screen and then close. You can run an interactive session using socket_read() and a while loop.
heinzel
Forum Newbie
Posts: 9
Joined: Mon Apr 09, 2007 7:40 am

Post by heinzel »

Thanks for the replies guys! First of all, as requested some code:

Code: Select all

#!/usr/bin/php -q
<?php

require_once ('database.php');

error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();

$address = gethostbyname('www.risk-online.net');
$port = 1240;

// Start Socket creation for PHP 5 Socket Server

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, 10)) < 0) {
    echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}

$read_sockets = array($master);

//Create Persistent Loop to continuously handle incoming socket messages
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) {
            echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
            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{
                $allclients = $read_sockets;
                array_shift($allclients);

                $arguments = explode(",", $buffer);

                if ($arguments[0] == "blabla") {
                    execute some command for blabla;
                    }
            }
        }
    }
}
?>
I hope this works as I cut out some 500 lines of code in between. For all that want to learn about PHP sockets, kirupa has a very good tutorial on Sockets with PHP 5 and Flash 8 at this location: http://www.kirupa.com/developer/flash8/ ... flash8.htm. Which answers the question of what my frontend is.
heinzel
Forum Newbie
Posts: 9
Joined: Mon Apr 09, 2007 7:40 am

Post by heinzel »

@ TheMoose: That is exactly how I attempted to do it. However, I don't seem to do it right. Please help me, you're the guy who apparently can! :-)

I basically try to assign the value of

Code: Select all

$allclients[count($allclients)-1]
to a variable when someone signs in. The variable looks something like "Socket Ressource #8" (or any other number) when I print that out. I have an array, let's call it $room_a, and in $room_a I have several of those Socket Ressources stored. When I address them all, it works fine when there is only one room. But not once there are several... It mixes them up. Am I on the right track, I just didn't do it right somewhere along the way?

I will be gone to a festival this weekend ("Rock im Park" if anyone cares), so worry not if I won't reply before Monday. Please post anyway, I appreciate it a lot!
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

What you might want to try doing is have your clients send an additional argument for the room he/she is joining.

On the server, set up your connected clients array to be a bit different than what it is now. You'll need 2 arrays (ideally), one to store unlisted clients but connected clients, and another to store the clients associated to the room they're in. IE:
Pseudo:

Code: Select all

$rooms["A"][0] = $client1;
$rooms["A"][1] = $client2;
$rooms["B"][0] = $client3;
$rooms["B"][1] = $client1;

$master[0] = $client4;  // hasn't read the bytes to determine what room he/she is in yet
When they first connect, you add them to the $master list. Once you read the room he/she is trying to join (it'd be better to have the client send a join command as well, instead of immediately a chat message), you remove them from the $master list, and add them to the appropriate $rooms listing.

Then whenever you receive a command, you look inside the associated $rooms list, and act upon that command to only the clients in that channel. It'll save you some processing time as you don't have to loop through an entire $master list of clients, instead you only loop through a smaller listing of clients in a given channel.
heinzel
Forum Newbie
Posts: 9
Joined: Mon Apr 09, 2007 7:40 am

Post by heinzel »

@ TheMoose: Thanks, that's good stuff. I'll revamp the code after this weekend to the multidimensional array. Maybe as I redesign it, it'll get rid of whatever didn't work. I was just totally unsure how to approach multiple rooms as you can find applications easily, but never a tutorial or easily readable code for it on the web.
I'll post in here again sometime next week to keep you updated.
heinzel
Forum Newbie
Posts: 9
Joined: Mon Apr 09, 2007 7:40 am

Post by heinzel »

OK, final update: The code works. Thanks for your help, TheMoose! I changed the code so that the rooms are stored in a multidimensional array as you suggested, and the client now knows the room it is in instead of just passing its own name to the server which then had to find the appropriate room.
Post Reply