Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
David Šabacký:14.6.2021 19:44

Zdravím,

potřebuji pomocí PHP (v příkazové řádce) číst, viz. můj kód níže. Chodí mi to v HTML/JavaScriptu, ale nechodí mi to v čistém PHP.

Mohl bych požádat o pomoc?

Díky

David

Zkusil jsem:

<?php
error_reporting(E_ALL);

echo "<h2>TCP/IP Connection</h2>\n";

/* Get the port for the WWW service. */
$service_port = getservbyname('www', 'tcp');

/* Get the IP address for the target host. */
$address = gethostbyname('demo.signalk.org');

/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
} else {
    echo "OK.\n";
}


echo "Attempting to connect to '$address' on port '$service_port'...";
echo $address."/signalk/v1/stream\r\n";

$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
    echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
} else {
    echo "OK.\n";
}

$in = "GET / HTTP/1.1\r\n";
$in .= "Host: demo.signalk.org/signalk/v1/stream\r\n";
//$in .= '{"context": "vessels*","subscribe": [{"path": "navigation*", "period": 1000,"format": "delta", "policy": "instant", "minPeriod": 10000},{"path": "mmsi*","minPeriod": 1000,"policy": "ideal"}]}';
//$in .= "Connection: Close\r\n\r\n";
$out = '';

echo "Sending HTTP HEAD request...";
socket_write($socket, $in, strlen($in));
echo "OK.\n";

echo "Reading response:\n\n";
while ($out = socket_read($socket, 2048)) {
    echo $out;
}

echo "Closing socket...";
socket_close($socket);
echo "OK.\n\n";
?>

Kód v JavaScriptu, ale potřebuju to dostat do PHP, jak jsem psal v příkazové řádce:

<html>
<body>
    <div id="root"></div>
    <script>

        var host = 'ws://demo.signalk.org/signalk/v1/stream?subscribe=none';
        //var host = 'ws://10.38.39.20:3000/signalk/v1/stream?subscribe=none';
        var socket = new WebSocket(host);
        socket.onopen = function(e) {
                //alert(e.data);
                socket.send('{"context": "vessels*","subscribe": [{"path": "navigation*", "period": 1000,"format": "delta", "policy": "instant", "minPeriod": 10000},{"path": "mmsi*","minPeriod": 1000,"policy": "ideal"}]}');

         };

        //socket.close();


        socket.onmessage = function(code) {
                         document.getElementById('root').innerHTML = code.data;

        };




    </script>


</body>
</html>
 
Odpovědět
14.6.2021 19:44
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:15.6.2021 8:32

No, a jak si to ale predstavujes? V web-socket jsem si hral zatim jen s chatem. Takze ti moc neporadim...

U chatu to funguje tak, ze si vytvoris v php nekonecnou smycku, ve ktere nacitas obsah socketu, pripojenych lidi. Aby ti smycka fungovala, musis vypnout casove omezeni pro spusteni kodu.

set_time_limit(0);      // how long run server
  • Prvne si tam dej 5-15 sekund, treba. za tu dobu stihnes spustit html stranku a testnout, zda se ti to pripoji.

Neprijemne totiz je, ze pokud to nechas v nekonecnu a nemas tam pridanou moznost zastaveni, tak ten proces bude mozne zhodit jen linuxovym prikazem pro odstraneni z procesu. Podobne na win.

  • Dalsi zasadni problem je, ze seznam pripojenych uzivatelu-socketu je treba si ukladat do pole. To tak uplne v na php.net/socket_cre­ate jasne neni. Cili, ty si vytvoris nejake pole, kam ukladas vsechny conected na tvuj socket. A pak to pole prochazis a overujes, zda se na nekterem connect objevi zprava nebo ne (obvykle na masterovi). A kdyz jo, tak to posles vsem connected mimo mastera nebo ne.

A tez je teda dobre, pri kontrolovani mastera mit zabudovany prikaz na zastaveni nekonecne smycky while.
Princip:

  • Na zacatku si vytvoris mastera.
  • U mastera kontrolujes, zda se k nemu nekdo pripoji, posle message na socket.
  • Pokud jo, probiha to pomoci hand-shake. Uzivatel posle zadost o pripojeni, data o sobe. Tvuj program zadost prijme, vygeneruje certifikat (json kod), hand shake a pripoji ho do pole changed.
  • A uzivatel si certifikat zapise a dale pouziva pri komunikaci s masterem
  • Pokud uzivatel udela F5 v prohlizeci a nema platne pripojeni, pripojuje se znova. Takze ti takhle muze naskakar spousta otevrenych uzivatelu. A tez je to neprijemne pro uzivatele. Takze musis mit nejaky mechanismus k pripojovani a odpojovani uzivatelu na strane prohlizece i php-socket-serveru
  • A take je dobre myslet na to, ze server si aktivitu na socketu monitoruje. Posila a prijima zpravy typu ping.

Ale, mozna, ze ty potrebujes neco jineho.

/*
public function writeError($str)//,$socket
        {
        $str .= " failed ";
//      $str .= $socket && is_resource($socket) ? socket_strerror(socket_last_error($socket)) : '';
        $str .= socket_strerror(socket_last_error());
        echo $str.'<br>';
        return false;
        }

public function create($address,$port,$max_conn=20)
        {
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)  or writeError("socket_create()",$socket);
        socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1) or writeError("socket_set_option()",$socket);
        socket_bind($socket, $address, $port)                   or writeError("socket_bind()",$socket);
        socket_listen($socket,$max_conn)                        or writeError("socket_listen()",$socket);
        //socket_set_nonblock($socket);
        echo     "Server Started : ".date('Y-m-d H:i:s')."\n";
        echo "<br>Master socket  : ".$socket."\n";
        echo "<br>Listening on   : address = ".$address.", port = ".$port."\n\n";
        $this->master  = $socket;
        $this->sockets = array();
        $this->users   = array();
        $this->userAdd($socket,array(
                'name'   => 'master'
                )); // pridavam socked mastera do seznamu uzivatelu + do pole sockets
       // a to pole pak presunuji do changed, $changed = $WS->sockets, ve while smycce
    }

public function connect($cfg)
        {
        global $REQ;
        //  global $sockets,$users;
        $socket = socket_accept($this->master) or $this->writeError("socket_accept()",$socket); //accept new socket
        if ($socket)
                {
                $header = socket_read($socket, 1024)   or $this->writeError("socket_read()",$socket); //read data sent by the socket
                $this->createHandshake($socket, $header, $cfg); //perform websocket handshake
                socket_getpeername($socket, $ip)       or $this->writeError("socket_getpeername()",$socket);
                $uniqid = $REQ->get('uniqid');
                $name   = $REQ->get('name');
                return $this->userAdd($socket,array(
                        'name'   => $name,
                        'uniqid' => $uniqid,
                        'ip'     => $ip,
                        'handshake' => true
                        ));
                //$this->userAdd($socket,$ip,true);
//              return $this->findUserBySocket($socket); // add user->index
                }
        return false;
        //console($socket." CONNECTED!");
        //return $user;
        }


*/

$cfg = array(
'server' => array(
        'host' => 'localhost', //host
        'port' => '9000', //port
        'max_conn' => 20,
        'url' => ''
        ),
//'null' => NULL, //null var
'header_sep' => PHP_EOL ? PHP_EOL : "\r\n"
);
$cfg['server_url']    = "ws://".$cfg['server']['host'].":".$cfg['server']['port']."/demo/ws_server.php";//RTC-chat/php-ws
$cfg['server']['url'] = $cfg['server_url'];

$WS = new classWebSocket(); // Ja si na to udelal nejakou class a moznost zastavit beh. Ma to asi 20k. Ale podstatny je ten cyklus.
$WS->create($s['host'],$s['port'],$s['max_conn']);

$write_null  = null;
$except_null = null;
$run = true;

        $changed = $WS->sockets;
//var_dump($changed);
//die();
while($run)
        {
        $changed = $WS->sockets;
//  socket_select($changed,$write=NULL,$except=NULL,NULL);
        socket_select($changed,$write_null,$except_null,0,10);
        foreach($changed as $socket)
                {
                if ($socket==$WS->master)
                        {
                //      $client=socket_accept($master);
                        $user = $WS->connect($cfg);
                        $ROOM->join($user);
                //      if($client<0)
                //        { console("socket_accept() failed"); continue; }
                  //    else
                    //    { connect($client); }
                        }
                else    {
                        $bytes = @socket_recv($socket,$buffer,2048,0);
                        if ($bytes==0)
                                {
                //               disconnect($socket);
                                $user = $WS->disconnect($socket);
                                $ROOM->leave($user);
                                }
                        else    {
                                $user = $WS->findUserBy('socket',$socket);
                                if ($WS->receive($user, $buffer)==-999)
                                        {$run = false;}
//        if(!$user->handshake){ dohandshake($user,$buffer); }
//        else{ process($user,$buffer); }
//                      $received_text = unmask($buf); //unmask data
//                      $msg = json_decode($received_text); //json decode
                                }
                        }
                }
        }
$WS->closeAll();
echo '<hr>'.$MICRO->stop();

Jestli to spravne chapu, tak ty tam smycku mas. Readujes master socketa. Neresis nejake handshake. Neresis pripojeni uzivatele. Jen chces vedet, zda to nejak zareaguje.
No, jenze, vypsani na obrazovku se obvykle deje az, kdyz php program ukonci svou cinnost :)
A muzou nastat tyto situace:

  • bud ti bezi cyklus stale dokola
  • nebo se cyklus zastavi a vypisou se ti vsechna echa na obrazovku
  • cyklus nebezi dostatecne dlouho, aby ses stihl javascriptem pripojit

Na read nemusi nutne nic byt. A tim padem ti to hned skonci.
Socketovat muzes tedy jen tak, ze nekde bezi server, ktery vysila data, kdyz se na nej pripoji uzivatel. Neco, co bezi v nekonecne smycce porad dokola a ceka na uzivatele. Read dela jen to, ze precte ze socketu. A protoze 99% casu na socketu nic neni, tak tva smycka ihned skonci :) Coz se projevi tim, ze php ukonci zasilani stranky uzivateli a vypisou se ti vsechna echa. (Dobre na tom je, ze program nezustane viset v pameti, nemusis ho zhazovat z procesu :) Spatne, ze se v tom kratkem okamziku nikdo nestihl pripojit, takze read nic nevypise. )
Tvuj JS kod dela to, ze se pokusi pripojit na nejaky server a odeslat zpravu.

  • Takze si ten cyklus sprav na nekonecnou smycku
  • Nebo, jestli chces mit neco zajimaveho, tak muzes cely js kod obalit do casovace a nechat ho probihat stale dokola, dokud nezmacknes klavesu, treba. Je tam sance, ze se trefis do okamziku, kdy ve vedlejsim okne spustis ten php program.
Editováno 15.6.2021 8:34
 
Nahoru Odpovědět
15.6.2021 8:32
Avatar
Odpovídá na Peter Mlich
David Šabacký:15.6.2021 10:48

Ahoj

díky, ono je to i tom, že na tom websocketu se generují stále nějaké informace. Potřebuju jenom klienta, kterým to budu číst a parsovat.

D

 
Nahoru Odpovědět
15.6.2021 10:48
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:15.6.2021 12:30

A pise ti to teda nejakou chybu?
Protoze, jinak ten kod je asi dobre, az na to, ze php ma limit pro beh scriptu. Pokud ten while teda bezi do nekonecka, tak nikdy neskonci. A tudiz nemuze odeslat na obrazocku zadne echo. A cele to skonci chybou php-memory-limit nebo php-time-limit.
Otazkou je, kam dal ty informace maji putovat?

Jakoze jsem to teda spatne pochopil Potrebujes funkcni js kod prepsat do php. Jenom cteni socketu.

Prvne bych si pred while napsal die(); a doplnil chybove hlasky ke kazdemu prikazu, ktery bude reagovat na socket_strerror(soc­ket_last_error()); Zjistit, zda se to spravne pripoji, zda je spravna url adresa a tak.
Zkusim ten kod upravovat, jestli je to nejaky free server a pobezi mi to, treba na neco prijdu :)

 
Nahoru Odpovědět
15.6.2021 12:30
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:15.6.2021 14:10

smazano...

Editováno 15.6.2021 14:11
 
Nahoru Odpovědět
15.6.2021 14:10
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:15.6.2021 14:58

Podarilo se mi to dostat do stavu, kdy mi server odpovida a vypisuje

content = HTTP/1.1 505 HTTP Version Not Supported Connection: close Server: Cowboy Date: Tue, 15 Jun 2021 12:56:52 GMT Content-Length: 0
// -------
<?php
error_reporting(E_ALL);

function writeError($source, $socket)
        {
        if ($socket)
                {
                $code = socket_last_error($socket);
                socket_clear_error($socket);
                }
        else    {
                $code = socket_last_error();
                }
        $msg  = socket_strerror($code);
        echo "<hr>Error ($source) [".$code."] ".$msg.'<hr>';
        return false;
        }

echo "<h2>TCP/IP Connection</h2>\n";

// url = ws://demo.signalk.org/signalk/v1/stream?subscribe=none
$service = array();
$service['hostname']     = 'demo.signalk.org';
$service['service']  = 'www';
$service['protocol'] = 'tcp';
$service['port']     = getservbyname($service['service'], $service['protocol']);
$service['path']     = '/signalk/v1/stream?subscribe=none';
$service['path2']     = '/signalk/v1/stream';
$service['address']  = gethostbyname($service['hostname']);


/* Create a TCP/IP socket. */
echo "<br>"; echo "Attempting to connect to '{$service['address']}' on port '{$service['port']}', header-host '{$service['hostname']}{$service['path2']}' ...";
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or writeError("socket_create", $socket);
$bool   = socket_connect($socket, $service['address'], $service['port']) or writeError("socket_create", $socket);

$opt = socket_get_option($socket);
echo "<br>"; var_dump('opt', $opt);

$status = socket_get_status($socket);
echo "<br>"; var_dump('status', $status);


echo "<br>"; echo "Sending HTTP HEAD request...";
$header[] = "HEAD / HTTP/1.1";
$header[] = "Host: ".$service['hostname'];
$header[] = "Connection: Close";
$header[] = "";
$header[] = "";
$header = implode(PHP_EOL, $header);
var_dump($header);
//$msg  = '{"context": "vessels*","subscribe": [{"path": "navigation*", "period": 1000,"format": "delta", "policy": "instant", "minPeriod": 10000},{"path": "mmsi*","minPeriod": 1000,"policy": "ideal"}]}';
//socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1) or $this->errorAdd("socket_set_option",$socket);
//socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1) or writeError("socket_set_option",$socket);

$result = socket_write($socket, $header, strlen($header));
echo "<br>"; var_dump('socket_write written bytes = ', $result);

$content = '';

echo "<br>"; echo "Reading response...";
$result = true;
while ($result==true) {
        $result = socket_read($socket, 2048) or writeError("socket_read", $socket); //read data sent by the socket
        echo "<br>"; var_dump('socket_read', $result);
        $content .= $result;
}
echo "<br>"; echo 'content = '. $content;

echo "<br>"; echo "Closing socket...";
@socket_close($socket);
echo "<br>"; var_dump('socket_close');
echo time();
?>

/*
TCP/IP Connection

Attempting to connect to '52.212.52.84' on port '80', header-host 'demo.signalk.org/signalk/v1/stream' ...
string(3) "opt" NULL
string(6) "status" bool(false)
Sending HTTP HEAD request...string(58) "HEAD / HTTP/1.1 Host: demo.signalk.org Connection: Close "
string(29) "socket_write written bytes = " int(58)
Reading response...
string(11) "socket_read" string(134) "HTTP/1.1 505 HTTP Version Not Supported Connection: close Server: Cowboy Date: Tue, 15 Jun 2021 12:56:52 GMT Content-Length: 0 " Error (socket_read) [0] Success <<<<------------
string(11) "socket_read" string(0) ""
content = HTTP/1.1 505 HTTP Version Not Supported Connection: close Server: Cowboy Date: Tue, 15 Jun 2021 12:56:52 GMT Content-Length: 0
Closing socket...
string(12) "socket_close" 1623761812
*/
 
Nahoru Odpovědět
15.6.2021 14:58
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 6 zpráv z 6.