Websockets with php – tutorial on basics

Websockets

Websockets is a new feature available in browsers as a part of the Html5 specs that allows javascript clients to open bi directional socket connections to a server. Currently all major desktop browsers support the api.

Websocket is not an independant socket protocol, but is based on the TCP protocol just like HTTP. Therefore websocket connections are basically tcp socket connections that following the websocket rules to communicate. The protocol is is documented at RFC 6455.

So a separate socket server is needed to handle the websocket communications. The same web/http server like apache would not do that. Websocket server are run like normal daemons on linux for example.

Websocket url

A websocket url looks like this

ws://host:port/some/path

The important parts are host and port. It should be noted that the uri part after port is not necessary to establish the connection. It should not be confused to point to the path of the php server script or anything. It can be used by the server to locate resources. The connection is just made to the host on the given port number.

Now lets try to code up something using websockets.

Code

We shall use the following websocket server, written in php

https://github.com/ghedipunk/PHP-Websockets

The server itself is a class that can be extended to write the rest of the application. Download the zip and look inside. The websockets.php is the base class and we shall extend that class to write our own simple websocket server application. The base class does the socket management and websocket handshake stuff etc.

The application class just needs to override the process function to handle the incoming requests from the client.

#! /usr/local/bin/php
<?php

require_once('websockets.php');

class echo_server extends WebSocketServer 
{
	//protected $maxBufferSize = 1048576; //1MB... overkill for an echo server, but potentially plausible for other applications.
	
	protected function process ($user, $message) 
	{
		if($message == 'help')
		{
			$reply = 'Following commands are available - date, hi';
		}
		else if($message == 'date')
		{
			$reply = "Current date is " . date('Y-m-d H:i:s');
		}
		else if($message == 'hi')
		{
			$reply = "Hello user. This is a websocket server.";
		}
		else
		{
			$reply = "Thank you for the message : $message";
		}
		
		$this->send($user, $reply);
		
		//The uri component say /a/b/c
		echo "Requested resource : " . $user->requestedResource . "n";
	}
	
	/**
		This is run when socket connection is established. Send a greeting message
	*/
	protected function connected ($user) 
	{
		//Send welcome message to user
		$welcome_message = 'Hello. Welcome to the Websocket server. Type help to see what commands are available.';
		$this->send($user, $welcome_message);
	}
	
	/**
		This is where cleanup would go, in case the user had any sort of
		open files or other objects associated with them.  This runs after the socket 
		has been closed, so there is no need to clean up the socket itself here.
	*/
	protected function closed ($user) 
	{
		echo "User closed connectionn";
	}
}

$host = '0.0.0.0';
$port = 9000;

$server = new echo_server($host , $port );






Now launch the server script from terminal

php /var/www/blog/websocket/echo_server.php

Once launched it shall open a socket server on 9000 that will speak the "websocket" protocol and supporting browsers can talk to it.

Next comes the client, that would be written in javascript. Here is the code


<html>
<head>
	<title>WebSocket</title>

	<style type="text/css">
		#log {
			width:600px; 
			height:300px; 
			border:1px solid #7F9DB9; 
			overflow:auto;
			padding:10px;
		}
		#msg {
			width:300px;
		}
	</style>
	
	<script type="text/javascript">
	var socket;

	function init() {
		var host = "ws://localhost:9000/path/to/app"; // SET THIS TO YOUR SERVER
		
		try 
		{
			socket = new WebSocket(host);
			log('WebSocket - status ' + socket.readyState);
			
			socket.onopen = function(msg) 
			{ 
				if(this.readyState == 1)
				{
					log("We are now connected to websocket server. readyState = " + this.readyState); 
				}
			};
			
			//Message received from websocket server
			socket.onmessage = function(msg) 
			{ 
				log(" [ + ] Received: " + msg.data); 
			};
			
			//Connection closed
			socket.onclose = function(msg) 
			{ 
				log("Disconnected - status " + this.readyState); 
			};
			
			socket.onerror = function()
			{
				log("Some error");
			}
		}
		
		catch(ex)
		{ 
			log('Some exception : '  + ex); 
		}
		
		$("msg").focus();
	}

	function send()
	{
		var txt, msg;
		txt = $("msg");
		msg = txt.value;
		
		if(!msg) 
		{ 
			alert("Message can not be empty"); 
			return; 
		}
		
		txt.value="";
		txt.focus();
		
		try 
		{ 
			socket.send(msg); 
			log('Sent : ' + msg); 
		} 
		catch(ex) 
		{ 
			log(ex); 
		}
	}
	
	function quit()
	{
		if (socket != null) 
		{
			log("Goodbye!");
			socket.close();
			socket=null;
		}
	}

	function reconnect() 
	{
		quit();
		init();
	}

	// Utilities
	function $(id)
	{ 
		return document.getElementById(id); 
	}
	
	function log(msg)
	{ 
		$('log').innerHTML += '<br />' + msg; 
		$('log').scrollTop = $('log').scrollHeight;
	}
	
	function onkey(event)
	{ 
		if(event.keyCode==13)
		{ 
			send(); 
		} 
	}
	</script>

</head>

<body onload="init()">

	<h3>WebSocket</h3>

	<div id="log"></div>

	Enter Message <input id="msg" type="textbox" onkeypress="onkey(event)"/>

	<button onclick="send()">Send</button>
	<button onclick="quit()">Quit</button>
	<button onclick="reconnect()">Reconnect</button>

</body>
</html>

The WebSocket class is used to created an object of websocket. It takes the websocket url as the parameter to connect. Then there are events like 'onopen', 'onmessage' , 'onclose' that need to be handled.

The communication can look like this

WebSocket - status 0
We are now connected to websocket server. readyState = 1
[ + ] Received: Hello. Welcome to the Websocket server. Type help to see what commands are available.
Sent : help
[ + ] Received: Following commands are available - date, hi
Sent : hi
[ + ] Received: Hello user. This is a websocket server.
Sent : date
[ + ] Received: Current date is 2013-02-13 10:31:58
Sent : how are you
[ + ] Received: Thank you for the message : how are you

Conclusion

The main power of websockets lies in its ability to do bidirectional communication without breaking the connection. Therefore it can be used to implement realtime communication like chat without polling.

Last Updated On : 12th February 2013

Subscribe to get updates delivered to your inbox

12 Comments + Add Comment

  • I have install above demo and it’s work fine in localhost
    Now i upload on live server then how i run this echo_server.php ?
    If i run through terminal on live and i close terminal then it’s stopped working.
    How i run persistent this echo_server.php file ?

  • Thanks — very helpful, but contains an important omission.

    Requires the following additional line of code in the echo server:

    $server->run();

    otherwise it just terminates before the client has a chance to do anything.

  • Nice logic! Putting the echo_server.php in the public root directory!

  • Hello,
    I have a problem – commands sent to the server and are not correctly
    recognized, 1 of 15 passes completely. Tell me how to solve the problem.
    Thank you!

  • Hi,

    I have run the file as a cron job once using:

    wget http://www.wilsea.com/websockets1/echo_server.php

    I get an email with the following :

    –2013-08-14 19:52:01– http://www.wilsea.com/websockets1/echo_server.php
    Resolving http://www.wilsea.com... 188.64.188.21
    Connecting to http://www.wilsea.com|188.64.188.21|:80… connected.
    HTTP request sent, awaiting response… 200 OK
    Length: unspecified
    Saving to: `echo_server.php’

    0K 36.0M=0s

    2013-08-14 19:52:02 (36.0 MB/s) – `echo_server.php’ saved [258]

    I have changed the port to 8000 (and this is open) and the IP address in the php & html file.

    I have this in the log file:

    [14-Aug-2013 19:52:02 Europe/London] PHP Warning: socket_bind() [function.socket-bind]: unable to bind address [98]: Address already in use in /home/wilseayd/public_html/websockets1/websockets.php on line 22

    Does this mean port 8000 is in use or is it something else?

    Cheers

    SteveW

  • The function closed($user) in my server is never called, Can you help me?

  • how can i add channels in this code so as to send a message to users in a specific channel

  • After a few hours of googling and taking tutorials, this is the tutorial that finally got to work for me.
    So thanks a lot!

  • My client application is not browser. It’s just a gateway which has wifi stack running on it. Can I still use websockets for bidirectional communication?

  • Thanks your code is running wounderful as I expected. Can we video stream via this code.? ????

    I have userA and user1,2,3 now when userA command to play video1 then vidoe1 need to play on user1,2,3.a

    give me idea, How can I resolve this.

  • Is this websocket lib up-to-date with current spec ? Could it be used in production env ?

    • for details on the library contact the author at github. It probably hasn’t been updated for many months.
      there are other more complete libraries like ratchet. can check them.

Leave a comment