Задать вопрос
  • Прием потока данных через TCP сокет на PHP?

    @galaxy
    Задебажил немного, вот рабочий (вроде) вариант:

    define('EAGAIN', 11);
    
    $socket = socket_create_listen(1234, SOMAXCONN) ;
    socket_set_nonblock($socket);
    
    $clients = array();
    
    while(1) {
        usleep(300000);
        $client = @socket_accept($socket);
        if($client) {
          socket_set_nonblock($client);
          $clients[] = $client;
          socket_getpeername($client, $peer);
          echo "$client ($peer) connected\n";
        }
        reset($clients);
        while(list($i,$client) = each($clients)) {
            $data = socket_read($client, 4096);
            if($data === false && socket_last_error() != EAGAIN) {
                echo "error reading from $client: " . socket_strerror(socket_last_error()).", disconnecting\n";
                socket_close($client);
                unset($clients[$i]); }
            elseif($data!="") {
                $data = trim($data);
                socket_getpeername($client, $peer);
                echo "$client ($peer) says: $data\n";
                if(strtolower($data)=="exit") {
                    socket_close($client);
                    socket_close($socket);
                    die("Aborted by user");
                }
            } elseif ($data === "") {
                echo "$client ($peer) disconnected\n";
                socket_close($client);
                unset($clients[$i]);
            }
        }
    }
    
    


    Следующие моменты исправил:
    1. После accept клиентский сокет надо делать неблокирующим: socket_set_nonblock($client);
    у вас скрипт, видимо, постоянно висел на read'e
    2. socket_read на неблокирующем сокете возвращает ошибку с кодом 11 (EAGAIN), если нечего читать, что учтено в коде.
    3. Сигналом того, что соединение закрыто клиентом, является отсутствие ошибки на read и прочитанная пустая строка: elseif ($data === "")
    (в мануале по php ерунда, честно говоря, написана)
  • Прием потока данных через TCP сокет на PHP?

    @galaxy
    А покажите весь скрипт, если не сложно. И кстати, тут есть тег <source>
  • Прием потока данных через TCP сокет на PHP?

    @galaxy
    Нет, не надо, они все (вместе с серверным) на одном локальном адресе сидят.
  • Прием потока данных через TCP сокет на PHP?

    @galaxy
    Вы писали, что проблема у вас именно, когда строки с socket_close нет, из чего я и исходил. Закрыть он, конечно, может не успеть, особенно, если клиент не ожидает этого и со своей стороны закрывать ничего не собирается.

    TIME_WAIT — это нормально, никуда не деться от них. Не забывайте про SO_REUSEADDR и проблем быть не должно.

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

    Да, про socket_read(), конечно так. Reset не нужен, foreach его все равно сделает.

    И да, я свои примеры, естественно, не тестировал :)

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

    Так, в примере с селектом я делаю socket_read($fd, 4096) и перехожу к обработке данных. По идее никто не гарантирует, что я так вычитаю сообщение целиком (на это можно только надеяться, если сообщение достаточно короткие). По-хорошему, надо как-то договариваться о длине сообщения и читать из сокета (через select) пока не наберется эта длина. Для сообщений переменной длины можно ее передавать перед самим сообщением (как первые 4 байта пакета, например).