0
I have a system that uses php web socket for chat communication and real-time notification. It works, but usually gives spikes and the server time in time drops the service.
I’m going to post my code here and ask with all affection if you can help me understand what can be improved, what is wrong, etc.
<?php
$host = '216.172.XXX.XXX';
$port = '2703';
$null = NULL;
$pem_passphrase = '';
$pemfile = 'http://216.172.XXX.XXX/~vendemodac/ssl/certs/vendemoda.pem';
$context = stream_context_create();
stream_context_set_option($context, 'ssl', 'local_cert', $pemfile);
// Pass Phrase (password) of private key
stream_context_set_option($context, 'ssl', 'passphrase', $pem_passphrase);
stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
stream_context_set_option($context, 'ssl', 'verify_peer', false);
// Create the server socket
$socket = stream_socket_server(
'ssl://'.$host.':'.$port,
$errno,
$errstr,
STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,
$context
);
//Create TCP/IP sream socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//reuseable port
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
//bind socket to specified host
socket_bind($socket, 0, $port);
//listen to port
socket_listen($socket);
//create & add listning socket to the list
$clients = array($socket);
//start endless loop, so that our script doesn't stop
while (true) {
//manage multipal connections
$changed = $clients;
//returns the socket resources in $changed array
socket_select($changed, $null, $null, 0, 10);
//check for new socket
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket); //accpet new socket
$clients[] = $socket_new; //add socket to client array
$header = socket_read($socket_new, 2048); //read data sent by the socket
perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake
//socket_getpeername($socket_new, $ip); //get ip address of connected socket
$response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected'))); //prepare json data
send_message($response); //notify all users about new connection
//make room for new socket
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
//loop through all connected sockets
foreach ($changed as $changed_socket) {
//check for any incomming data
while(socket_recv($changed_socket, $buf, 2048, 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;
$loja_id = $tst_msg->loja_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;
//prepare data to be sent to client
$response_text = mask(json_encode(array('nome_empresa'=>$nome_empresa,'grupo_mensagem'=>$grupo_men,'loja_id'=>$loja_id,'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
}
$buf = @socket_read($changed_socket, 2048, PHP_NORMAL_READ);
if ($buf === false) { // check disconnected client
// remove client for $clients array
$found_socket = array_search($changed_socket, $clients);
//socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
//notify all users about disconnected connection
$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')));
//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));
}