Сокеты — введение

Ещё один вид транспорта в unix системах, про который я пока не успел ничего рассказать - это сокеты.

В переводе с английского, сокет - это штекер, т.е. элемент, позволяющий соединять между собой всякую фигню, например приборы.

Для лучшего объяснения работы сокетов, удобно использовать популярный в интернете пример с телефоном и телефонной станцией.

Где телефонная станция, словно сервер, держит соединения с сотнями или может тысячами различных телефонных аппаратов, а телефоны, эпизодически устанавливают соединение со станцией, и обмениваются своими данными.

Ровно такая же идея работает и в сокетах, с той лишь разницей что сокет - это интерфейс для доступа к памяти компьтера.

Сокеты подразделяются на два вида:

  • “Локальные” или “юникс-сокеты”
  • И “веб-сокеты” или ещё их называют “сетевые сокеты”

При этом локальные сокеты видны в файловой системе как файл, но при этом все данные сохраняются в локальной памяти на уровне ядра. А сетевые сокеты биндятся на сетевой порт, и слушают его, являя собой настоящий веб-сервер. (Вы ведь уже придумали что с этим можно сделать, да?)

Понятно, что и создание файла, и бинд порта может делать только один процесс, и его мы обычно называем сервером.
“Сервер” обязан запускаться раньше всех и создавать свой файл или слушать свой порт, повисая в бесконечном цикле.

После чего довольные клиенты должны обращаться к уже созданному файлу и записывать туда (читать оттуда) информацию, или слать невнятные сообщения на сетевой адрес с настоящим IP адресом и портом.

В реализации на php между сетевыми и локальными сокетами разница заметна только в коннекте. Во всём остальном они одинаковы.

Что, уже нетерпится попробовать? Тогда в бой! :-)

simple-server.php

// Создаём сокет, биндим и слушаем
// В случае если мы хотим создать интернет сокет (а мы хотим!)
// Мы должны прописать путь соединения примерно такой
// "tcp://127.0.0.1:8080" что значит мы биндим порт 8080 на локалхосте
$socket = stream_socket_server(
                                    "unix:///tmp/simple-socket",
                                    $errno,
                                    $errstr,
                                    STREAM_SERVER_BIND | STREAM_SERVER_LISTEN
                            );

if ( ! $socket )
{
    echo "$errstr ( $errno )\n";
}
else
{
    // Поступающее соединение от клиента принимаем
    while ( $conn = stream_socket_accept($socket) )
    {
        $data = "Московское время" . date("H:i:s")  . PHP_EOL;
        fwrite( $conn, $data );
        fclose( $conn );
    }
    fclose($socket);
}

simple-client.php

// Тут всё также tcp://127.0.0.1:8080
$socket = stream_socket_client(
                            "unix:///tmp/simple-socket",
                            $errno,
                            $errstr,
                            30,
                            STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT
                        );
if ( ! $socket )
{
    echo "$errstr ($errno)\n";
}
else
{
    fwrite( $socket, "HI" );

    while ( ! feof( $socket ) )
    {
        echo fgets( $socket, 1024 );
    }
    fclose( $socket );
}

Мне кажется что примеры слишком простые что бы их как-то комментировать или подробно расписывать.

Поэтому давайте в следующей статье попробуем связать демоны, сокеты, очереди, сигналы и ещё что-нибудь для интереса в одну работающую программу.