Может ли PHP асинхронно использовать сокеты? - PullRequest
20 голосов
/ 16 сентября 2009

Типичная функция сокета PHP синхронна и останавливает поток при ожидании входящих соединений и данных. (например, socket_read и socket_listen)

Как мне сделать то же самое асинхронно? поэтому я могу отвечать на данные в событии, полученном с данными, вместо того, чтобы опрашивать данные и т. д.

Ответы [ 4 ]

18 голосов
/ 16 сентября 2009

Да, вот для чего socket_set_nonblock(). Ваш код взаимодействия с сокетом должен быть написан иначе, принимая во внимание специальные значения, которые предполагают коды ошибок 11, EWOULDBLOCK и 115, EINPROGRESS.

Вот несколько вымышленных примеров кода из цикла опроса сокета синхронизации PHP, как было запрошено:

$buf = '';
$done = false;
do {
    $chunk = socket_read($sock, 4096);
    if($chunk === false) {
        $error = socket_last_error($sock);
        if($error != 11 && $error != 115) {
            my_error_handler(socket_strerror($error), $error);
            $done = true;
        }
        break;
    } elseif($chunk == '') {
        $done = true;
        break;
    } else { 
        $buf .= $chunk;
    }
} while(true);
4 голосов
/ 07 февраля 2014

Термин «асинхронный» часто неправильно используется в сетевом программировании. Для ввода / вывода асинхронный часто используется просто как другое слово для неблокирования. Это означает, что процесс может продолжаться до того, как вызов в сети API завершит передачу.

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

Другими словами, асинхронный ввод-вывод не является действительно асинхронным, если только несколько потоков не используются для одновременного выполнения нескольких операций чтения / записи / принятия - все сокеты будут вынуждены ожидать синхронного неблокирующего вызова, если у него есть данные быть прочитанным / записанным или иным образом не заблокированным, а чтение / запись большого файла может все еще занять секунды или даже минуты, если не прервано. Обратите внимание, что для этого потребуется идеальный поток между клиентом и сервером, иначе сам TCP прервет передачу. Например, сервер, отправляющий быстрее, чем клиент может загрузить, может вызвать блокировку записи.

Таким образом, со строгой точки зрения PHP не может выполнять асинхронную сеть, только неблокирующую. Короче говоря, выполнение процесса остановится, когда сетевой вызов сможет с пользой читать / записать и т. Д. Однако процесс будет продолжен, когда вызов не сможет с пользой прочитать / записать или заблокировать его иным образом. В действительно асинхронной системе процесс будет продолжаться независимо, а чтение / запись будет выполняться в другом потоке. Обратите внимание, что блокировка ввода-вывода может выполняться асинхронно, если она выполняется в другом потоке.

Более того, PHP не может выполнять управляемый событиями ввод-вывод без установки расширения, которое его поддерживает. В противном случае вам потребуется выполнить некоторую форму опроса, чтобы выполнить неблокирующий ввод / вывод в PHP. Код из Chaos был бы функциональным неблокирующим примером чтения, если бы он использовал socket_select.

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

4 голосов
/ 16 сентября 2009

Как мне сделать то же самое асинхронно? так что я могу отвечать на данные в данных полученное событие вместо опроса данные и т. д.

Вам нужно будет выполнить скрипт и выполнить stream_select, чтобы проверить, есть ли какие-либо данные для получения. Обработка и отправка данных обратно.

0 голосов
/ 16 сентября 2009

AFAIK PHP является строго однопоточным, что означает, что вы не можете сделать это асинхронно, потому что выполнение скрипта всегда линейно.

Прошло много времени с тех пор, как я это сделал, но, насколько я помню, вы можете только открыть сокет и продолжить выполнение скрипта после получения данных.

...