PHP-реализация WebSockets

Здравствуйте, написал небольшой скрипт для работы с WebSockets относительно скриптов в паблике.
По идее должно работать отлично, но всё не так, как хотелось бы :(
Когда я отправляю данные из браузера (подопытный Google Chrome 18) на сервер, то php-демон должен писать мне эти данные в терминал. Однако, вместо данных присылаются непонятные рандомные символы. Расскажите пожалуйста, каким образом их нужно дешифровать или же исправьте мой код, пожалуйста.
Спасибо заранее.

client.html

/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .html4strict.geshi_code {font-family:monospace;} .html4strict.geshi_code .imp {font-weight: bold; color: red;} .html4strict.geshi_code .kw2 {color: #000000; font-weight: bold;} .html4strict.geshi_code .kw3 {color: #000066;} .html4strict.geshi_code .es0 {color: #000099; font-weight: bold;} .html4strict.geshi_code .br0 {color: #66cc66;} .html4strict.geshi_code .sy0 {color: #66cc66;} .html4strict.geshi_code .st0 {color: #ff0000;} .html4strict.geshi_code .nu0 {color: #cc66cc;} .html4strict.geshi_code .sc-1 {color: #808080; font-style: italic;} .html4strict.geshi_code .sc0 {color: #00bbdd;} .html4strict.geshi_code .sc1 {color: #ddbb00;} .html4strict.geshi_code .sc2 {color: #009900;} .html4strict.geshi_code span.xtra { display:block; }

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

<script type="text/javascript">
$(document).ready(function() {
 
  if(!("WebSocket" in window)){
    $('#chatLog, input, button, #examples').fadeOut("fast");  
    $('<p>Oh no, you need a browser that supports WebSockets. How about <a href="http://www.google.com/chrome">Google Chrome</a>?</p>').appendTo('#container');    
  }else{
    //The user has WebSockets
 
  connect();
   
  function connect(){
      var socket;
      var host = "ws://localhost:10001/foreveralone/server.php";
     
      try{
        var socket = new WebSocket(host);
        message('<p class="event">Socket Status: '+socket.readyState);
        socket.onopen = function(){
          message('<p class="event">Socket Status: '+socket.readyState+' (open)');  
        }
       
        socket.onmessage = function(msg){
          message('<p class="message">Received: '+msg.data);          
        }
       
        socket.onclose = function(){
          message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
        }      
         
      } catch(exception){
        message('<p>Error'+exception);
      }
       
      function send(){
        var text = $('#text').val();
        if(text==""){
          message('<p class="warning">Please enter a message');
          return ;  
        }
        try{
          socket.send(text);
          message('<p class="event">Sent: '+text)
        } catch(exception){
          message('<p class="warning">');
        }
        $('#text').val("");
      }
     
      function message(msg){
        $('#chatLog').append(msg+'</p>');
      }//End message()
     
      $('#text').keypress(function(event) {
            if (event.keyCode == '13') {
             send();
             }
      });  
     
      $('#disconnect').click(function(){
        socket.close();
      });

    }
   
   
  }//End connect()
   
});
</script>

<style type="text/css">
body{font-family:Arial, Helvetica, sans-serif;}
#container{
  border:5px solid grey;
  width:800px;
  margin:0 auto;
  padding:10px;
}
#chatLog{
  padding:5px;
  border:1px solid black;  
}
#chatLog p{margin:0;}
.event{color:#999;}
.warning{
  font-weight:bold;
  color:#CCC;
}
</style>
<title>WebSockets Client</title>

</head>
<body>
  <div id="wrapper">
 
    <div id="container">
   
      <h1>WebSockets Client</h1>
       
        <div id="chatLog">
       
        </div>
        <p id="examples">e.g. try 'hi', 'name', 'age', 'today'</p>
       
      <input id="text" type="text" />
        <button id="disconnect">Disconnect</button>

  </div>
 
  </div>
</body>
</html>
 


server.php

/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .php.geshi_code {font-family:monospace;} .php.geshi_code .imp {font-weight: bold; color: red;} .php.geshi_code .kw1 {color: #b1b100;} .php.geshi_code .kw2 {color: #000000; font-weight: bold;} .php.geshi_code .kw3 {color: #990000;} .php.geshi_code .co1 {color: #666666; font-style: italic;} .php.geshi_code .co2 {color: #666666; font-style: italic;} .php.geshi_code .co3 {color: #0000cc; font-style: italic;} .php.geshi_code .co4 {color: #009933; font-style: italic;} .php.geshi_code .coMULTI {color: #666666; font-style: italic;} .php.geshi_code .es0 {color: #000099; font-weight: bold;} .php.geshi_code .es1 {color: #000099; font-weight: bold;} .php.geshi_code .es2 {color: #660099; font-weight: bold;} .php.geshi_code .es3 {color: #660099; font-weight: bold;} .php.geshi_code .es4 {color: #006699; font-weight: bold;} .php.geshi_code .es5 {color: #006699; font-weight: bold; font-style: italic;} .php.geshi_code .es6 {color: #009933; font-weight: bold;} .php.geshi_code .es_h {color: #000099; font-weight: bold;} .php.geshi_code .br0 {color: #009900;} .php.geshi_code .sy0 {color: #339933;} .php.geshi_code .sy1 {color: #000000; font-weight: bold;} .php.geshi_code .st0 {color: #0000ff;} .php.geshi_code .st_h {color: #0000ff;} .php.geshi_code .nu0 {color: #cc66cc;} .php.geshi_code .nu8 {color: #208080;} .php.geshi_code .nu12 {color: #208080;} .php.geshi_code .nu19 {color:#800080;} .php.geshi_code .me1 {color: #004000;} .php.geshi_code .me2 {color: #004000;} .php.geshi_code .re0 {color: #000088;} .php.geshi_code span.xtra { display:block; }

<?
  header('Content-Type: text/plain;'); // хэйдер возвращение данных
  set_time_limit(0); // заставляет работать php-скрипт как демон
  ob_implicit_flush(true); // отправляет информацию вне зависимости от того, закончил ли работать php-скрипт или нет
  $sockets = array(); // все сокеты
  $handshakes = array(); // массив рукопожатий (отдаём информацию о том, что это не просто сокет, а сокет по стандарту WebSocket
 
  $sockets["server"] = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);  // создаём главный сокет-сервер, к которому будут обращаться клиенты
  socket_bind($sockets["server"], "localhost", 10001); // прикрепляем главный сокет-сервер к адресу ws://localhost:10001/%server%.php
  socket_set_option($sockets["server"],SOL_SOCKET,SO_REUSEADDR,1); // разрешаем использовать один порт для нескольких соединений
  socket_listen($sockets["server"], 20); // ставим лимит подключений (20)

  while (true) { // скрипт работает постоянно
    $changed_sockets = $sockets;
    $num_sockets = socket_select($changed_sockets, $write=NULL,$exceptions=NULL,NULL); // проверим все сокеты на изменение статуса по сравнению с прошлым разом
    foreach($changed_sockets as $socket) { // просмотрим каждый из сокетов, который изменил свой статус
      if($socket == $sockets["server"]) { // значит серверу пришли данные о установлении связи между клиентом и сервером
  if (($client = socket_accept($sockets["server"])) >= 0) $sockets[] = $client; // если удалось установить связь, то добавляем в список всех сокетов
      } else {
  $index = array_search($socket, $sockets);
  $len = @socket_recv($socket,$buffer,4096,0); // получаем информацию от сокета
  if($len == 0) { // если статус сокета изменился, а данных нет, то значит сокет закрылся и мы должны убрать его из списка
    unset($sockets[$index]);
    unset($handshakes[$index]);
    socket_close($socket);
  }
  else if(!isset($handshakes[$index])) { // говорили ли мы уже этому подключению, что мы - WebSocket?
   $buffer = substr($buffer,strpos($buffer,"Sec-WebSocket-Key: ")+19);
   $accept = base64_encode(sha1(substr($buffer,0,strpos($buffer,"rn")) . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
   $upgrade  = "HTTP/1.1 101 Switching Protocolsrn" .
         "Upgrade: websocketrn" .
         "Connection: Upgradern" .
         "Sec-WebSocket-Accept: {$accept}rnrn" .
         "Sec-Websocket-Extensions=x-webkit-deflate-frame"  . chr(0);

   socket_write($socket,$upgrade,strlen($upgrade)); // отправляем пакет о нас
   $handshakes[$index] = true; // теперь сказали
  }
  else {
    echo 'buf:'.$buffer."rn";
  }
      }
    }
  }
?>
 

1 ответов


//Unmask incoming framed message
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;
}

//Encode message for transfer to client.
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;
}

http://www.sanwebe.com/2013/05/chat-using-websocket-php-socket


Знаете, совсем недавно я задумывался над созданием игры на основе WebSockets.
Изучив много материала в интернете, наткнулся на статью на хабре.
phpDaemon — фреймворк асинхронных приложений
Положил статью в закладки и теперь с удовольствием могу поделиться с вами. )