Build chat room using WebSockets - stream bytes like a champ

No image preview
Tutorials /
PHP Programming/

#php

#web


 

WebSockets allow us real-time bidirectional communication between client and server. We use them to stream games, videos, live market data, data in tracking systems, etc.

 

 

 

WebSocket is different from the ordinary HTTP request-response model, it uses one TCP connection that is kept alive, and that means we can receive and send data without refreshing the site, and the event is delivered on both sides instantly. WebSockets can work on both HTTP and HTTPS protocols using ports 80 or 443.

 

 

We will use Ratchet and PHP in our project, this is a little project I made a while ago for learning. It may seem not very easy at the beginning if you are new to WebSockets but trust me it is not so hard, we are just scratching the surface.

 

 

We will continue with the assumption you already have installed Composer and  LAMP, if not, find the documentation on Google on how to install them, and then come back, we will skip that part to not stray from the topic.

 

 

 

chatroom1.png

Communication between the private and regular browsers on the same computer.

 

 

 

Install Ratchet

 

 

To install Ratchet open the terminal at the root of your project and run this command.

 

 

 

composer require cboden/ratchet

 

 

 

To see if everything is there you can go to your composer.json file and look up if the Ratchet is there, or just run the command in the terminal to show all packages.

 

 

 

composer show

 

 

Output:

...    
ratchet/rfc6455               v0.3.1  RFC6455 WebSocket protocol handler
...

 

 

 

We are all set with the required packages, it is time to build our application. 

 

 

 

Project structure

 

 

..vendor/

..root/

 ..server/

            Chat.php

            chat_server.php

..chat1/

           index.php

...

 

 

 

WebSocket server instance

 

 

First, we will create server/file chat_server.php, this script will create an instance of the WebSocket server, and it will run it in the console and catch all requests from clients using event listeners we created within the namespace MyChat/Chat. Here we have defined the host, and port and included all Ratchet packages with the autoload.php file.

 

 

 

<?php
require dirname(__DIR__) . '/vendor/autoload.php';

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyChat\Chat;

$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new Chat()
        )
    ),
    8080,
    "127.0.0.1"

    );
    $server->run();
?>

 

 

 

Event Class 

 

 

Now we can build a logic to catch events on the server, it will delegate messages, users, groups, and other events.

 

 

 

  1. onOpen - Called when a new client has Connected
  2. onMessage - Called when a message is received by a Connection
  3. onClose - Called when a Connection is closed
  4. onError - Called when an error occurs on a Connection

 

 

 

It will be stored in the server/Chat.php file, since this is a lengthy script I have included an explanation of what is what in the comments.

 

 

 

<?php
namespace MyChat;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {
    protected $clients;


    public function __construct() {
        //create storage for all objects
        $this->clients = new \SplObjectStorage; 
    }


    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection 
        $this->clients->attach($conn);
        echo "New connection! ({$conn->resourceId})\n";
    }


    public function onMessage(ConnectionInterface $from, $msg) {
        $data = json_decode($msg);
        switch($data->command){
            case "client": $this->process_client($from, $data);
            case "message": $this->process_message($data, $msg);

        }
    }


    protected function process_client($from, $data){
        //Create a group for the clients
        if(isset($data->user_id) and isset($data->group)){
            foreach($this->clients as $client){
                if($client->resourceId == $from->resourceId){
                    $client->group = $data->group;
                }
            } 
        }
    }


    protected function process_message($data, $msg){
        //Send messages only to clients that are in a specific group
        if(isset($data->user_id) and isset($data->group)){
            foreach ($this->clients as $client) {
                if ($client->group == $data->group) {
                    // Send to group clients
                    $client->send($msg);
                }
            }
        }

    }


    public function onClose(ConnectionInterface $conn) {
        // The connection is closed, remove it, as we can no longer send it messages
        $this->clients->detach($conn);

        echo "Connection {$conn->resourceId}S   
        Las disconnected\n";
    }


    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}

 

 

 

We will define autoloader for our class using namespace MyChat, so autoloader can find the directory of the class and the class itself. Open your composer.json and edit it to look like this.
 

 

 

{
    "autoload":{
        "psr-4":{
            "MyChat\\": "server"
        }
    },
    "require": {
        "cboden/ratchet": "^0.4.4"
    }
}

 

 

 

All is done, you just need to include the index.php from the GitHub repo., I didn't want to share it here since this whole article would be too long. 

The only thing left to do is to run your server with the command in the console, and start messaging.
 

 

 

php chat_server.php

 

 


You could set up a LAN network and use this chat on a LAN network or even on a server that supports WebSockets.

[root@techtoapes]$ whoami
[root@techtoapes]$ Author Luka

Login to comment.

Admin Luka #1
“ Nothing worth having comes easy. ” — Theodore Roosevelt