Coroutine Socket Client Support

Latest version: pecl install openswoole-22.1.2 | composer require openswoole/core:22.1.5

OpenSwoole has full support for using PHP Sockets or any package that is based off socket_create() like communication.

Hopefully you know that OpenSwoole is an asynchronous PHP framework and thus, everything must not perform blocking I/O operations. Thanks to coroutine support in Swoole, you can create and use PHP Sockets without blocking the process, coroutines enable the process to do other operations when waiting for long I/O operations to complete. This is all thanks to something called coroutine hooks also known as runtime flags.

If you haven't already you should read the documentation for coroutine hooks to understand how normal PHP Sockets can be used within a non-blocking coroutine environment.

You have to install OpenSwoole core library with composer require openswoole/core to use this feature.


Background

Before coroutine hooks were added OpenSwoole managed its own coroutine clients and there was a client for sockets, this client is no longer supported and should not be used today, you can find its old documentation here. This old coroutine socket client was deprecated in favor of using OpenSwoole coroutine hooks. You can read more about coroutine client history here.


Client Timeouts

All network requests (establish a connection, send data and receive data) may time out.

You can set timeouts when using native PHP sockets, refer to the timeout guide to understand how to setup timeouts.

Do not use set_time_limit() with sockets, it is not supported with OpenSwoole

Instead you should use socket_set_option() to set a timeout or make the PHP socket non-blocking and periodically poll the socket to check for requests.


Examples

To use native PHP Sockets you will require the OpenSwoole\Runtime::HOOK_SOCKETS hook.

Once OpenSwoole\Runtime::HOOK_SOCKETS has been enabled and when you are inside a coroutine context you can use the socket API without blocking the process:


Basic socket example with loop

<?php

Co::set(['hook_flags' => OpenSwoole\Runtime::HOOK_SOCKETS]);

// Inside the coroutine context container
co::run(function()
{
    echo "Inside the coroutine context\n";

    $address = '127.0.0.1';
    $port = 1234;

    // Create WebSocket
    $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
    socket_bind($server, $address, $port);
    socket_listen($server);

    $client = socket_accept($server);

    // Send messages into WebSocket in a loop
    while(true)
    {
        sleep(1);
        $content = 'Now: ' . time();
        $response = chr(129) . chr(strlen($content)) . $content;
        socket_write($client, $response);
    }
});

echo "Outside the coroutine context\n";

Native TCP Server PHP Sockets

<?php

// Enable all coroutine hooks
Co::set(['hook_flags'=> OpenSwoole\Runtime::HOOK_ALL]);

co::run(function()
{
    $socket = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr);

    if(!$socket)
    {
        echo "$errstr ($errno)\n";
    }
    else
    {
        while($connection = stream_socket_accept($socket))
        {
            fwrite($connection, 'The local time is ' . date('n/j/Y g:i a') . "\n");
            fclose($connection);
        }

        fclose($socket);
    }
});

Last updated on February 9, 2023