Guest User

Small WebSocket Server

a guest
Aug 19th, 2012
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 7.02 KB | None | 0 0
  1. <?php  
  2. // Functions
  3. ////////////////////////////////////////////////////
  4.    
  5.     function ConsoleError($errorFunctionName, $socket)
  6.     {
  7.         return $errorFunctionName . " failed, reason: " . socket_strerror(socket_last_error($socket)) . "\r\n";
  8.     }
  9.    
  10.     function websock_decode($data)
  11.     {
  12.             $bytes = $data;
  13.             $data_length = "";
  14.             $mask = "";
  15.             $coded_data = "" ;
  16.             $decoded_data = "";        
  17.             $data_length = $bytes[1] & 127;
  18.             if ($data_length === 126)
  19.             {
  20.                 $mask = substr($bytes, 4, 8);
  21.                 $coded_data = substr($bytes, 8);
  22.             }
  23.             else if ($data_length === 127)
  24.             {
  25.                 $mask = substr($bytes, 10, 14);
  26.                 $coded_data = substr($bytes, 14);
  27.             }
  28.             else
  29.             {
  30.                 $mask = substr($bytes, 2, 6);
  31.                 $coded_data = substr($bytes, 6);
  32.             }
  33.             for ($i = 0; $i < strlen($coded_data); $i++)
  34.             {
  35.                 $decoded_data .= $coded_data[$i] ^ $mask[$i%4];
  36.             }
  37.             //echo "Server Received->".$decoded_data."\r\n";
  38.             return $decoded_data;
  39.     }
  40.    
  41.     function websock_encode($data, $binary = false)
  42.     {
  43.             $databuffer = array();
  44.             $sendlength = strlen($data);
  45.             $rawBytesSend = $sendlength + 2;
  46.             $packet;
  47.  
  48.             if ($sendlength > 65535)
  49.             {
  50.                     // 64bit
  51.                     array_pad($databuffer, 10, 0);
  52.                     $databuffer[1] = 127;
  53.                     $lo = $sendlength | 0;
  54.                     $hi = ($sendlength - $lo) / 4294967296;
  55.  
  56.                     $databuffer[2] = ($hi >> 24) & 255;
  57.                     $databuffer[3] = ($hi >> 16) & 255;
  58.                     $databuffer[4] = ($hi >> 8) & 255;
  59.                     $databuffer[5] = $hi & 255;
  60.  
  61.                     $databuffer[6] = ($lo >> 24) & 255;
  62.                     $databuffer[7] = ($lo >> 16) & 255;
  63.                     $databuffer[8] = ($lo >> 8) & 255;
  64.                     $databuffer[9] = $lo & 255;
  65.  
  66.                     $rawBytesSend += 8;
  67.             }
  68.             else if ($sendlength > 125)
  69.             {
  70.                     // 16 bit
  71.                     array_pad($databuffer, 4, 0);
  72.                     $databuffer[1] = 126;
  73.                     $databuffer[2] = ($sendlength >> 8) & 255;
  74.                     $databuffer[3] = $sendlength & 255;
  75.  
  76.                     $rawBytesSend += 2;
  77.             }
  78.             else
  79.             {
  80.                     array_pad($databuffer, 2, 0);
  81.                     $databuffer[1] = $sendlength;
  82.             }
  83.  
  84.             // Set op and find
  85.             $databuffer[0] = (128 + ($binary ? 2 : 1));
  86.             $packet = pack('c', $databuffer[0]);
  87.            
  88.             // Clear masking bit
  89.             //$databuffer[1] &= ~128;
  90.             // write out the packet header
  91.             for ($i = 1; $i < count($databuffer); $i++)
  92.             {
  93.                     //$packet .= $databuffer[$i];
  94.                     $packet .= pack('c', $databuffer[$i]);
  95.             }
  96.  
  97.             // write out the packet data
  98.             for ($i = 0; $i < $sendlength; $i++)
  99.             {
  100.                     $packet .= $data[$i];
  101.             }
  102.  
  103.             return $packet;
  104.     }
  105.  
  106. /////////////////////////////////////////////////////
  107.  
  108.     $address = "localhost";
  109.     $port = "10001";
  110.  
  111.     set_time_limit(0);
  112.     ob_implicit_flush(true);
  113.    
  114.     $sockets = array();
  115.     $handshakes = array();
  116.    
  117.     $sockets["listening"] = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  118.    
  119.     if ($sockets["listening"] < 0)
  120.     {
  121.         die(ConsoleError("socket_create()", $sockets["listening"]));
  122.     }
  123.    
  124.     socket_set_option($sockets["listening"], SOL_SOCKET, SO_REUSEADDR, 1);
  125.    
  126.     if (!socket_bind($sockets["listening"], $address, $port))
  127.     {
  128.         die(ConsoleError("socket_bind()", $sockets["listening"]));
  129.     }
  130.    
  131.     if (socket_listen($sockets["listening"], 100) < 0)
  132.     {
  133.         die(ConsoleError("socket_listen()", $sockets["listening"]));
  134.     }
  135.    
  136.     echo("WebSocket server is started\r\n");
  137.    
  138.     while(true)
  139.     {
  140.         $readable_sockets = $sockets;
  141.        
  142.         socket_select($readable_sockets, $writable_sockets = NULL, $exceptions = NULL, NULL);
  143.        
  144.         foreach ($readable_sockets as $socket)
  145.         {
  146.             //Если это запрос на подключение нового клиента
  147.             if ($socket == $sockets["listening"])
  148.             {
  149.                 $client = socket_accept($socket);
  150.                 if ($client < 0)
  151.                 {
  152.                     echo(ConsoleError("socket_accept", $client));
  153.                     continue;
  154.                 }
  155.                 else
  156.                 {
  157.                     $sockets[] = $client;
  158.                     echo("New client try to connect\r\n");
  159.                 }
  160.             }
  161.             //Если это получение данных, отправленных клиентом
  162.             else
  163.             {
  164.                 $index = array_search($socket, $sockets);
  165.                 $len = socket_recv($socket, $buffer, 2048, 0);
  166.                 //Если это сообщение об отключении клиента
  167.                 if ($len === 0)
  168.                 {
  169.                     if ($index >= 0)
  170.                     {
  171.                         unset($sockets[$index]);
  172.                         if (isset($handshakes[$index]))
  173.                         {
  174.                             unset($handshakes[$index]);
  175.                         }
  176.                     }
  177.                     socket_close($socket);
  178.                     echo("Client disconnected\r\n");
  179.                 }
  180.                 else if ($len === false)
  181.                 {
  182.                     echo(ConsoleError("socket_recv", $socket));
  183.                     continue;
  184.                 }
  185.                 //Если это блок данных от клиента, который можно прочитать
  186.                 else
  187.                 {
  188.                     //Если мы уже выполняли "рукопожатие" с этим клиентом
  189.                     if (isset($handshakes[$index]))
  190.                     {
  191.                         //Обрабатываем сообщение $buffer от клиента $socket
  192.                        
  193.                         $tt = "";
  194.                         for ($i = 0; $i < strlen($buffer); $i++)
  195.                         {
  196.                             $tt .= str_pad(sprintf("%x", ord($buffer[$i])), 2, "0", STR_PAD_LEFT) . " ";
  197.                         }
  198.                         $tt .= "\r\n";
  199.                         echo("Received buffer: " . $tt);
  200.                        
  201.                         $temp = websock_decode($buffer);
  202.                         echo("Received message: " . $temp . "\r\n");
  203.                        
  204.                         $answer = websock_encode($temp);
  205.                        
  206.                         $tt = "";
  207.                         for ($i = 0; $i < strlen($answer); $i++)
  208.                         {
  209.                             $tt .= str_pad(sprintf("%x", ord($answer[$i])), 2, "0", STR_PAD_LEFT) . " ";
  210.                         }
  211.                         $tt .= "\r\n";
  212.                         echo("Sended buffer: " . $tt . "\r\n");
  213.                         echo("sended string: " . $answer . "\r\n");
  214.                        
  215.                         foreach ($sockets as $client)
  216.                         {
  217.                             if ($client != $sockets["listening"])
  218.                             {
  219.                                 socket_set_nonblock($client);
  220.                                 if (socket_write($client, $answer, strlen($answer)) === false)
  221.                                 {
  222.                                     ConsoleError("socket_write()", $client);
  223.                                 }
  224.                                 socket_set_block($client);
  225.                             }
  226.                         }
  227.                     }
  228.                     else
  229.                     {
  230.                         //Выполняем "рукопожатие"
  231.                         $webSocket_key = substr($buffer, strpos($buffer, "Sec-WebSocket-Key: ") + 19);
  232.                         $webSocket_key = substr($webSocket_key, 0, strpos($webSocket_key, "\r\n"));
  233.                         $webSocket_accept = $webSocket_key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  234.                         $webSocket_accept = base64_encode(sha1($webSocket_accept, true));
  235.                         $webSocket_answer =
  236.                             "HTTP/1.1 101 Switching Protocols\r\n" .
  237.                             "Upgrade: websocket\r\n" .
  238.                             "Connection: Upgrade\r\n" .
  239.                             "Sec-WebSocket-Accept: {$webSocket_accept}\r\n\r\n" . chr(0);
  240.                         socket_write($socket, $webSocket_answer, strlen($webSocket_answer));
  241.                         $handshakes[$index] = true;
  242.                     }
  243.                 }
  244.             }
  245.         }
  246.     }
  247. ?>
Advertisement
Add Comment
Please, Sign In to add comment