Как заставить pfsockopen() в php не плодить соединения?

Задача: научиться исользовать постоянные сокетные соединения (persistent socket connections) к TCP серверу. т.е. чтобы повторный запуск php скрипта не создавал новое соединение, а старался использовать предыдущее еще открытое соединение.

Но никак не получается так сделать.



Мой подопытный php (ver 5.3.3) скрипт:

<?php<br>
$fp = pfsockopen("tcp://127.0.0.1", "1337", $errno, $errstr, 60); <br>
if ($fp) { <br>
    var_dump($fp); // выводит "resource(1..2) of type (persistent stream)"<br>
    echo "ftell(): " . ftell($fp) . "\n"; // выводит всегда "0"<br>
    fputs($fp, time() . "\n"); <br>
    echo "readed data: '" . fread($fp, 10) . "'\n"; // выводит 10 принятых байт<br>
    fclose($fp); <br>
} <br>


Народ в интернетах обычно спрашивает на тему pfsockopen, мол «как бы сохранить handle сокета чтобы использовать его потом», на что им отвечают, что конечно же это невозможно. А pfsockopen(), вызванный с теми же атрибутами, якобы, должен сам возвращать handle уже открытого сокета.



В php мануале pfsockopen() есть заметка:

To see if it's really a new connection, or a reused one, you can use ftell() — and see if ther's been any traffic on the connection. If it's more than 0, then it's a reused connection.

Однако, мой ftell() упорно возвращает ноль, т.е. соединение создается новое.



Если выполнить netstat в терминале, тоже вроде бы видно, что соединения с каждым запуском скрипта добавляются:

$ netstat -t -a --numeric-hosts | grep 1337<br/>
tcp 0 0 127.0.0.1:1337 0.0.0.0:* LISTEN <br/>
tcp 0 0 127.0.0.1:51754 127.0.0.1:1337 TIME_WAIT <br/>
tcp 1 0 127.0.0.1:51648 127.0.0.1:1337 CLOSE_WAIT <br/>
tcp 1 0 127.0.0.1:51652 127.0.0.1:1337 CLOSE_WAIT <br/>
tcp 1 0 127.0.0.1:51654 127.0.0.1:1337 CLOSE_WAIT <br/>
tcp 1 0 127.0.0.1:51650 127.0.0.1:1337 CLOSE_WAIT <br/>
tcp 1 0 127.0.0.1:51646 127.0.0.1:1337 CLOSE_WAIT <br/>
tcp 0 0 127.0.0.1:51752 127.0.0.1:1337 TIME_WAIT <br/>
tcp 1 0 127.0.0.1:51644 127.0.0.1:1337 CLOSE_WAIT <br/>
tcp 0 0 127.0.0.1:51756 127.0.0.1:1337 TIME_WAIT <br/>
tcp 1 0 127.0.0.1:51656 127.0.0.1:1337 CLOSE_WAIT <br/>


В качестве сервера использую nodejs (ver 0.4.10) скрипт:

var net = require('net'),<br>
    server;<br>
<br>
server = net.createServer({allowHalfOpen: false});<br>
server.on('connection', function(socket) {<br>
    console.log('connection opened\n', socket);<br>
<br>
    socket.on("data", function(str) {<br>
        console.log("data: " + str + "\n");<br>
        socket.write("response\n");<br>
    });<br>
});<br>
<br>
server.on('close', function() {<br>
    console.log('connection closed\n');<br>
});<br>
<br>
server.listen(1337, "127.0.0.1");<br>


Переключение параметра allowHalfOpen не дает результата.



Как я запускаю php скрипт

Скрипт отрабатывает мгновенно, затем я его запускаю повторно. Пробовал при помощи:

  1. Через commandline вызов (гугление подсказывает, что и не должно работать)
  2. Модуль к Apache 2.2.16 (libphp5.so)
  3. Php5-fpm как fastcgi в nginx


Результат одинаковый.



Подскажите, куда копать дальше?

Спасибо!
  • Вопрос задан
  • 3551 просмотр
Пригласить эксперта
Ответы на вопрос 1
p4s8x
@p4s8x
Здесь явно присутствует мистика!

Чтобы узнать какое конкретно соединение используется нужно воспользоваться
stream_socket_get_name ($fp,false); // или true в зависимости от стороны
Но мне это ситуацию сильно не спасло)
ftell должен возвращать что-то типа позиции, но мне всегда выдавал 0 независимо от того, записалось что-то в сокет или нет.
Опытным путем было выяснено, что если соединение не трогать (примерно) 5 секунд, то используется новое, если соединение переоткрывать слишком быстро, то он либо создает новое, либо использует одно из уже созданных, но если это одно из созданных уже не использовалось в течении 5 секунд, то он следуя «правилу» создает новое. и эти 5 секунд это не значение таймаута.
Если например писать в сокет один символ, то сниффер покажет, что в одно соединение была произведена запись несколько раз.
Копаем дальше)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы