PHP-реализация 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 — фреймворк асинхронных приложений
Положил статью в закладки и теперь с удовольствием могу поделиться с вами. )