Socket Programming With PHP (
Page 1 of 9 )
You might not know this, but PHP comes with a very capable socket
programming API. These socket functions now include almost everything you
would need for socket-based client-server communication over TCP/IP, and
can be easily deployed to build simple network applications. Find out more,
inside.If you've been working with PHP for a while, you're probably used to thinking
about it only in the context of a Web page or a Web server. While this is not
unusual - PHP is, after all, a scripting language that's most commonly used to
dynamically generate Web pages - it can stifle your creativity; as you'll see in
this article, there's a lot more you can do with PHP than just connect to a
database, retrieve records and insert them into an HTML template.
One of
PHP's better-guarded secrets - and one that I discovered quite by accident - is
a very comprehensive set of network programming functions. Steadily evolving
over the last few releases, this socket programming API now supports almost
everything you would need for socket-based client-server communication over
TCP/IP, and can be rapidly deployed to build simple client-server applications
in PHP.
Over the course of this article, I'll be taking a close look at
the more important functions in this API, using code listings and explanations
to put them in context. Along the way, I'll also build some simple client-server
applications, thereby illustrating PHP's effectiveness as a rapid development
and deployment tool for network-based applications through practical, real-life
examples (well, some of them, at any rate).
It should be noted at the
outset itself that this is an introductory article, primarily meant for Web
developers interested in expanding their PHP knowledge into the somewhat-arcane
area of network programming. I won't be getting into anything too complicated -
for truly sophisticated client-server programming, you're probably better off
with C++ or Java anyway - preferring instead to focus on the practical
applications of PHP's socket functions. As is traditional with these articles,
I'll also keep the technical jargon to a minimum, avoiding mention of
tongue-twisting acronyms and hard-to-pronounce buzzwords.
In return for
all this largesse, I expect you to laugh at the appropriate places, and say nice
things about me to your friends. Do we have a deal?{mospagebreak title=Going
Backwards} For those of you new to the topic, a "socket" provides a way for
clients and servers to communicate in a networked environment. It creates an
end-to-end communication channel, allowing a client to send requests to a server
and a server to receive these requests and respond to them. A common example
here is that of a Web server; the server opens a socket (usually on port 80),
and clients (Web browsers) communicate with it through this socket, requesting
specific HTML pages for processing and display.
PHP comes with a fairly
comprehensive set of functions to create and manipulate socket communications;
however, this capability is not enabled by default. Consequently, you may need
to recompile your PHP binary with the "--enable-sockets" parameter to activate
socket support. Windows users get a pre-built binary with their
distribution.
Let's start with a simple example - a TCP server that
accepts a string as input, reverses it and returns it to the client. Here's the
code:
<?
// set some variables
$host = "192.168.1.99";
$port = 1234;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create
socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to
socket\n");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket
listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming
connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// clean up input string
$input = trim($input);
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write
output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
?>
This is somewhat involved, so an explanation is in
order:
1. The first step here is to set up a couple of variables to hold
information on the IP address and port on which the socket server will run. You
can set up your server to use any port in the numeric range 1-65535, so long as
that port is not already in use.
<?
// set some variables
$host = "192.168.1.99";
$port = 1234;
?>
2. 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.
<?
// don't timeout!
set_time_limit(0);
?>
3. 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.
<?
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create
socket\n");
?>
In case you're wondering what this is all about, don't worry
too much about it. The AF_INET parameter specifies the domain, while the
SOCK_STREAM parameter tells the function what type of socket to create (in this
case, TCP).
If you wanted to create a UDP socket, you could use the
following line of code instead:
<?
// create socket
$socket = socket_create(AF_INET, SOCK_DGRAM, 0) or die("Could not create
socket\n");
?>
4. Once a socket handle has been created, the next step is to
attach, or "bind", it to the specified address and port. This is accomplished
via the socket_bind() function.
<?
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to
socket\n");
?>
5. With the socket created and bound to a port, it's time to
start listening for incoming connections. PHP allows you to set the socket up as
a listener via its socket_listen() function, which also allows you to specify
the number of queued connections to allow as a second parameter (3, in this
example).
<?
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket
listener\n");
?>
6. At this point, your server is basically doing nothing,
waiting for incoming client connections. Once a client connection is received,
the socket_accept() function springs into action, accepting the connection
request and spawning another child socket to handle messaging between the client
and the server.
<?
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming
connection\n");
?>
This child socket will now be used for all subsequent
communication between the client and server.
7. With a connection
established, the server now waits for the client to send it some input - this
input is read via the socket_read() function, and assigned to the PHP variable
$input.
<?
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
?>
The second parameter to socket_read() specifies the number of
bytes of input to read - you can use this to limit the size of the data stream
read from the client.
Note that the socket_read() function continues to
read data from the client until it encounters a carriage return (\n), a tab (\t)
or a \0 character. This character as treated as the end-of-input character, and
triggers the next line of the PHP script.
8. The server now must now
process the data sent by the client - in this example, this processing merely
involves reversing the input string and sending it back to the client. This is
accomplished via the socket_write() function, which makes it possible to send a
data stream back to the client via the communication socket.
<?
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write
output\n");
?>
The socket_write() function needs three parameters: a
reference to the socket, the string to be written to it, and the number of bytes
to be written.
9. Once the output has been sent back to the client, both
generated sockets are terminated via the socket_close() function.
<?
// close sockets
socket_close($spawn);
socket_close($socket);
?>
And that's it - socket creation, in nine easy
steps!