DEV Community

loading...
Cover image for PHP Blocking Socket

PHP Blocking Socket

aldora713 profile image ShakalakaB Updated on ・3 min read

I have been interested in asynchronous programming, always want to find out what happens behind the screen. I searched online, and noticed 'blocking socket' is a topic that can't be walked around. And following is what I understand after some code experiments.

Blocking Socket

First, what is socket? The PHP official manual says it's an endpoint for communication. Still like a definition in mist for me, so I mimic the online example to see how 'socket' works. Following is an example for blocking socket.
In order to communite, we need a 'server', who waits for a client's message and a 'client', who tells server what does it need, then the server would answer.

server

$host = "127.0.0.1";
$port = 10000;

set_time_limit(0);

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

$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");

$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");


do {
    $spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
    do {
        $input = socket_read($spawn, 1024) or die("Could not read input\n");

        $input = trim($input);
        echo "Client Message : " . $input . "\n";

        $response = 'received' . "\n";
        socket_write($spawn, $response, strlen($response)) or die("Could not write output\n");

        if ($input == 'quit') {
            break;
        }
        if ($input == 'shutdown') {
            socket_close($spawn);
            break 2;
        }

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

Basically, I create a socket that listens on port 10000. With socket_accept(), it would just wait until a client connects with it. During the wait, the program doesn't have the control until connection is made or an error happened, and this is what 'blocking' means. Once it gets connected, it would wait for the client's message with socket_read(), in blocking mode again. When the message received, it would respond to the client with socket_write. If it receives 'quit', it ends the connection, and wait for another client to connect. If 'shutdown', the server stops the connection and close itself. If none of these, it goes into another loop and wait for next message from client.
Notice: trim() the input from client which contains \n, and add \n to the end of response. (I would talk later why this is needed)

client

if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}

if (socket_connect($sock, '127.0.0.1', 10000) === false) {
    echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}

do {

    $stdin = fopen('php://stdin', 'r');
    $msg = trim(fgets($stdin));
    socket_write($sock, $msg, strlen($msg));

    if (false === ($buf = socket_read($sock, 2048, PHP_NORMAL_READ))) {
        echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
    }

    echo "response: $buf \n";

} while (true);


// close socket
socket_close($sock);

I create a socket as client, and connect it with the server I created. Then the client reads the input from php://stdin and sends it to the server, and get the response. The reason I add \n at the end of response string from server, is because the PHP_NORMAL_READ in socket_read(), PHP_NORMAL_READ means socket reading stops at \n or \r. Without \n at the end, the client can't get the response.

One problem with the server is that, it can only communicates with one client one time. If one more client tries to connect with it, the connection would never be made unless the another close the connection. In PHP Non-blocking Socket I would introduce a solution for this - non-blocking socket.

Discussion (0)

Forem Open with the Forem app