How to open a connection via socket?

Asked

Viewed 2,486 times

0

I have an application in PHP/Javascript (using the framework jQuery), I want to open a connection via socket for a chat system, similar to Google’s G-talk, but I’m not able to open socket no way.

I can’t use any solution based on node.js.

I tried the following:

CLIENT

<!DOCTYPE HTML>
<html>
    <head>
        <script type="text/javascript">
            WebSocketTest()
            function WebSocketTest(){   
                // Let us open a web socket
                var ws = new WebSocket("ws://localhost/index.php");

                ws.onopen = function(){
                    // Web Socket is connected, send data using send()
                    ws.send("Message to send");
                    alert("Message is sent...");
                };

                ws.onmessage = function (evt)   { 
                    var received_msg = evt.data;
                    alert("Message is received...");
                };

                ws.onclose = function(){ 
                    // websocket is closed.
                    alert("Connection is closed..."); 
                };
            }
        </script>
    </head>
    <body>
        [...]
    </body>
</html>

SERVER

<?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('localhost');

    /* 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'...";
    $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 = "HEAD / HTTP/1.1\r\n";
    $in .= "Host: localhost\r\n";
    $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";
?>

However, I get the following error:

ebSocket Connection to 'Ws://localhost/chat_4/index.php' failed: Error During Websocket Handshake: Unexpected Response code: 200

You would have a more practical solution to check when a message was dynamically inserted into the database?

1 answer

4

Good morning, I don’t know if you have already got your solution, but I can help with a solution that works on some of my systems.

Server side php server.

<?php
$host = '127.0.0.1';
$port = '9000';
$null = NULL;

above vc defines your host, connection port and variable with null value. Note. Important vc set the host with the address of your server (IP).

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);
socket_listen($socket);
$clients = array($socket);


while (true) {
    $changed = $clients;
    socket_select($changed, $null, $null, 0, 10);

if (in_array($socket, $changed)) {
    $socket_new = socket_accept($socket);
    $clients[] = $socket_new;

    $header = socket_read($socket_new, 1024);
    perform_handshaking($header, $socket_new, $host, $port);

    socket_getpeername($socket_new, $ip);
    $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected')));
    send_message($response);

    $found_socket = array_search($socket, $changed);
    unset($changed[$found_socket]);
}

At this point 'below' I start creating an array that will be converted into json. This data will be released in the socket tunnel, that is, the communication between your server and client will be done by this json.

Obs. these values can be defined according to your need and utility.

foreach ($changed as $changed_socket) { 


    while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
    {
        $received_text = unmask($buf); //unmask data
        $tst_msg = json_decode($received_text);

        $user_id_cliente = $tst_msg->id_cliente;
        $empresa_id = $tst_msg->empresa_id;
        $user_time_mensagem = $tst_msg->time_mensagem;
        $user_conteudo_mensagem = $tst_msg->conteudo_mensagem;
        $user_nome_cliente = $tst_msg->nome_cliente;
        $quem_esta_enviado = $tst_msg->quem_envia;
        $produto_detalhes = $tst_msg->produto_detalhes;
        $grupo_men = $tst_msg->grupo_mensagem;
        $nome_empresa = $tst_msg->nome_empresa;

        $regra_empresa = $tst_msg->regra_empresa;
        $atacado_empresa = $tst_msg->atacado_empresa;
        $min_empresa = $tst_msg->min_empresa;
        $cidade_cliente = $tst_msg->cidade_cliente;
        $valor_pedido = $tst_msg->valor_pedido;
        $pedido_mandar = $tst_msg->pedido_mandar;

        $response_text = mask(json_encode(array('nome_empresa'=>$nome_empresa,'grupo_mensagem'=>$grupo_men,'pedido_mandar'=>$pedido_mandar,'regra_empresa'=>$regra_empresa,'atacado_empresa'=>$atacado_empresa,'min_empresa'=>$min_empresa,'cidade_cliente'=>$cidade_cliente,'valor_pedido'=>$valor_pedido,'produto_detalhes'=>$produto_detalhes,'quem_envia'=>$quem_esta_enviado,'empresa_id'=>$empresa_id,'id_cliente'=>$user_id_cliente, 'time_mensagem'=>$user_time_mensagem, 'conteudo_mensagem'=>$user_conteudo_mensagem, 'nome_cliente'=>$user_nome_cliente)));
        send_message($response_text); //send data
        break 2; //exist this loop
    }

continuing...

    $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
    if ($buf === false) { 
        $found_socket = array_search($changed_socket, $clients);
        socket_getpeername($changed_socket, $ip);
        unset($clients[$found_socket]);

        $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
        send_message($response);
    }
}
}

socket_close($socket);

function send_message($msg)
{
    global $clients;
    foreach($clients as $changed_socket)
    {
        @socket_write($changed_socket,$msg,strlen($msg));
    }
    return true;
}


function unmask($text) {
    $length = ord($text[1]) & 127;
    if($length == 126) {
        $masks = substr($text, 4, 4);
        $data = substr($text, 8);
    }
    elseif($length == 127) {
        $masks = substr($text, 10, 4);
        $data = substr($text, 14);
    }
    else {
        $masks = substr($text, 2, 4);
        $data = substr($text, 6);
    }
    $text = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }
    return $text;
}

function mask($text)
{
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);

    if($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
    elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
    return $header.$text;
}

function perform_handshaking($receved_header,$client_conn, $host, $port)
{
    $headers = array();
    $lines = preg_split("/\r\n/", $receved_header);
    foreach($lines as $line)
    {
        $line = chop($line);
        if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
        {
            $headers[$matches[1]] = $matches[2];
        }
    }

    $secKey = $headers['Sec-WebSocket-Key'];
    $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));

    $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
    "Upgrade: websocket\r\n" .
    "Connection: Upgrade\r\n" .
    "WebSocket-Origin: $host\r\n" .
    "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_conn,$upgrade,strlen($upgrade));
}

Client side your-file.js

remember the host and the port? are inserted below

var wsUrir = "ws://127.0.0.1:9000";
    connection = new WebSocket(wsUrir);

open connection, activates the block below

    connection.onopen = function(ev) { 
        console.log('socket aberto');
    };

transactions, messages, requests, etc., run below.

    connection.onmessage = function(ev) {
        var msg_ws = JSON.parse(ev.data);

        var type_ws = msg_ws.type;
        var ws_id_cliente = msg_ws.id_cliente;

        console.log(ev.data);

        if(type_ws !== 'system'){

            // suas condições aqui

        }


    };

if an error occurs during or after connection the function below is triggered.

    connection.onerror  = function(ev){
        console.log("Error Occurred - "+ev.data);
    }; 

if the connection closes, below is triggered

    connection.onclose  = function(ev){
        console.log("conexao fechada"); 
    };

After configuring your files you will have to access your terminal, navigate to the directory that is the file php server. and enter the command:

php -q **server.php**

obs. make sure you have php installed and that variable php be global in your OS.

Another important note is that the socket server only works in php with this command line call, that is, if you try to access by url right in the browser the file will not run and if you close the connection will also be terminated.

Anyway, if you have any questions contact me, what I know I share. Hugs!

  • I ended up making an ajax system that keeps checking if there is a new message in the bank. From the performance point of view it is a tragedy. I will try to apply your solution. Thank you.

  • 1

    Boy, like you said, it’s literally a tragedy, I had this same idea that you at the beginning of my project and suffered a lot until you know the socket, see, this code works very well for me I’m sure it will work for you too, if you have doubts do not hesitate to ask me.

  • @Luizaugustoneto as the client-side code to send the messages to the server?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.