Сокеты в PHP

Тему сетевого программирования я еще не затрагивал, поэтому эта статья будет первым шагом в этом направлении. Сокеты, я бы сказал, – основа сетевого взаимодействия на прикладном уровне. С помощью этой технологии две программы, написанные даже на разных языках, могут обмениваться информацией, будучи достаточно удалены друг от друга. Нет, это не то, что изображено на картинке :) Это интерфейс обмена информацией сетевыми приложениями.

Итак, рассмотрим, как реализованы сокеты в PHP, хотя принцип работы с ними одинаковый во всех языках.

Сначала напишем простые клиент и сервер: сервер будет запускаться и ждать соединения, а клиент соединяться к нему и посылать какую-то строку (информацию). А затем я покажу на примере, как отправлять письмо, используя почтовый SMTP-сервер.

Не буду приводить здесь список сокетных функций в PHP. По мере чтения примеров далее Вы сами увидете их.

Пишем простой echo-сервер

Что значит echo-сервер? Это значит, что строка, посланная серверу, возвращается в ответ тому, кто ее послал – клиенту. Т.е. эхо получается по сути.

Сначала нам нужно создать дескриптор сокета:

echo 'Create socket ... ';
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
    throw new Exception('socket_create() failed: '.socket_strerror(socket_last_error())."\n");
} else {
    echo "OK\n";
}

Заметим, что я здесь использовал вызов socket_strerror(socket_last_error()), чтобы определить, в чем была причина ошибки, если вдруг возникла ошибка. Т.е. сначала мы определили номер ошибки с помощью socket_last_error(), а затем этот номер передали в socket_strerror, чтобы превратить его в текстовое описание ошибки.

Теперь нам нужно привязать созданный дескриптор к определенным адресу и порту машины, на которой он будет запущен. Обычно локальный адрес – 127.0.0.1, или localhost. Возьмем порт с номером 10001:

$address = 'localhost';
$port    = 10001;

echo 'Bind socket ... ';
if (($ret = socket_bind($sock, $address, $port)) < 0) {
    throw new Exception('socket_bind() failed: '.socket_strerror(socket_last_error())."\n");
} else {
    echo "OK\n";
}

Затем нам нужно включить прослушивание этого сокета:

echo 'Listen socket ... ';
if (($ret = socket_listen($sock, 5)) < 0) {
    throw new Exception('socket_listen() failed: '.socket_strerror(socket_last_error())."\n");
} else {
    echo "OK\n";
}

Цифра 5 здесь означает, что мы разрешим встать в очередь на подключение к этому адресу максимум пяти клиентам.

Когда клиент попытается установить с нами соединение, нам нужно его принять:

echo 'Accept socket ... ';
if (($msgsock = socket_accept($sock)) < 0) {
    throw new Exception('socket_accept() failed: '.socket_strerror(socket_last_error())."\n");
} else {
    echo "OK\n";
}

После этого дескриптор принятого соединения сохраняется в переменной $msgsock, с которой мы далее будем работать.

Ну а дальше мы просто общаемся с клиентом, отправляя ему данные …

$msg = "Hello, Client!";
echo "Say to client ($msg) ... ";
socket_write($msgsock, $msg, strlen($msg));
echo "OK\n";

… или принимая их от него:

echo 'Client said: ';
if (false === ($buf = socket_read($msgsock, 1024))) {
    throw new Exception('socket_read() failed: '.socket_strerror(socket_last_error())."\n");
} else {
    echo $buf."\n";
}

После всего этого «разговора» двух программ, нужно освободить ресурсы, вызвав socket_close:

echo 'Close socket ... ';
socket_close($sock);
echo "OK\n";

Приведу полный исходный текст нашего простенького сервера:

server.php

<?
    header('Content-Type: text/plain;');
    error_reporting(E_ALL ^ E_WARNING);
    set_time_limit(0);
    ob_implicit_flush();
   
    echo "-= Server =-\n\n";

    $address = 'localhost';
    $port    = 10001;

    try {
   
        echo 'Create socket ... ';
        if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
            throw new Exception('socket_create() failed: '.socket_strerror(socket_last_error())."\n");
        } else {
            echo "OK\n";
        }

        echo 'Bind socket ... ';
        if (($ret = socket_bind($sock, $address, $port)) < 0) {
            throw new Exception('socket_bind() failed: '.socket_strerror(socket_last_error())."\n");
        } else {
            echo "OK\n";
        }

        echo 'Listen socket ... ';
        if (($ret = socket_listen($sock, 5)) < 0) {
            throw new Exception('socket_listen() failed: '.socket_strerror(socket_last_error())."\n");
        } else {
            echo "OK\n";
        }

        do {
            echo 'Accept socket ... ';
            if (($msgsock = socket_accept($sock)) < 0) {
                throw new Exception('socket_accept() failed: '.socket_strerror(socket_last_error())."\n");
            } else {
                echo "OK\n";
            }
           
            $msg = "Hello, Client!";
            echo "Say to client ($msg) ... ";
            socket_write($msgsock, $msg, strlen($msg));
            echo "OK\n";

            do {
           
                echo 'Client said: ';
                if (false === ($buf = socket_read($msgsock, 1024))) {
                    throw new Exception('socket_read() failed: '.socket_strerror(socket_last_error())."\n");
                } else {
                    echo $buf."\n";
                }
               
                if (!$buf = trim($buf)) {
                    continue;
                }
               
                if ($buf == 'shutdown') {
                    socket_close($msgsock);
                    break 2;
                }
               
                echo "Say to client ($buf) ... ";
                socket_write($msgsock, $buf, strlen($buf));
                echo "OK\n";
               
            } while (true);
           
        } while (true);

    } catch (Exception $e) {
        echo "\nError: ".$e->getMessage();
    }
   
    if (isset($sock)) {
   
        echo 'Close socket ... ';
        socket_close($sock);
        echo "OK\n";
   
    }
?>

Вызовом функции set_time_limit(0), мы говорим интерпретатору, что скрипт может выполняться бесконечно, а не 30 секунд максимум, как по-умолчанию прописано в php.ini.

А вызовом функции ob_implicit_flush мы говорим ему, что выводить строки с помощью echo нужно сразу при их выводе, а не после полной загрузки страницы, как это делается по-умолчанию.

Как видите, в этом простом скрипте мы сохраняем строку, которую нам пришлет клиент, в переменной $buf, затем ее же отправляем обратно клиенту. При этом мы сравниваем эту строку с ‘shutdown’. Если это ‘shutdown’, то корректно завершаем работу сервера.

Теперь запустите этот скрипт в браузере и Вы должны увидеть следующее:

-= Server =-

Create socket … OK
Bind socket … OK
Listen socket … OK
Accept socket …

Т.е. сервер ждет подключения к нему клиента. Ну что ж, не будем заставлять его долго ждать и напишем для него клиента.

Пишем клиента

client.php

<?
    header('Content-Type: text/plain;');
    error_reporting(E_ALL ^ E_WARNING);
    set_time_limit(0);
    ob_implicit_flush();
   
    echo "-= Client =-\n\n";

    $address = 'localhost';
    $port    = 10001;

    try {
   
        echo 'Create socket ... ';
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if ($socket < 0) {
            throw new Exception('socket_create() failed: '.socket_strerror(socket_last_error())."\n");
        } else {
            echo "OK\n";
        }

        echo 'Connect socket ... ';
        $result = socket_connect($socket, $address, $port);
        if ($result === false) {
            throw new Exception('socket_connect() failed: '.socket_strerror(socket_last_error())."\n");
        } else {
            echo "OK\n";
        }

        echo 'Server said: ';
        $out = socket_read($socket, 1024);
        echo $out."\n";
       
        $msg = "Hello, Server!";
        echo "Say to server ($msg) ...";
        socket_write($socket, $msg, strlen($msg));
        echo "OK\n";
       
        echo 'Server said: ';
        $out = socket_read($socket, 1024);
        echo $out."\n";
       
        $msg = 'shutdown';
        echo "Say to server ($msg) ... ";
        socket_write($socket, $msg, strlen($msg));
        echo "OK\n";
       
    } catch (Exception $e) {
        echo "\nError: ".$e->getMessage();
    }
   
    if (isset($socket)) {
   
        echo 'Close socket ... ';
        socket_close($socket);
        echo "OK\n";
       
    }
?>

Т.е. наш клиент соединяется к серверу по адресу localhost:10001. Далее после вывода того, что ему сказал сервер («Hello, Client!»), он приветствует сервера: «Hello, Server!». Потом сервер отвечает ему тем же (он же echo-сервер :) ), а клиент отсоединяется от него, посылая команду shutdown.

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

-= Client =-

Create socket … OK
Connect socket … OK
Server said: Hello, Client!
Say to server (Hello, Server!) …OK
Server said: Hello, Server!
Say to server (shutdown) … OK
Close socket … OK

При этом вывод сервера выглядел следующим образом:

-= Server =-

Create socket … OK
Bind socket … OK
Listen socket … OK
Accept socket … OK
Say to client (Hello, Client!) … OK
Client said: Hello, Server!
Say to client (Hello, Server!) … OK
Client said: shutdown
Close socket … OK

Итоги

Фух, что-то статья получилась больше, чем я думал. Знаете, давайте я расскажу об отправке email с использованием сокетов в другой статье. Я знаю, что многие интересуются отправкой по SMTP с авторизацией, вот о ней и расскажу. А пока все. Удачных экспериментов с сокетами!




Читайте также:



 #  #  #  #  #  #  #  #  #  #

60 Ответов на “Сокеты в PHP”

  1. Skill00
    Июль 14th, 2008

    Даже не думал, что про сокеты можно вот так вот легко и в то же время подробно расписать) Отличная статья.

    P.S. Держи еще одну идею :) . С постов в этом блоге получился бы очень неплохой мануал, если собрать все это дело, например в pdf )

  2. Tyler
    Июль 20th, 2008

    спасибо, познавательно :)

  3. Atrius
    Июль 25th, 2008

    Я с вами полностью согласен.

  4. porfeus
    Сентябрь 18th, 2008

    Автор молодец! 5 баллов, нигде еще не встречал такой подробный и рабочий manual про сокетов в php -

  5. novice
    Сентябрь 18th, 2008

    2 porfeus: Спасибо! Рад такое слышать, т.е. читать :)

  6. kycuk
    Сентябрь 20th, 2008

    Спасибо, очень полезная статья.

  7. Prost
    Сентябрь 29th, 2008

    Статья действительно очень доступно написана. Жаль только, что у меня не получается на практике поработать с сокетами. Даже не знаю почему. У меня стоит Денвер-3. Может кто-то знает как включить поддержку сокетов?

  8. Porfeus
    Октябрь 10th, 2008

    Prost: “Может кто-то знает как включить поддержку сокетов” -Заходишь в php.ini, ищешь через поиск строчку ;extension=php_sockets.dll и разкоментируешь ее те убираешь впереди знак-;

  9. SarGun
    Декабрь 24th, 2008

    А цп неукого не нагружается??или так и должно быть?

  10. Григорий
    Декабрь 27th, 2008

    Спасибо!

  11. alexandr
    Январь 6th, 2009

    Супер. Большое спасибо автору

  12. novice
    Январь 6th, 2009

    Большое пожалуйста читателю :)

  13. slayersilence
    Март 14th, 2009

    странно не могу на 3м денвере работать с сокетами. разкоментировал ->скачал php_sockets.dll выдало что не хватает некого файла скачал -> php4ts.dll теперь возмущается что не может найти вход в ф-ю. не подскажете в чем могут быть проблемы?

  14. AL
    Апрель 14th, 2009

    Необходимо скачать и установить расширения для Денвера PHP 5: дополнительные модули.
    http://i-novice.net/gout/DkIQRQgcSxMSRxkBUl1CBBEYQ0FMRFRbUlhQBxUZSA0WA0pdRl4I/

  15. Константин
    Май 24th, 2009

    Очень информативно и полезною. Спасибо!
    Как раз то, что искал.

  16. Шэд
    Май 28th, 2009

    Автору спасибо, коротко, понятно и работает =))
    До этой статьи три мануала не осилил =)

  17. iliavlad
    Июнь 8th, 2009

    Ошибку в socket_create() надо сравнивать с false.

    manual
    socket_create() returns a socket resource on success, or FALSE on error.

  18. Дмитрий
    Июль 4th, 2009

    Уважаемый автор.

    Подскажите пожалуйста как запустить описанный вами сокет-сервер, в ситуации, когда это не единственный php-скрипт в системе?

    Т.е. предположим я взаимодействую с сервером написанном на php посредством обычных POST/GET запросов и хочу в каких-то особых случаях запускать сокет-сервер. Например так: получил команду от клиента на создание постоянного соединение, создал сокет, отдал клиенту порт и завершил текущий скрипт, а скрипт с сокет-сервером продолжает работать и закрывает сам себя когда он больше не нужен клиенту.

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

    Два вопроса в этой связи:
    1. Правильно ли я рассуждаю. Представляется ли вам такая инфраструктура использования сокета разумной и корректной.
    2. Не правильнее ли будет сразу получив команду запустить сокет-сервер в “автономное плавание” из скрипта обработки команды, с тем, чтобы клиент мог просто соединиться с сокетом, не запуская предварительно соотвествующий скрипт. И если это правильнее, то как это сделать?

    С уважением.

  19. novice
    Июль 5th, 2009

    Дмитрий, я думаю Вам стоит попробовать оба варианта – экспериментируйте и обязательно поймете, что лучше, а что нет. Если я правильно понял вопрос по второму варианту, то Вам нужно запустить скрипт сокетами в автономное плавание примерно следующим образом (тут описан запуск параллельного php-скрипта без передачи ему параметров через POST – передачу сами без труда сделаете):

    $fp = fsockopen($server_name, 80);
    fwrite($fp,
    “POST /script.php HTTP/1.1\r\nHost: “.$server_name.”\r\n”.
    “Content-Type: application/x-www-form-urlencoded\r\n”.
    “Content-Length: 0\r\n”.
    “Connection: close\r\n\r\n”
    );
    fclose($fp);

    И не забывайте про функцию ignore_user_abort.

  20. Дмитрий
    Июль 6th, 2009

    Novice, спасибо большое за советы. Вы позволите, я уточню детали?

    Если я правильно Вас понял, Вы предлагаете разместить код сокет-сервера, о котором я писал выше, в файле, который в примере называется “script.php”, верно? И приводите способ его “отправки в автономное плавание”.

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

  21. novice
    Июль 6th, 2009

    Насчет script.php – верно. Насчет запуска параллельного скрипта не с помощью сокетов – я думаю, что сокетами запускать проще всего. Возможно, есть и другие варианты, но, к сожалению, я не обладаю информацией о них. По поводу недостатка информации по работе с сокетами в PHP – если Вы программировали сокеты, например, на C++, то Вам не составит труда понять их и в PHP, т.к. принципы абсолютно те же.

  22. Дмитрий
    Июль 6th, 2009

    Все понял. Еще раз большое спасибо. Сокеты программировал и на плюсах и на Java так что с ними самими никаких трудностей :) Некоторые трудности с .. как бы это сказать красиво… с виртуальной машиной PHP :) Отсюда и вопросы.

  23. Павел
    Июль 8th, 2009

    Нет, это не то, что изображено на картинке :) Это интерфейс обмена информацией сетевыми приложениями.
    /* Там сокет под проц же нарисован какойто…. */

  24. ilyichzc
    Июль 23rd, 2009

    Подскажите, как заточить приведенный пример с сокетами под многопользовательскую схему. Я пробую и у меня не получается. Пытаюсь после принятия соединения на accept запихивать $msgsock в архив и работать на прием собщений опрашивая архив в цикле. В том же цикле опрашиваю и слушающий сокет. Но такая схема не работает. Не могу понять. Для каждого подключения новый слушающий нужен чтоли? Объясните пож. кто владеет информацией. Весь инет перерыл. На ПХП очень мало толкового. Спасибо.

  25. novice
    Июль 23rd, 2009

    Сокеты на PHP должны быть аналогичны сокетам на C++: создается “слушатель” с помощью socket_listen, затем socket_accept сидит в цикле и ждет. Как только к слушающему сокету подключается удаленный клиент, socket_accept создает “экземпляр” соединения и возвращает его, чтобы читать/записывать. Далее, если к этому же слушающему сокету соединяется другой клиент, для него так же socket_accept создает отдельный экземпляр и т.д. То есть получается, что слушающий сокет не нужно трогать – он нужен только для прослушки. А работать надо с ресурсом, который возвращается функцией socket_accept.

  26. ilyichzc
    Июль 24th, 2009

    Вот вот. Я так и пытаюсь делать. Но это не работает. Комп начинает тормозить через минуту работы проги. Память чем то заполняется, хотя у меня стоит проверка переполнения массива с экземплярами сокетов сообщений. Вот код поправьте кто может. Буду рад помощи.

    <?php
    error_reporting (E_ALL);

    /* Разрешить скрипту зависнуть в ожидании соединений. */
    set_time_limit (0);

    /* Включить неявную очистку вывода, и мы увидим всё получаемое
    * по мере поступления. */
    ob_implicit_flush ();

    $address = ‘192.168.1.4′;
    $port = 11000;

    if (($sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) {
    echo “socket_create() failed: reason: ” . socket_strerror ($sock) . “\n”;
    }

    if (($ret = socket_bind ($sock, $address, $port)) < 0) {
    echo “socket_bind() failed: reason: ” . socket_strerror ($ret) . “\n”;
    }

    if (($ret = socket_listen ($sock, 5)) < 0) {
    echo “socket_listen() failed: reason: ” . socket_strerror ($ret) . “\n”;
    }
    $current_conn = 0;
    $connections = array();

    socket_set_nonblock ($sock);

    $listen = true;

    while ($listen)
    {
    if (($new_connection = socket_accept($sock)) $msgsock)
    {
    if (FALSE === ($buf = socket_read ($msgsock, 2048)))
    {
    socket_close ($connections[$key]);
    unset($connections[$key]);
    }

    $buf = trim ($buf);

    if (empty($buf))
    {
    continue;
    }

    if ($buf == ‘q’)
    {
    socket_write ($msgsock, ‘You exit now!’, strlen ($talkback));
    socket_close ($connections[$key]);
    unset($connections[$key]);
    continue;
    }

    if ($buf == ’s’ || count($connections) > 10)
    {
    $listen = false;
    break;
    }

    $talkback = “PHP: You said ‘$buf’.\n”;
    socket_write ($msgsock, $talkback, strlen ($talkback));
    echo “$buf\n”;
    }
    }

    reset($connections);

    foreach ($connections as $key=>$msgsock)
    {
    $msg = “PHP: Server shuting down!\n”;
    socket_write ($msgsock, $msg, strlen($talkback));
    socket_close ($connections[$key]);
    unset($connections[$key]);
    }

    socket_close ($sock);
    exit();

    ?>

  27. elvis
    Июль 24th, 2009

    Подскажите, плиз: запускаю вышеприведенный скрипт сервера (http://i-novice.net/gout/DkIQRQgcSwgKU1YJX1xGFUxFVEYVUUcWSVFH/) и у меня выходит следующее:
    -= Server =-

    Create socket … OK
    Bind socket … OK
    Listen socket … OK
    Accept socket … OK
    Say to client (Hello, Client!) … OK
    Client said:
    Client said:
    Client said:
    Client said:
    Client said:
    Client said:
    Client said:
    Client said:
    ………… и т.д.

    Т.е. строка “Client said: ” выводится безконечное множество раз. В чем проблема?

  28. novice
    Июль 25th, 2009

    elvis, это значит, что сервер почему-то принял от клиента пустое сообщение (в коде server.php есть условие).

  29. ilyichzc
    Июль 25th, 2009

    Разобрался наконец. Вот рабочий пример многопользовательской схемы. Работает в одном потоке т.к. в WЦindows pcnctl не поддерживается. Прога криво останавливает сервер. Просто не успел подправить разрыв соединений. Нужно создать флаг завершения и отключать пользователей в цикле while($listen). В остальном работает и наглядно показывает как и что. Вот исходник:

    ———————————————————–

    <?php
    error_reporting (E_ALL);

    /* Разрешить скрипту зависнуть в ожидании соединений. */
    set_time_limit (0);

    /* Включить неявную очистку вывода, и мы увидим всё получаемое
    * по мере поступления. */
    ob_implicit_flush ();

    $address = ‘192.168.1.4′;
    $port = 11000;
    ///*

    if (($sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) {
    echo “socket_create() failed: reason: ” . socket_strerror ($sock) . “\n”;
    }

    if (($ret = socket_bind ($sock, $address, $port)) < 0) {
    echo “socket_bind() failed: reason: ” . socket_strerror ($ret) . “\n”;
    }

    if (($ret = socket_listen ($sock, 5)) < 0) {
    echo “socket_listen() failed: reason: ” . socket_strerror ($ret) . “\n”;
    }
    $current_conn = 0;
    $connections = array();

    socket_set_nonblock ($sock);

    $listen = true;

    while ($listen)
    {

    if (($new_connection = @socket_accept($sock)) 0)
    {
    $num = socket_select($read, $write, $exceptions, $timeout);
    echo(”changed sockets number = {$num}\r\n”);
    }

    // reset($write);

    if ($num > 0)
    {
    echo(”Changed sockets for reading “.count($read).”\r\n”);

    foreach ($connections as $key=>$s)
    {
    //$key = array_search($s, $connections);
    $can_write = array_search($s, $write);
    $can_read = array_search($s, $read);

    if ($can_read !== FALSE) $can_read = true;
    if ($can_write !== FALSE) $can_write = true;

    if ($can_write && $s === $new_connection)
    {
    $msg = “\nWelcome to the PHP Test Server. \n” .
    “To quit, type ‘quit’. To shut down the server type ’shutdown’.\n”;
    socket_write($s, $msg, strlen($msg));
    }

    echo(”Try read from socket {$key}\r\n”);

    if ($can_read && FALSE === ($buf = socket_read ($s, 2048)))
    {
    socket_close ($connections[$key]);
    unset($connections[$key]);

    echo(”Unable read from socket {$key} close conection! \r\n”);
    continue;
    }

    if ($can_read)
    {
    $buf = trim($buf);
    echo(”read ‘{$buf}’ from socket {$key}\r\n”);
    }
    else $buf = ”;

    if (empty($buf))
    {
    continue;
    }

    if ($buf == ‘q’)
    {
    if ($can_write)
    socket_write ($s, ‘You exit now!’, strlen ($talkback));

    socket_close ($connections[$key]);
    unset($connections[$key]);
    continue;
    }

    if ($buf == ’s’ || count($connections) > 10)
    {
    $listen = false;
    break;
    }

    $talkback = “PHP: You said ‘$buf’.\n”;

    if ($can_write)
    socket_write ($s, $talkback, strlen ($talkback));

    echo “$buf\n”;
    }
    }
    }

    reset($connections);

    foreach ($connections as $key=>$msgsock)
    {
    $msg = “PHP: Server shuting down!\n”;
    socket_write ($msgsock, $msg, strlen($talkback));
    socket_close ($connections[$key]);
    //unset($connections[$key]);
    }

    socket_close ($sock);
    //*/
    exit();

    ?>

  30. Derian
    Июль 30th, 2009

    Статья хорошая получилась.
    Только вот возникают вопросы по многопользовательской системе работы через сокеты.
    У меня стоит сервак в сети я запускаю на нем серверную часть и подключаюсь к нему по телнету, все ок.
    Но как сделать, чтобы с других компов я мог подключиться к этому сокету?

  31. ilyichzc
    Август 1st, 2009

    Смотри мой пост выше. У меня все работает. С трех компов коннектился. Удачи.

  32. Derian
    Август 3rd, 2009

    Твой пример не работает..

  33. metaluga
    Август 8th, 2009

    огромное тебе спс автор!
    действительно тикаво читать!

  34. ilyichzc
    Август 10th, 2009

    А что не работает в моем примере? Возможно какие то детали в коде вылетели при модерировании.. Так было с первым постом. Но там простые вещи, которые можно понять и поправить. Вроде отсутствия скобок или т.п.

  35. elvis
    Август 15th, 2009

    ilyichzc, исправь плиз, ошибки в твоем коде, если не сложно. Я попробовал сам исправлять, но мой Апач постоянно ругается – ошибка на ошибке. Кстати, твой код в формате Юникод.

  36. ilyichzc
    Август 15th, 2009

    Если уважаемая администрация позволит, то дам ссылку на скрипт в zip архиве. А то так и будет дырявый код.
    http://i-novice.net/gout/DkIQRQgcSwsXUVkCUksbExYZZXEuZBpMXEpDMQlVUwASRUpPW0M=/

  37. Logicm@n
    Август 21st, 2009

    Добрый день!
    Очень понравилась статья. Большее спасибо автору!

    У меня возник следующие вопросы. Получается, что для того, чтобы все работало, нужно, чтобы был запущен server.php. Тогда:

    как сделать так, чтобы он был постоянно запущен? Или какие механизмы есть, чтобы сервер запускался перед тем, как работать с сокетом?
    как запустить server.php? То есть я, например, открывал в браузере. А если мне не нужно выводить никакой информации, можно ли сделать как-то, чтобы “серверный” сокет как-то всегда находился в памяти?

    Спасибо!

  38. novice
    Август 24th, 2009

    Чтобы socket.php был постоянно запущен, Вы можете запустить его с помощью тех же сокетов:

    $fp = fsockopen($server_name, 80);
    fwrite($fp, “POST /server.php HTTP/1.1\r\nHost: “.$server_name.”\r\n”.”Content-Type: application/x-www-form-urlencoded\r\n”.”Content-Length: 0\r\n”.”Connection: close\r\n\r\n”);
    fclose($fp);

    При этом необходимо, чтобы на сервере директива PHP max_execution_time была установлена в 0, иначе выполнение server.php будет прерываться.

  39. ilyichzc
    Август 26th, 2009

    Не нужно открывать скрипт в браузере. Сделайте batch файл в котором пропишите:
    c:/PHP/php-cgi.exe -f d:/work/server/server.php

  40. Logicm@n
    Август 26th, 2009

    Спасибо за помощь!
    Решил написать службу, а в ней открывать сокет :)

    Еще раз благодарю за статью!

  41. ArtikZ
    Сентябрь 7th, 2009

    Было бы ваще супер, если бы еще была ссылочка на примерчик в зип(рар)-архиве… Скиньте плыз на мыло(artikz@ya.ru) т.к. временно пропадаю и не смогу ближайших пару месяцев войти в инет.

  42. Vsevolod
    Сентябрь 7th, 2009

    Не подскажите почему выводится ошибка:
    Fatal error: Call to undefined function socket_create() in /home/host800681/flexsdk.ru/htdocs/www/flexapps/fex/server.php on line 15

    для этой функции нужно что-то дополнительно ставить на сервер?

  43. ilyichzc
    Ноябрь 5th, 2009

    Вобщем начинал я с этого поста и в итоге написал игровой сервер. Под windows работает без нареканий, а под CentOS не могу запустить. Беда такая:
    Не хочет работать с mySql сервером. Коннект проходит без ошибок и первый запрос тоже. В первом запросе система проверяет созданы ли нужные таблицы и если нет, то создает их самостоятельно. Дак вот все последующие запросы получают “MySQL server has gone away”, хотя wait_timeout стоит приличный, да и запросы происходят сразу после запуска скрипта. Не подскажет ли кто как победить данную проблему т.к. я в никсах не специалист

  44. Vital
    Ноябрь 8th, 2009

    поведуйте, как в серверном скрипте узнать IP подключившегося клиента?

  45. Владимир
    Ноябрь 16th, 2009

    Возник такой вопрос. Как организовать множественное подключение? Т.е. чтобы 2 и больше клиента могли быть, и не могли отключать сервер. Что бы он всегда крутился в системе.

  46. AleXXXman
    Ноябрь 22nd, 2009

    Автор, огромное тебе спасибо:) Довольно подробно и на отлично объясненных примерах все написано! Я – новичек в php и эта статья для меня была очень полезна

  47. Denny
    Январь 15th, 2010

    Здравствуйте, у меня при прочтении статьи возник вопрос.
    Когда клиент отрубается от сервера, работа сервера прекращается. ка кже сделать. чтобы он дальше продолжал ловить подключения?

  48. alex
    Январь 16th, 2010

    В большинстве случаев сокеты используют для обращения к уже
    существующим серверам. Если будет желание, попробуйте раскрыть
    тему по обращению через сокеты к различным действующим серверам по
    различным протоколам. У Вас получается о сложном доступно.
    Успехов

  49. ilyichzc
    Январь 27th, 2010

    Vsevolod: Скорее всего у вас в php.ini не подключен модуль
    sockets.

    Отвечаю на вопросы: “Как сделать, чтобы сервер не отключался после отсоединения клиента?” и “Как обеспечить работу с множественными подключениями?” -
    Приведенный мной выше код обеспечивает обработку множества соединений без остановки в реальном времени. Единственное ограничение это цикл обработки одного клиента т.к. остальные все равно стоят в очереди. По этому цикл обработки одного соединения не должен быть очень долгим (например соединение с другим сервером для получения даных по http может занять несколько секунд, что скажется на других пользователях).
    Для того, чтобы сервер не останавливался его нужно запускать не из под апача как скрипт, инициируемый браузером, а как самостоятельную резидентную программу -демон, из командной строки. В UNIX обычно php myServer.php. В WINDWS путь к php\php-cgi.exe -f myServer.php. Для нормальной работы программа должна правильно демонизироваться. На эту тему есть достаточно информации в сети. Рекомендую поискать класс PhpDaemon. Он позволяет быстро путем наслодования создать собственный демон.

  50. ilyichzc
    Январь 27th, 2010

    Забыл добавить, что демонизация не обязательна. Программа, запущенная из командной строки и так будет работать пока ее не вырубят. Демонизация же позволяет отвязать процесс от конкретного окна и заставить работать на фоне. В PHP демонизация возможна только в POSIX системах, к которым windows не относится.

  51. MageMerlin
    Март 29th, 2010

    Спасибо большое. Занимаемся написанием игрового сервера Flash + PHP с сокетным соединением (не loadVars() – тоесть вечное нужно соединение). Пост неплохо помог разобраться в самых азах – долго не мог понять как можно вызывать из клиента сервер по IP если у нас server.php имеет вполне определенное имя скрипта. Сразу все встало на места в голове, когда прочел строчку о запуске сервера из браузера.

    Если не трудно ilyichzc – пожалуйста, выложите где-нибудь на народе/рапидшаре и т.д. архивчик со скриптом на предмет покопаться. По приведенной ссылке не грузится к сожалению.

    Автору поста – радует, когда такие подробные комментарии в тему уточняют сам пост. Это редчайший вариант блогосферы, обычно такое на форумах происходит. Респект!

  52. ilyichzc
    Апрель 3rd, 2010

    Исходника к сожалению не осталось. Есть законченый батлнет для мобильных телефонов. Но то штука комерческая и по этому не могу ее выдать, а выдерать что то оттуда нет времени. Причем начинал делать с этого поста. Многие хулят PHP, что мол медленный очень для таких задач. Я испытывал свой сервер 500 ми ботами, которые одновременно рвали его на части (запрашивали инфу друг про друга, про комнаты, создавали комнаты и т.п.), при этом сервер работал нормально и показал в худшем случае 0.9 миллисекунд задержки на цикл. Так что для первого проекта вполне не плохо, учитывая что разработка занимает не много времени.

  53. MageMerlin
    Апрель 5th, 2010

    Ок, да в принципе и не нужно. Во время освоения мануала и поста показало, что ваш пример почему-то сразу рвет коннект с сервером, telnet при подключении выдает что-то типа “подключение утеряно”. Видимо либо где-то побился кусок кода, либо элементарный баг в счетчике.

    А так улыбнуло, что хостер сам не знает, открыты ли у него порты наружу или нет.

  54. Jenya
    Апрель 12th, 2010

    2 ilyichzc:
    А немогли бы вы выложить “многпоточный скрипт” тот который приводили выше, а то при копирование он не работает, даже с корректировками. И ещё, клиента можно оставить того же что приводит novice или тоже нужен модифицированный?

  55. MageMerlin
    Апрель 24th, 2010

    Видимо, комментарий не прошел антиспам. Хороший, детально документированный (на английском) пример многопоточного (правильнее говоря обрабатывающего более 1 клиента) скрипта находится в комментариях на сайте php.net к функции socket_select() – точную ссылку не привожу чтоб антиспам пропустил. Там же есть мой комментарий с особенностями использования клиента на флеше. Также, есть куски кода на flasher.ru по ссылке forum/showpost.php?p=901346&postcount=7 (сами подставьте)

  56. MageMerlin
    Апрель 25th, 2010

    А вот я кой-чего не могу догнать. Что такое socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1); и зачем оно нужно? Такая строчка присутствует в примере кода. Я построил уже на этом примере сокет для игры в кости, все прекрасно работает. Но вот начал детально разбирать код – и так и не смог найти адекватного объяснения зачем это и что это.

  57. Денис
    Май 14th, 2010

    Спасибо за пример, очень помог. А вот как сделать когда 3 и д.т. клиента запущенно сразу, что-бы 1 клиент отправлял другим клиентам сообщения, я через массив замутил, но когда 2 человек просто рубит соеденение, массив не чистится :(

  58. Ilya Korovin
    Июнь 5th, 2010

    Статья супер! Так все просто и понятно про написано.

  59. Ilya
    Июнь 8th, 2010

    ilyichzc
    не могли бы вы выложить еще раз файлы?
    Очень нужен много поточный сервер.

  60. MK13
    Июль 15th, 2010

    Такой вопрос. При запуске на локальной машине серверная часть работает нормально. Подключаюсь к сокетам из софтины на дельфе. При установке скрипта на хостинге из вне подключиться не удаётся. Если же запустить простенький скрипт проверки открытых портов на том же хосте показывает что заданный порт открыт. В чём может быть причина что из вне достучаться до порта не получается?

Оставить комментарий


© 2008 - 2010 i-novice.net | Все права защищены.