Send message to specific user in Websocket PHP

4

I have a real-time chat application with Websocket. But at the moment it sends messages to all users, I would like to know how do I send them to a specific user. In case, when I click on the user (from a list that appears next to it), he will start a conversation with that due user.

I have the following data being returned via JSON:

//ENVIA COM O ENTER
    $('#message').on('keydown', function(e) {
        var mymessage = $('#message').text(); //get message text
        var msg = $.trim(mymessage);
        var myname = $('.myname').text(); //get user name
        var mensagem = 'mensagem='+mymessage;
        var from = $('.myname').attr('id');
        var to = $('p.nome-informacoes').attr('id');
        var code = e.which || e.keyCode;

        if (e.which == 13 && e.shiftKey == false) {
            if(code == 13){
                if(mensagem != ''){

                    if(mymessage == "" || mymessage.length === 0 || !mymessage.trim()){return false;}
                    else{
                        $.ajax({
                            type: 'POST',
                            url : 'sys/chat.php',
                            data: 'acao='+'inserir'+'&para='+to+'&mensagem='+mymessage,
                            success: function(html){}
                        });

//AQUI ELE PEGA OS DADOS VIA JSON QUE VÃO SER ENVIADOS PARA O USUÁRIO ESPECÍFICO                        
                            var msg = {
                            message: mymessage,
                            name: myname,
                            from: from,
                            to: to,
                            color : '<?php echo $colours[$user_colour]; ?>'
                            };
                            //convert and send data to server
                            websocket.send(JSON.stringify(msg));
                        }

                    }
                }

                return false;
            }
        })


websocket.onmessage = function(ev) {
        var msg = JSON.parse(ev.data); //PHP sends Json data
        //console.log(msg);
        var type = msg.type; //message type
        var mensagem = msg.message; //message text
        var umsg = $.trim(mensagem);
        var uname = msg.name; //user name
        var ucolor = msg.color; //color
        var status = msg.status;
        var myname = $('.myname').text();
        var nome_user = $('.comecar').attr('title');
        var id = $('p.nome-informacoes').attr('id');
        var id_de = $('.myname').attr('id');
        var from = msg.from;
        var to = msg.to;
        var data = [];

        //AQUI ELE VAI ADICIONANDO ALGUMAS INFORMAÇÕES DE CADA USUÁRIO PARA PODER DIRECIONAR A MENSAGEM PARA USUÁRIO CORRETO
        data.push({'user': uname, 'message': umsg, 'from': from, 'to': to });
        var dados_user = JSON.stringify(data)
        var parser     = JSON.parse(dados_user);

        for(i in dados_user){
            console.log(parser[i]);
        }



        //console.log(localStorage.length);
        if(type == 'usermsg' && umsg.length > 0)
        {
            $("#message_box").animate({"scrollTop": $('#message_box')[0].scrollHeight}, 1);
            $(teste2).append("<div class='mensagem'><span class=\"user_name outro\" nome=\""+uname+"\" style=\"color:#"+ucolor+"\">"+uname+"</span> : <pre><span class=\"user_message\">"+umsg+"</span></pre></div>");

        }

        if(type == 'system' )
        {
            $('#jan_'+id+'').append("<div class=\"system_msg\">"+umsg+"</div>");

        }

        $('#message').text(''); //reset text
        $('.input').val('');
    };
    
asked by anonymous 02.05.2015 / 05:59

1 answer

2

Below we will understand how the operation of a Socket server.

server.php

$host = '192.168.0.28'; // Host do servidor para conexão
$port = '9000'; // Porta do servidor para conexão
$null = NULL; // Variável nula auxilar

error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);

// Permite o script rodar infinitamente para esperar por conexões
set_time_limit(0);

// Ativa a saída implicita do buffer, isto é, assim que houver alguma
// tiver uma modificação no buffer, é enviado para a tela e o buffer esvaziado.
ob_implicit_flush();

// Cria o servidor socket
$socketServer = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Seta a porta como reutilizável
socket_set_option($socketServer, SOL_SOCKET, SO_REUSEADDR, 1);

// Amarra socket com o host especificado
socket_bind($socketServer, 0, $port);

// Escuta a porta
socket_listen($socketServer);

// Cria uma lista de sockets que serão escutados
$clients = array($socketServer);

// Armazena o nome dos usuários.
$usersList = array();

// Inicia um loop infinito para que o servidor estaj sempre apto a receber as
// mensagens e receber novas conexões.
while (true) {
    // Controla multiplas conexões copiando a lista para verificar quais as
    // conexões possui alterações.
    $changed = $clients;
    // Verifica se existe sockets com alterações
    socket_select($changed, $null, $null, 0, 10);

    // Testa por novas conexões
    if (in_array($socketServer, $changed)) {
        // Aceita nova conexão
        $socket_new = socket_accept($socketServer);

        // Adiciona o scket client na lista
        $clients[] = $socket_new;

        // Lê os dados enviados pelo novo socket
        $header = socket_read($socket_new, 1024);

        // Envia a resposta do servidor com informações sobre a conexão aceita
        perform_handshaking($header, $socket_new, $host, $port);

        // Obtem o endereço IP do socket conectado.
        socket_getpeername($socket_new, $ip);

        // Prepara a mensagem de boas vindas
        $response = mask(json_encode(array(
            'type'=>'system',
            'message'=> $ip. ' connected'
        )));

        // Envia a mensagem para todos indicando que uma nova pessoa entrou.
        send_message($response);

        // Remove a nova conexão da lista de sockets modificados.
        $found_socket = array_search($socket_new, $changed);
        unset($changed[$found_socket]);
    }

    // Verifica todos os outros sockets modificados que foram alterados
    foreach ($changed as $changed_socket) {

        // Verifica por dados recebidos inciando um loop de leitura do buffer
        // recebido inteiro.
        while (socket_recv($changed_socket, $buf, 1024, 0) >= 1) {
            // Desmascara os dados
            $received_text = unmask($buf);

            // Interpreta os dados
            $tst_msg = json_decode($received_text);

            $user_name = $tst_msg->name;
            $user_toname = $tst_msg->toname;
            $user_message = $tst_msg->message;
            $user_color = $tst_msg->color;

            // Registra o nome do usuário
            $found_socket = array_search($changed_socket, $clients);
            $usersList[$found_socket] = $user_name;

            // Prepara os dados para resposta
            $response_text = mask(json_encode(array(
                'type'=>'usermsg',
                'name'=>$user_name,
                'toname'=>$user_toname,
                'message'=>$user_message,
                'color'=>$user_color
            )));

            // Envia mensagem para um usuário específico ou para todo mundo
            if ($user_toname) {
                $key = array_search($user_toname, $usersList);
                send_message($response_text, $key);
            } else {
                send_message($response_text);
            }
            break 2; // Finaliza este loop
        }

        $buf = socket_read($changed_socket, 1024, PHP_NORMAL_READ);

        // Verifica por clientes desconectados
        if ($buf === false) {
            // Remove o cliente da lista
            $found_socket = array_search($changed_socket, $clients);
            socket_getpeername($changed_socket, $ip);
            unset($clients[$found_socket]);
            unset($usersList[$found_socket]);

            // Notifica a todos que o usuário desconectou
            $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
            send_message($response);
        }
    }
}
// Finaliza o socket do servidor
socket_close($socketServer);

function send_message($msg, $key = false) {
    global $clients;
    if($key !== false) {
        if (isset($clients[$key])) {
            socket_write($clients[$key],$msg,strlen($msg));
        }
    } else {
        foreach($clients as $changed_socket) {
            socket_write($changed_socket,$msg,strlen($msg));
        }
    }
    return true;
}


// Desmascara os dados recebidos
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;
}

// Codifica as mensagens para transferir para o cliente
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;
}

// Realiza handshake com o novo cliente
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);
        $matches = array();
        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')));
    //hand shaking header
    $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));
}

To run the server enter the terminal and execute

php -q server.php

Client example file

<!DOCTYPE html>
<html>
    <head>
        <meta charset='UTF-8' />
        <style type="text/css">
            <!--
            .chat_wrapper {
                width: 500px;
                margin-right: auto;
                margin-left: auto;
                background: #CCCCCC;
                border: 1px solid #999999;
                padding: 10px;
                font: 12px 'lucida grande',tahoma,verdana,arial,sans-serif;
            }
            .chat_wrapper .message_box {
                background: #FFFFFF;
                height: 150px;
                overflow: auto;
                padding: 10px;
                border: 1px solid #999999;
            }
            .chat_wrapper .panel input{
                padding: 2px 2px 2px 5px;
            }
            .system_msg{color: #BDBDBD;font-style: italic;}
            .user_name{font-weight:bold;}
            .user_message{color: #88B6E0;}
            -->
        </style>
    </head>
    <body>
        <?php
        $colours = array('007AFF', 'FF7000', 'FF7000', '15E25F', 'CFC700', 'CFC700', 'CF1100', 'CF00BE', 'F00');
        $user_colour = array_rand($colours);

        ?>

        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

        <script language="javascript" type="text/javascript">
            $(document).ready(function () {
                var wsUri = "ws://192.168.0.28:9000/demo/server.php";
                websocket = new WebSocket(wsUri);

                websocket.onopen = function (ev) {
                    $('#message_box').append("<div class=\"system_msg\">Conectado!</div>");
                };

                $('#send-btn').click(function () {
                    var mymessage = $('#message').val();
                    var myname = $('#name').val();
                    var toname = $('#toname').val();

                    if (myname === "") {
                        alert("Entre com algum nomde");
                        return;
                    }
                    if (mymessage === "") {
                        alert("Entre com aguma mensagem");
                        return;
                    }


                    var msg = {
                        message: mymessage,
                        name: myname,
                        toname: toname,
                        color: '<?php echo $colours[$user_colour]; ?>'
                    };

                    websocket.send(JSON.stringify(msg));
                });


                websocket.onmessage = function (ev) {
                    var msg = JSON.parse(ev.data);
                    var type = msg.type;
                    var umsg = msg.message;
                    var uname = msg.name;
                    var ucolor = msg.color;

                    console.log(type);
                    if (type === 'usermsg') {
                        $('#message_box').append("<div><span class=\"user_name\" style=\"color:#" + ucolor + "\">" + uname + "</span> : <span class=\"user_message\">" + umsg + "</span></div>");
                    } else if (type === 'system') {
                        $('#message_box').append("<div class=\"system_msg\">" + umsg + "</div>");
                    }

                    $('#message').val('');
                };

                websocket.onerror = function (ev) {
                    $('#message_box').append("<div class=\"system_error\">Um erro ocorreu - " + ev.data + "</div>");
                };
                websocket.onclose = function (ev) {
                    $('#message_box').append("<div class=\"system_msg\">Conexão finalizada</div>");
                };
            });
        </script>
        <div class="chat_wrapper">
            <div class="message_box" id="message_box"></div>
            <div class="panel">
                <input type="text" name="name" id="name" placeholder="Your Name" maxlength="10" style="width:20%"  />
                <input type="text" name="toname" id="toname" placeholder="To Name" maxlength="10" style="width:20%"  />
                <input type="text" name="message" id="message" placeholder="Message" maxlength="80" style="width:40%" />
                <button id="send-btn">Send</button>
            </div>
        </div>

    </body>
</html>

This example does not consider a client connection limit, which is necessary to have a control, because for each client, the processing is required by the server.

To display the user list online, simply create a command that will be sent from time to time to the server, which will return the variable $usersList .

    
16.11.2015 / 07:53