PHP Sockets Made Easy

A Tutorial by Jim Plush, senior web engineer, Panasonic Avionics (jiminoc @AT@ gmail.com)

Introduction to Sockets

This tutorial aims to raise your skills and clear up any confusion or questions you have regarding socket programming with PHP. Let's first talk about what a socket is. Take a look at the picture below...it's a normal to think of these when you hear the work "sockets". Conceptually we can use these socket tools to get a clearer picture of just what sockets do. A socket is a plug or a way to connect to another computer. This computer might be in the next room or across the world which is known as network programming. Your computer is assigned an IP address. This IP address let's any computer in the world know where to reach you (Let's pretend for a minute that firewalls don't exist and you're connected directly to the internet) Computers communicate with your computer through "PORTS". This allows around 65,000+ different applications to be talking to the internet at any given time. If you didn't have ports, computers would have a hard time trying to find out what data was meant for what program.

A picture of sockets Sockets on a computer

The most common example of how to think about ports is the web. Normal web traffic goes over port 80. When you make a request for a webpage, your browser opens up a socket connection to port 80 on the machine you wish to view the webpage on and says "hey give me this page I want". The web server on the other end is listening on port 80 for any requests. When it receives a request, it awaits for your command which typically says "GET /index.html HTTP/1.0\r\n" which tells the web server, "I want the index.html page on this website, jack!". Another example is FTP which listens on port 21. So there are many applications out there that use these "ports" in your computer to communicate to the outside world. In fact this is how alot of the virus and trojans work. They keep a socket or port on your computer open to the outside world, waiting for commands to attack other computers or to send your personal details to a master computer. Clever eh? You can see a list of all your open socket connections by typing in "netstat" on any command line. This command lists all the computers currently connected to you and which ports they're communicating on.

Sockets and PHP

PHP makes socket programming pretty easy. You can do alot of very complex tasks using sockets and PHP. One such task I have recently run into is writing a socket server that allows multiple applications to connect to it. All of these applications want to send their own little bits of information to parts of a system only I know about. They just want to send data to all administrators for example, however only I know where administrators are logged in at. Their c++ applications need to open up a socket to me, and send me the information that want to forward and I'll do the job of finding out where those people are. PHP performs very well for this task.

So what's involved in socket programming with PHP? Well let's start off with a socket server. Its a very simple concept. You create a program that runs all the time, constantly running that just sits there and says "CONNECT TO ME!!! HERE I AM, OVER HERE ON PORT 10000". Creating a socket server is very much like using a telephone. There are certain steps you have to do to make a telephone call right? Well there are certain steps to make a phone call to another computer as well. They look like so...

  1. Install a Phone - socket_create()
  2. Plug in the phone to the phone jack - socket_bind()
  3. Turn the power to the phone on - socket_listen()
  4. When the phone rings, you pick it up and talk! - socket_accept()

TCP & UDP Protocols

The majority of the time you'll being using either TCP or UDP sockets. What's the difference you may ask? TCP is a stateful connection protocol which means I know that if I send you the data "1,2,3" that you'll receive "1,2,3". It's much like a telephone conversation. When I pick up the phone I hear you on the other end, I can listen to what you tell me, I can talk back and I KNOW WHEN YOU HANG UP. That is important as UDP sockets do not follow that concept. A UDP socket is much like leaving someone a voicemail. You made the call, you told them your message but you have no idea if they'll ever listen to your message.

The world wide web is built on TCP. You want to make sure you're getting all of the web page displayed, not some of it. There are definitely uses for UDP as well. Music streaming is the most common example. If someone is sending you millions of packets of information while a song is playing, if something happens and some packets of data are lost, do you really want to hear the beginning of Stairway to Heaven(RIAA please don't sue me for using a real song title you pricks) at the end of the song? Probably not, you just want to keep on listening.

PHP Socket Server

Let's take a look at these steps one by one and see how the PHP commands and options affect our server. Our first goal is to create a socket server that will listen on Port 10000, accept a connection and then respond with a message from the server. We'll start simple and get more complex as we go along.

Step 1

Looking at step one we see "Install a Phone - socket_create()". What this does is creates a resource on the operating system for us to use. A socket descriptor. It's exactly like when you use $fp = fopen("myfile.txt", "r");. $fp now contains a "resource" that you must pass to other functions that want to operate on that file. It's the operating systems way of saying, "here is a safe handle you can use to work with this thing". Let's take a look at the socket_create function itself. This is the function that acts like installing a phone in your house.

socket_create()
resource socket_create ( int domain, int type, int protocol )

When we make a call to socket_create() we are passing in 3 required parameters as you can see above. A typical call to socket_create() will look like this:

  1. $mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

Let's examine this function call. The first parameter you see is AF_INET. AF = Address Family and INET basically means Internet. So it's the internet's address family. 99.9% of the time this is the parameter you'll want to use. This allows you to use UDP or TCP connections to communicate with computers. You could also use the option AF_UNIX, which means the Unix Address Family which would allow you to talk to processes running inside the unix system. So once again, just memorize AF_INET and you should be all set :)

The 2nd parameter you see there is "SOCK_STREAM". SOCK_STREAM is a constant that tells the socket_create function to use a TCP connection. If you were to be using UDP sockets you would put SOCK_DGRAM as the parameter. You could also use SOCK_RAW if you wanted to craft your own layer of transport. Alot of gaming companies do this to get the speed of UDP but at least some acknowledgement that the msg arrives like TCP, so it's sort of a TCP/UDP hybrid. That is not for the faint of heart however so we'll stick with TCP for this example.

The 3rd parameter is SOL_TCP which says just use Socket Layer TCP pretty please.

Step 2

If you remembered the steps above you'd see we now have to "Plug in the phone to the phone jack - socket_bind()". This effectively takes the socket resource that socket_create gives us and locks it into a specified port. So we first said "hey operating system, give me a cable I can use to get to the network". The operating system, said "sure, here ya go" if everything went error free and then we tell it "ok operating system, here is that cable you gave me, why don't you go plug it over there on port 10000 so I can start talking to people!". So now with the socket_bind call we're actually telling the OS to marry our application with the port number we tell it. Basically "hey Jack, anything that wants to talk over port 10000 wants to talk to me, so just send me the data.".

  1. socket_bind($mysock, "127.0.0.1", 10000));

The first parameter is the resource variable that we received when we created our socket which is $mysock. This holds a resource to that bound socket so the OS knows which connection we're passing around to all these functions. The 2nd parameter is the IP address we wish to bind to. In this case it's our local IP address 127.0.0.1. The final parameter is the port which is 10000. Now our socket is "plugged in" to the operating system.

Step 3

So we created our socket, bound it to the operating system on port 10000 and now all we have to do is power it up and get ready to start listening for someone to call us! "Turn the power to the phone on - socket_listen()". What this function does is basically tell the Operating System you've done the grunt work of setting up your socket and now you're all ready to start getting phone calls. It also let's you define how big your waiting cue is. The 2nd parameter to socket_listen is the "backlog" or how many connections should we queue up while we're waiting to deal with another connection. It's very much like calling a busy company's main telephone number. If you call while they're trying to help someone else the receptionist will pick you up and say "please hold". They'll put you in the holding cue and you'll be a little flashing light on her phone board. If too many people call and there's no more hold spots to fill, you can't get through to that company anymore. Much like a socket will start dropping incoming connections if the cue is full. When she's done with that guy, she picks you up and starts talking to you which frees up another holding spot.

  1. socket_listen($mysock, 5);

You can see we again pass in the resource handler which is $mysock. We also pass in the number 5 which again means. "While I'm on the phone with someone, you can put up to 5 people on hold until I'm done servicing this one".

Putting it all together

Let's put some basic socket code together to create a very basic socket server. We won't add error checking in this example. We'll save that for the next task.

  1. #!/usr/bin/php -q
  2. <?php
  3. $address = "10.139.17.143";
  4. $port = "10000";
  5.  
  6. /* create a socket in the AF_INET family, using SOCK_STREAM for TCP connection */
  7. $mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  8.  
  9. socket_bind($mysock, $address, $port);
  10.  
  11. socket_listen($mysock, 5);
  12.  
  13. $client = socket_accept($mysock);
  14.  
  15. // Read the input from the client &#8211; 1024 bytes
  16. $input = socket_read($client, 1024);
  17.  
  18. $output = "thanks for connecting, you wrote: ".$input."\r\n";
  19.  
  20. // Display output back to client
  21. socket_write($client, $output);
  22.  
  23. socket_close($client);
  24.  
  25. socket_close($mysock);
  26. ?>

Let's take a look at some new lines of code we added here. the first line is the "she bang" line telling the operating system where it can find our PHP executable. Since we aren't going to use the webserver, we must tell it what will execute this script. Put in the path to where your php executable lives. We create our socket, bind it and listen as we previously discussed. Now we're all ready to receive connections and we let the socket_accept function do that for us. So the call to $client = socket_accept($mysock); gives us the $client variable which is a resource to the currently connected user. socket_accept only takes one variable which is the new client connection so that one is easy. We can now start reading what this client is sending us, storing it in the $input variable. We pass in the $client's resource variable along with 1024 which means "Read in the first 1024 bytes of their message". We then take that input and output our own message letting the user know what they've typed. We close the sockets and the program exits. This server handles one client and then dies, not very useful but its the bare minimum of a socket server.

Now let's start our socket server and make a connection to it. Open a command prompt and execute your server. If we saved this file as app_server.php we'll chmod it to 777 to make it executable, then we'll start it with ./app_server.php
It should now be hanging there waiting for a connection.
Now you should be albe to open up another command prompt and type in: telnet 127.0.0.1 10000


Which means open up a session to my local machine on port 10000. You're trying to connect to your socket server. If all goes well you can type in a message, hit enter, and the socket server will reply a message back to you.

This is by no means a socket server that should be used on a web site but again it is the bare minimum you can do to reply to a client. Next section we'll start beefing this puppy up and making it into a more robust socket program.