jump to navigation

Basic explanation of socket server – socket client in PHP October 19, 2010

Posted by Tournas Dimitrios in PHP.
trackback

Certainly PHP is not the proper language to implement production socket-based server applications . A plethora of very robust and well-tested/supported socket servers exist (FMS3 , RED5 ,WOWZA ) . Do a google and you’ll come across a dozen of possible solutions for your needs . This article will demostrate how to set-up a basic PHP socket server/client , just to demystify the concept of sockets . Firstly I’ll show you the code and explain line by line the basic functionality .

A basic socket server with PHP :


$host = "127.0.0.1";
$port = "8888";

set_time_limit(0);

print "Starting Socket Server...\n";

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

socket_bind($sock, $host, $port);

socket_listen($sock, 4);

$childSocket = socket_accept($sock);

do
{
    // look for new messages

    $incomingData = socket_read($childSocket, 2048);

    if(trim($incomingData) == "are you hungry?")
    {
        $response = "Server Response > I could eat!\n";
        socket_write($childSocket, $response, strlen($response));
    }
    else if(trim($incomingData) == "exit")
    {
        $response = "Goodbye!\n";
        socket_write($childSocket, $response, strlen($response));
        socket_close($childSocket);
        break;
    }
    else
    {
        $response = strtoupper(trim($incomingData)) . "\n";
        $writeResp = socket_write($childSocket, $response, strlen($response));
        if($writeResp === FALSE)
        {
            socket_close($childSocket);
            break;
        }
    }

}
while(true);

socket_close($sock);

?>

Explanation in 6 steps :

1..Of course, a first step in using sockets, is creating it, this is done by :
set_time_limit(0);
$sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);

Since this is a server, it’s also a good idea to use the set_time_limit() function to ensure that PHP doesn’t time out and die() while waiting for incoming client connections .

With the preliminaries out of the way, it’s time to create a socket with the socket_create() function – this function returns a socket handle that must be used in all subsequent function calls. The first parameter you see in the brackets, AF_INET is the domain. The PHP Manual states the following regarding domains, there are 2 domains:

  • AF_INET – IPv4 Internet based protocols. TCP and UDP are common protocols of this protocol family.
  • AF_UNIX – Local communication protocol family. High efficiency and low overhead make it a great form of IPC (Interprocess Communication).

AF_INET is the domain that is used for internet_based sockets, so you’ll most likely be using this most often.The second parameter in the brackets, SOCK_STREAM is the type of socket, SOCK_STREAM is full duplex, meaning you can read ánd write to the socket.The last parameter in the brackets, SOL_TCP is the protocol, PHP knows 3 major protocols, icmp, udp and tcp[i], SOL_TCP is a constant protocol of TCP. NOTE: You can also use getprotobyname(“TCP”), or simply “0” instead of SOL_TCP,whatever rocks your boat.

The $sock variable now contains an active socket resource id .

2..The next step is to bind the socket to the resource-id , listening IP-address and port :

socket_bind($sock, $host, $port);

3..After the socket is bound to the port , you can start listening for connections.:

socket_listen($sock, 4);

The first argument is the $sock variable , which holds the socket resource-id .The second argument is a backlog variable that tells PHP how many messages to queue up before an error is passed to the client. This variable is a suggestion because some systems will define or override this value. For example, Windows sets this based on the underlying provider and basically ignores any user-submitted value.

Now that you’ve bound your socket to your computer, let’s listen from incoming connections, in this tutorial the way we’re using the listen function can only accept 4 connections at a time.

At this point , you have built a socket server that doesn’t do anything. This basically means the server starts and waits for incomming connections but does not handle them in any way . The next step is to set up the portion of the server that handles the incomng connections.

4..Create another socket that handles the incoming connections:

You need to create another socket that handles the incoming connections by making a call to socket_accept passing in the $sock resource id .

$childSocket = socket_accept($sock);

From this point the $shildSocket variable is used to handle all client communications .

5..The data sent from a connection is read using the socket_read function

$incomingData = socket_read($childSocket, 2048);

This function takes two arguments. The first argument is the client socket handler-id ,and the second argument is the number of bytes to read from the client . This can be useful when trying to run a more efficient socket server .It is also a good idea to limit the output on the client side (if possible) .The socket_read function continues to load information into the $incomingData variable until the data limit is hit or one of the following characters is found : carriage return(\n) ,tab(\t) or . PHP treats those as end-of-input characters and moves to the next line in the script when one is found.

6.. Sending back a message to the client .
socket_write($childSocket, $response, strlen($response) ;


PHP does not offer an asynchronous system (event based ) like you would find in Actionscript ,to be notified when a new message arrives on the socket server .So we have to create a loop to achieve the event-like behaviour .The key to allowing the user to send more than one message , at will ,(asynchronous) at each connection is to wrap the socket_read calls that are responsible for checking for new messages in a loop . Well it sounds more complicated that it actually is ,see the code  below and you’ll get the “picture”

do
{
    // look for new messages

    $incomingData = socket_read($childSocket, 2048);

    if(trim($incomingData) == "are you hungry?")
    {
        $response = "Server Response > I could eat!\n";
        socket_write($childSocket, $response, strlen($response));
    }
    else if(trim($incomingData) == "exit")
    {
        $response = "Goodbye!\n";
        socket_write($childSocket, $response, strlen($response));
        socket_close($childSocket);
        break;
    }
    else
    {
        $response = strtoupper(trim($incomingData)) . "\n";
        $writeResp = socket_write($childSocket, $response, strlen($response));
        if($writeResp === FALSE)
        {
            socket_close($childSocket);
            break;
        }
    }

}
while(true);
socket_close($sock);

And that’s it – socket creation, in six easy steps!
The connection stays active until you either close the prompt or you type “exit” when connected to the socket-server via your socket client application . You should now understand how sockets work in PHP as well how to impement them . See also  How to create a socket server in PHP .

Putting It All Together

Now, how about seeing it in action? Since this script generates an “always-on” socket, it isn’t a good idea to run it via your Web server; instead, you might prefer to run it from the command line via the PHP binary:

//*NIX users
$ /usr/local/bin/php -q server.php

//Windows users
C:\ php -q server.php

In case you don’t have a PHP binary, it’s fairly easy to compile one – just follow the installation instructions for compiling a static Apache module (these instructions are available in the PHP distribution), but omit the “–with-apache” parameter to the “configure” script.

Note the additional -q parameter to PHP – this tells the program to suppress the “Content-Type: text/html” header that it usually adds when executing a script (I don’t need this header here because the output of this script isn’t going to a browser).

Once the script has been executed and the socket server is active, you can simply telnet to it using any standard telnet application, and send it a string of characters as input. The server should respond to the client , and terminate the connection , if a “exit” message is received from a client connection . Here’s what it looks like:

$ telnet 127.0.0.1 8888
Trying 127.0.0.1.....
Connected to medusa.
Escape character is '^]'.
?"are you hungry?"
Server Response > I could eat!
?exit
Goodbye!
Connection closed by foreign host.

A basic socket client with PHP :
Thus far, I’ve been using a standard telnet client to connect to my socket server and interact with it. However, it’s just as easy to write a simple socket client in PHP. Consider the following example, which requests user input through an HTML form and creates a client connection to the server demonstrated a few pages back. The user’s input is sent from the client to the server via this newly-minted socket connection, and the return value from the server  is displayed to the user on an HTML page.

<html>
<head>
</head>

<body>

<?php
// form not yet submitted
if (!$submit)
{
?>
<form action="<? echo $PHP_SELF; ?>" method="post">
Enter some text:<br>
<input type="Text" name="message" size="15"><input type="submit" name="submit" value="Send">
</form>
<?php
}
else
{
// form submitted

// where is the socket server?
$host="127.0.0.1";
$port = 8888;

// open a client connection
$fp = fsockopen ($host, $port, $errno, $errstr);

if (!$fp)
{
$result = "Error: could not open socket connection";
}
else
{
// get the welcome message
fgets ($fp, 1024);
// write the user string to the socket
fputs ($fp, $message);
// get the result
$result .= fgets ($fp, 1024);
// close the connection
fputs ($fp, "exit");
fclose ($fp);

// trim the result and remove the starting ?
$result = trim($result);
$result = substr($result, 2);

// now print it to the browser
}
?>
Server said: <b><? echo $result; ?></b>
<?
}
?>

</body>
</html>

Different Strokes

If you’d prefer to, there’s also an alternative, somewhat longer approach to constructing a client. Most of the time, you won’t need to use this – fsockopen() is more than sufficient for most requirements – but it’s included here for reference purposes. Take a look at this next script, which replicates the functionality of the previous example:

<html>
<head>
</head>

<body>

<?php
// form not yet submitted
if (!$submit)
{
?>
<form action="<? echo $PHP_SELF; ?>" method="post">
Enter some text:<br>
<input type="Text" name="message" size="15"><input type="submit" name="submit" value="Send">
</form>
<?php
}
else
{
// form submitted

// where is the socket server?
$host="127.0.0.1";
$port = 8888;

// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");

// connect to server
$result = socket_connect($socket, $host, $port) or die("Could not connect to server\n");

socket_read ($socket, 1024) or die("Could not read server response\n");

// send string to server
socket_write($socket, $message, strlen($message)) or die("Could not send data to server\n");

// get server response
$result = socket_read ($socket, 1024) or die("Could not read server response\n");

// end session
socket_write($socket, "exit", 3) or die("Could not end session\n");

// close socket
socket_close($socket);

// clean up result
$result = trim($result);
$result = substr($result, 0, strlen($result)-1);

// print result to browser
?>
Server said: <b><? echo $result; ?></b>
<?php
}
?>

</body>
</html>

In this case, the socket_connect() function is used to open a connection to the server, with the familiar socket_read() and socket_write() functions used to receive and transmit data over the socket connection. Once the result string has been obtained from the server, the socket connection is closed with socket_close() and the output is printed to the browser.

Again, this is an alternative implementation – it’s unlikely that you’ll find much use for it, as the fsockopen() function provides a much simpler (and shorter) way to accomplish the same thing.

Advertisements

Comments»

1. How to create a socket server in PHP « Tournas Dimitrios - October 19, 2010

[…] How to create a socket server in PHP June 19, 2010 Posted by tournasdimitrios1 in PHP. trackback Ever want to build a chat application or perhaps even a game? If so, a socket server will help you get started. Once you understand the underlying functionality of creating the server, enhancing it is just as easy.The way a socket server works is, it will be running continuously and waiting for a client to connect to it. When a client connects, our server will add it to our list of clients and begin waiting for messages from that client. If you find this article to difficult then read first this article . […]

2. Aslam Doctor - January 2, 2012

This works nicely when I test through putty(telnet) on Wamp server.
Though when I tried to test through the Client script in browser, it timeout. Any idea why?

tournasdimitrios1 - January 2, 2012

@Aslam Doctor
Sockets-scripts are not meant to be run via browser (max_execution_time directive ) . Though set_time_limit is a starting point to tweak a little bit PHP’s behavior .
Alternatively , try something like :
exec(‘start c:/php/php.exe -q c:/Apache/htdocs/socketServer.php’);
On a shared server , most likely , you won’t be allowed to run it (disable_functions directive) . Can you imagine what it would be like if 100 websites all tried to use the same port ? You can get your own dedicated server or even a VPS. That way you have (pretty much) complete control over the system .


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s