Приглашаем посетить
Набоков (nabokov-lit.ru)

Section 20.1.  Sockets

Previous
Table of Contents
Next

20.1. Sockets

While it is out of the scope of this book to go into detail about network infrastructure, you at least need to know what protocols, ports , and sockets are. Protocols are like languages, defining how two computers can talk to each other, and there are hundreds of protocols to perform all varieties of operationsthere is a protocol for file transfer (File Transfer Protocol, or FTP), a protocol for transferring web pages (Hypertext Transfer Protocol, or HTTP), a protocol for network management (Simple Network Management Protocol, or SNMP), and many more.

Each protocol has a set of ports that it uses, which are theoretical openings in your computer's Internet connection that clients can connect to. They are numbered 1 to 65535, of which the first 1023 are considered reserved for administrative users. By default, your PC "listens" to no ports, meaning that it ignores all incoming connections. However, if you run a web server, it will open up port 80this is the port for HTTP, where your web server will listen for requests for web pages. Many of the first 1023 ports are used already, which means if you want to use a port for a new service you have written, it is best that you use a number above 1024.

Sockets are the literal connectors between a port and a program, sort of how a plug socket connects an appliance to the electricity grid in your house. Management of sockets in PHP comes in two flavors: easy and hard. As per usual, the easy option is not as flexible as the hard option, but it is much faster to get started with. We are going to be covering both here, because both have their own uses.

20.1.1. Sockets Are Files

The simplest way to work with sockets is by using them as if they were files. In fact, if you are using Unix, sockets actually are files, whereas in Windows this behavior is just emulated.

PHP works the same way as Unix, which means you can fread( ) and fwrite( ) to sockets as you would a normal file. For example:

    $fp = fsockopen ("slashdot.org", 80);

    if ($fp) {
            fwrite($fp, "GET / HTTP/1.1\r\nHOST: slashdot.org\r\n\r\n");

            while (!feof($fp)) {
                    print fread($fp,256);
            }

            fclose ($fp);
    } else {
            print "Fatal error\n";
    }

The fsockopen( ) call above opens a server on the port we specify, then waits for us to specify what to do with it. Using this function, you could send a hand-crafted HTTP request to the server. In contrast, the fopen( ) remote file handler uses PHP's stream functionality to automatically connect to the server and send the HTTP request using the GET methodthere is no flexibility.

As it stands, we open a socket for server slashdot.org on port 80; then, after checking the fsockopen( ) call has not returned false to signal failure, we write a HTTP GET request to the connection. Our HTTP request has two lines: first, we send the GET request using fwrite( ), asking for /, which is the root of the server. Second, we specify that we want to read from the host slashdot.org, which is a requirement for virtually hosted machines and HTTP 1.1.

With the HTTP request sent, we just need to wait for the response (the web page). This is done using a while loopwhile there is more to be read from the file (socket), we fread( ) in another 256 bytes and print it out. Once we are at the end of the "file," we close the socket and end the script.

Using fopen( ) would make the socket open line shorter, at the expense of flexibility. For example, the above script could be rewritten to specify that we are able to receive compressed content:

    $fp = fsockopen ("slashdot.org", 80);

    if ($fp) {
            fwrite($fp, "GET / HTTP/1.1\r\nHOST: slashdot.org\r\n
                    ACCEPT-ENCODING: gzip\r\n\r\n");

            while (!feof($fp)) {
                    print fread($fp,256);
            }

            fclose ($fp);
    } else {
            print "Fatal error\n";
    }

Slashdot is set up to serve compressed content when requested, so it will respond to our custom request with the compressed web page.

Section 20.1.  Sockets

If you liked persistent database connections, you might also like persistent socket connectionsthe function pfsockopen( ) takes the same parameters as fsockopen( ), but it remains open over requests.


20.1.2. Creating a Server

The server socket system starts with socket_create_listen( ), which takes a port number to listen on as its only parameter. This function creates a socket, binds it to the port you specify, and returns a pointer to the socket it created or false if it failed. You will need the socket resource it returns for later functions, so you should always save it in a variable. If the function fails, it is probably because the port you specified is already being used, or because you have insufficient privileges to open the port.

The socket_accept( ) function takes the return value of socket_create_listen( ) as its only parameter, and returns a client connectionsomeone who connected to our port number. It works by examining the queue of people waiting to be served, and taking the first client from there. If there are no clients waiting to be served, socket_accept( ) will wait ("block") until a client does become available, at which point it will return that.

You need to provide two parameters to the socket_write( ) function: the client to write to and the value you want to write. This data is then sent through our socket to the client, as you would expect. Its partner, socket_read( ), also takes two parameters, which are the connection to read from and the number of bytes to read. By using socket_write( ) and socket_read( ) together, you can interact with clients connecting to your socket.

Here is an example script that creates a ROT13 server when people connect to it and send text, it responds with the ROT13 equivalent of their text:

    $socket = socket_create_listen("12345");

    if (!$socket) {
            print "Failed to create socket!\n";
            exit;
    }

    while (true) {
            $client = socket_accept($socket);
            $welcome = "\nWelcome to the Amazing ROT13 Machine.\n
            Type '!close' to close this connection, or type '!halt'
            to halt the server.\n";

            socket_write($client, $welcome);

            while (true) {
                    $input = trim(socket_read ($client, 256));
                    if ($input =  = '!close') {
                            break;
                    }

                    if ($input =  = '!halt') {
                            socket_close ($client);
                            break 2;
                    }

                    $output = str_rot13($input) . "\n";
                    socket_write($client, $output);
                    print "Them: $input, Us: $output\n";
            }

            socket_close ($client);
    }

    socket_close ($socket);

Because this is going to serve data over a potentially infinite length of time, it is important that you execute that script using the CLI SAPI, not your web browser. Once you have it running, bring up a new command-line window and enter the following: telnet localhost 12345.

That should launch your telnet program, which is useful for forming simple connections to servers. All being well, you should receive the welcome message from the ROT13 servertry it out with a few words, then type !shutdown to finish. If you have followed correctly so far, you should see something like Figure 20-1.

Figure 20-1. Using telnet, we can connect to the ROT13 server and convert text by typing it in
Section 20.1.  Sockets



Previous
Table of Contents
Next