Introduction to Socket Programming with PHP

Are you one of those sorry souls who has desperately tried to learn network programming in C, but never had the stamina to tame the wild beast? I was for a long time until I finally decided that I had to learn it -- not only for my own satisfaction, but because I bumped into a problem that required some network programming. After a few sweaty nights, I became completely overwhelmed. Then I realized that my favorite programming language of all time, PHP, included a basic socket implementation. Hallelujah! I was saved!

While PHP's primary goal is to be a high-quality programming language for developing web-based applications, it has many neat features that could convince you to use it for other tasks as well -- for example, network programming.

Understanding sockets

What PHP unfortunately won't do for you is give you a basic understanding of what sockets really are, and how you can use them to create communication between two computers. So we'll have to go through that part ourselves. It's really not that hard, and hopefully this article will make it even easier.

You know what a network is, right? Know what a socket is? Not really? Sockets are just an abstraction of a low-level feature of the operating system. However, we don't need to go that deep to use sockets in our programs. We just need to get a basic understanding of how the socket philosophy works.

To explain this, I'll compare the process to a videogame, a game that resembles the real world quite closely, except that in the game all computer networks are organized by small men. You can control these small men to do exactly what you want, but there is a drawback. These men don't have any intelligence of their own -- they will do exactly as they are told, no matter how wrong that happens to be.

Figure 1: Controlling a network with small men.

I think we need a description of the game -- what are the goals here? To begin with, you need to make one man in "Computer I" go into the network connection and wait for some data to arrive. When the data does arrive, he's ready to open the hatch to let the data in. When this data comes through the hatch, someone has to lead it to the correct destination inside the computer. However, if you let the man in charge of the hatch do that job as well, who would make sure that the hatch is opened if additional data wants to get in?

There's actually a really simple solution to this problem: Just ask another man to lead whatever came in through the hatch to its destination inside the machine. In doing this, you are letting the first man continue to concentrate on his hatch job.

But we're not done yet: You also have to make one of the men in Computer II go to the hatch on his end to make sure the hatch is opened when something wants to get out. I'll play the first game, so you can see how it works.
I start out by pushing a few buttons, and move the joystick around and voilà -- we have Figure 2.

Figure 2: Here everything is in place.

But what is this?! Where's the third man? Take it easy, he'll be there. But wouldn't it be a waste of good working power to just let him stand there until something arrives? Wouldn't it be better to let him continue doing whatever it is he's doing and call for him when we actually have something for him to do?

After some more pushing, slamming, and banging around on the controls, I've told Computer II that I need to get some data, and have directed the man in Computer II open the hatch so the data can get out. In Figure 3, the data is on its way.

Figure 3: Data on its way!

As you can see, a chunk of data has now passed through the hatch of Computer II, and is on its way to "Computer I" (and don't wonder how that large chunk came through the tiny hatch!). This is coming along pretty well, just move the controls ... like ... that ... and if I push this ... and ... Ah! There you have it:

Figure 4: Data has arrived!

Here, I have managed to get the data from Computer II, send it through the network connection, and then into Computer I. I also called for a second man in Computer I to take care of the data. As you can see, he's just about to get the data in place. I must say, I'm pretty satisfied with myself.

Sockets programming in PHP

In the game, the small men were actually network sockets, and the controls represented my favorite programming language -- PHP!

The network sockets support in PHP doesn't include the most advanced features (yet) like the C implementation does, but it's probably enough for 95 percent of all network applications, and that's not bad at all. Also, you'll be able to write real network applications using such an easy-to-use language as PHP. Let's look at a simple TCP server. See listing 1 here.

Actually, the similarities between this program, and the made-up game we looked at earlier are quite clear. Let's discuss this for a moment. First, on line 8, we use set_time_limit(0) to tell PHP that we want to be able to wait for connections for an unlimited amount of time. This is the same as telling the men to wait by the hatch forever (or at least until we explicitly tell them to go away from there).

On lines 11 through 15, we create a new socket. This is known as the global socket and will be the one that checks for incoming connections. (In the analogy, this socket is represented by the man in control of the hatch in Computer I.) For this, we use the socket() function, which takes a total of three arguments. However, I won't try to explain these parameters, and then call this article an introduction to network programming. By the time you need to specify any other arguments than the ones we use here, you'll be quite into network programming already. However, one thing that can be good to know is that the second argument, SOCK_STREAM declares that we want to use the
TCP protocol (in contrast to UDP).

On lines 18 through 22, the newly created socket is bound to an IP address and a port. Since we're going to run this program on our local machine only, we use 127.0.0.1 as the IP address. The port we use, 10000, is picked at random. You can actually use any port between 1024 and the 65535 that isn't already in use. To draw a parallel to the analogy -- this is the same as telling one of the small men which network connection (hatch) to control, and what specific network data he is responsible for. If a packet arrives, which claims to be destined for port 10000, our small man knows that he is the one to take care of it (Yes, this may sound weird, but the small men actually can speak to the data packets!).

With the introduction of ports, you've probably already understood that there can be many men waiting for something to arrive at the same hatch. The port where the data is sent decides if one particular man should take care of the incoming data or not. So, our man will only care about the data that's going to port 10000.

Until now, we've just informed the man of what he should do, but we haven't really sent him instructions yet. This is done on lines 28 through 31 where we tell the man move from his sofa and get to the hatch. On lines 34 through 38, we also tell him stay there and open the hatch if it's needed. In programming terms, the accept_connect() function will wait until a connection arrives. So, the program will stop executing here until we use telnet on it a little later. Also note that when a connection is detected, accept_connect() will create another socket, called $msgsock, which will handle the communication with the connecting side. This is the third man that showed up in Figure 4 (he took care of the incoming data).

On lines 41 through 46, we send the visitor our welcome message using the write() function. Note that this is done by $msgsock because $sock is busy with his hatch, remember? At this stage, the accept_connect() function has already detected a connection, and therefore the execution of the script has reached this far. Or, in the analogy, the man saw something coming, opened the hatch, and asked the packet where it was going. The packet answered "port 10000", so he let it in and passed it to his helper, $msgsock.

On lines 49 through 54, something quite interesting happens. Here, we tell the second man, $msgsock, to go and wait at the hatch as well. This is to make sure he is ready when $sock lets in something he needs to take care of. In programming terms, we use read() to read data from our connection. However, for us to be able to receive any data, it first has to be sent from the other end. Like accept_connect(), the read() command will wait until something happens. When data has arrived for port 10000, the second man, $msgsock, will take it and show it the way to the $buf variable. So, we now have that data in $buf and can send back a nice reply on lines 57 through 61. Again, $msgsock will take care of this, and $sock will just open and close the hatch.

The last thing we do in this script is tell both men, $sock and $msgsock to go home and take a rest (lines 64 and 67). Or in more technical terms, we close both sockets and the network connection.

Testing our TCP server

Okay, it's time for testing -- always the most exciting part. However, before you try to execute the script, make sure you have the right permissions on it:

chmod 755 lst01.php

Also make sure that the first line of the script points at your PHP binary. Then, start the server:

./lst01.php

(If you get an error saying that the socket() function is undefined, you need to get into your PHP source directory, run ./configure --enable-sockets, and then recompile and reinstall the PHP binary by running make && make install.)

Now, open another terminal, and issue the following command:

telnet 0 10000

This means you want to establish a telnet connection to your local machine, and you want to use port 10000. If everything is okay, you should now get the following output:

Isn't that cool? It's not very advanced, but we actually created a real network connection and exchanged some information through it.

Summary

In this article, you learned how to exchange data between two computers using network sockets. I hope you found
the figures and explanations useful. The key to becoming a successful programmer is to understand what is actually happening behind a certain function call. When you can do that, you will be able to truly take control of your program.

Remember, network programming is all about sending and receiving data over a network connection. We did both today, so what's stopping you?

Daniel Solin
is a freelance writer and Linux consultant whose specialty is GUI programming. His first book, SAMS Teach Yourself Qt Programming in 24 hours, was published in May, 2000.