Pagina 1 di 1

WebSocket e PHP

Inviato: venerdì 6 maggio 2016, 20:24
da iJim
Sto cercando di scrivere una piccola applicazione in cui il client rimane in attesa di un evento da parte del server.
Sulla parte client utilizzo una WebSocket e sulla parte server utilizzo la socket tramite PHP.
Nella risposta effettuo l'handshake per la webSocket ma c'è qualcosa che non va!

Codice lato client

Codice: Seleziona tutto

function startConnection(){
    var message = 'Ciao';
    var port = 2518;

    // creazione websocket
    var websocket = new WebSocket("ws://localhost:"+ port +"/LipariStudios/tesiLaurea/sketchApps/22/server.php");

    websocket.onopen = function(evt) {
        console.log(evt);

        websocket.send(message);
        websocket.close();
    };
    websocket.onclose = function(evt) { console.log(evt); };
    websocket.onmessage = function(evt) { console.log(evt); };
    websocket.onerror = function(evt) { console.log(evt); };
};
Sul lato server

Codice: Seleziona tutto

// conf
//$host = 'localhost';
//$host = 'liparistudios.hostinggratis.it';
$host = '127.0.0.1';
//$host = '192.168.1.171';
$local = 'LipariStudios/tesiLaurea/sketchApps/22/server.php';   //  local
//$local = 'App/socketTest/01/server.php';   // remote
$data = 'risposta dalla socket';
$port = 2518;

$maxBufferSize = 2048;
$key = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)    or die("Failed: socket_create()");
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)   or die("Failed: socket_option()");
//socket_bind($socket, $host.'/'.$local, $port)             or die("Failed: socket_bind()\n");
socket_bind($socket, $host, $port)             or die("Failed: socket_bind()\n");

// attesa
socket_listen($socket,20)                                 or die("Failed: socket_listen()");

socket_accept($socket);

// connessione in entrata
while(true){
    $numBytes = @socket_recv($socket, $buffer, $maxBufferSize, MSG_WAITALL);
    if ($numBytes === false) {
        $sockErrNo = socket_last_error($socket);
        switch ($sockErrNo)
        {
            case 102: // ENETRESET    -- Network dropped connection because of reset
            case 103: // ECONNABORTED -- Software caused connection abort
            case 104: // ECONNRESET   -- Connection reset by peer
            case 108: // ESHUTDOWN    -- Cannot send after transport endpoint shutdown -- probably more of an error on our part, if we're trying to write after the socket is closed.  Probably not a critical error, though.
            case 110: // ETIMEDOUT    -- Connection timed out
            case 111: // ECONNREFUSED -- Connection refused -- We shouldn't see this one, since we're listening... Still not a critical error.
            case 112: // EHOSTDOWN    -- Host is down -- Again, we shouldn't see this, and again, not critical because it's just one connection and we still want to listen to/for others.
            case 113: // EHOSTUNREACH -- No route to host
            case 121: // EREMOTEIO    -- Rempte I/O error -- Their hard drive just blew up.
            case 125: // ECANCELED    -- Operation canceled

                echo "Unusual disconnect on socket " . $socket;
                // disconnect
                break;
            default:
                echo 'Errore sconosciuto ['. $sockErrNo .']: ' . socket_strerror($sockErrNo);
        }

    }
    elseif ($numBytes == 0) {
        // disconnect
        echo "Client disconnected. TCP connection lost: " . $socket;
    }
    else {
            $tmp = str_replace("\r", '', $buffer);
            if (strpos($tmp, "\n\n") === false ) {
                continue; // If the client has not finished sending the header, then wait before sending our upgrade response.
            }

            // handshake ////////////////////////////////

            // • prendi gli headers e lo componi come un array associativo e lo prendi dul buffer
            $headers = array();
            $lines = explode("\n",$buffer);
            foreach ($lines as $line) {
                if (strpos($line,":") !== false) {
                    $header = explode(":",$line,2);
                    $headers[strtolower(trim($header[0]))] = trim($header[1]);
                }
                elseif (stripos($line,"get ") !== false) {
                    preg_match("/GET (.*) HTTP/i", $buffer, $reqResource);
                    $headers['get'] = trim($reqResource[1]);
                }
            }

            // • prendi il protocolo   //  solitamente chat
            $subProtocol = (isset($headers['sec-websocket-protocol'])) ? $headers['sec-websocket-protocol'] : "";

            // • prendi il sub protocollo  //  solitamente super chat
            $extensions = (isset($headers['sec-websocket-extensions'])) ? $headers['sec-websocket-extensions'] : "";

            // • valore chiave 258EAFA5-E914-47DA-95CA-C5AB0DC85B11

            // • fai lo SHA-1 della key insieme alla chiave
            $webSocketKeyHash = sha1($headers['sec-websocket-key'] . $key);

            // • chr corrispondente ascii di un carattere
            // • hexdec da una stringa esadecimale ne ritorna il valore decimale

            $rawToken = "";
            for ($i = 0; $i < 20; $i++) {
              $rawToken .= chr(hexdec(substr($webSocketKeyHash,$i*2, 2)));
            }
            $handshakeToken = base64_encode($rawToken) . "\r\n";

            // • componi la chiave
//            Sec-WebSocket-Accept: $handshakeToken . $subProtocol . $extensions\r\n

            // • componi la risposta
            $handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken$subProtocol$extensions\r\n";

            // oppure
//            $handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: $handshakeToken$subProtocol$extensions\r\nSec-WebSocket-Protocol: chat";

            // • invia la risposta alla socket
            socket_write($socket,$handshakeResponse,strlen($handshakeResponse));

    }
}


socket_close($socket);
Da queste immagini si vede lo strano comportamento!
Immagine

Immagine

Re: WebSocket e PHP

Inviato: venerdì 6 maggio 2016, 23:57
da Zoff
Negli script la porta indicata è 2518, nell'immagine è 2516

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 1:14
da iJim
L'immagine è stata fatta qualche tentativo prima...

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 9:48
da Zoff
Hai avviato lo script php prima?

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 12:23
da iJim
Tutti e due gli script sono ospitati su un server Apache.
Io ho bisogno di un meccanismo in cui il server possa inviare in un qualsiasi momento un messaggio al client, che ovviamente era in attesa.
A quanto pare una cosa del genere è possibile utilizzando la WebSocket ( che non mi funziona! )

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 13:13
da Zoff
Il server websocket non è gestito da apache, va lanciato a parte a mano

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 18:58
da iJim
Grazie per la risposta!!!
Purtroppo me ne sono accorto ....
sto facendo un paio di test con il Server-Sent Event

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 19:00
da Zoff
Considera comunque che esistono server PHP belli e pronti: http://socketo.me/

Hello world: http://socketo.me/docs/hello-world

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 19:09
da iJim
Grazie dinuovo per la risposta!
Purtroppo non posso usare nessuna libreria esterna.... devo fare tutto da me!
:(

Re: WebSocket e PHP

Inviato: sabato 7 maggio 2016, 19:11
da Zoff
Ok! Ricorda il [Risolto].

WebSocket e PHP

Inviato: giovedì 12 maggio 2016, 20:28
da iJim
Purtroppo sono un tipo testardo!
• lancio lo script da terminale dove c'è la socket PHP in ascolto
// se provo con telnet funziona
• lancio la WebSocket in javascript

e NON ARRIVANO GLI HEADER al server !!!
ma se guardo alla console di chrome gli headers sembrano essere inviati, ho controllato sulle variabili del server e gli header in realtà non arrivano, sembra che partano ma non arrivino mai!!!

Codice: Seleziona tutto

        if (false === ($buffer = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
            echo "errore nella lettura: " . socket_strerror(socket_last_error($msgsock)) . "\n";
        }

            echo print_r($buffer, TRUE);
            echo print_r($headers, TRUE);
            echo print_r($_REQUEST, TRUE);
            echo print_r($_SERVER, TRUE);
            echo print_r($_GET, TRUE);
            echo print_r(headers_list(), TRUE);
Immagine

Immagine

[Risolto] WebSocket e PHP

Inviato: venerdì 13 maggio 2016, 16:49
da iJim
Ho trovato cosa non andava!
La socket ad ogni andata a capo smetteva di rimanere in attesa leggendo di fatto una sola riga, quindi non riuscivo a leggere tutti gli header, tramite un ciclo sono riuscito a raccogliere tutti gli header e a fare l'handshake!
Ho risolto anche un alta cosa tramite un trucco, per lanciare lo script php, basta fare una chiamata Ajax ad uno script php che include lo script da lanciare, basta poi terminare la chiamata Ajax.
In questo modo lo script contenente la socket in ascolto rimane attivo!