10ã¶æåãç§ã¯ãã©ãŠã¶ã®ããã¡ããäœãå§ããŸããã cocos jsã¯ã°ã©ãã£ãã¯ã¹ãšããŠãwebsocketã¯ãµãŒããŒãšã®éä¿¡ãšããŠéžæãããŸããã ç§ã¯ãã®ãã¯ãããžãŒãæ¬åœã«å¥œãã§ããã®äžã§ãµãŒããŒãšã®ã²ãŒã ã®éä¿¡ããã¹ãŠæŽçããŸããã
ãã®ããã«
ãã®èšäºã䜿çšããŸããã ããããæ®å¿µãªããããã®èšäºã«èšèŒãããŠããã³ãŒãã¯å®çšŒåã§ã¯äœ¿çšã§ããŸããã 倿ããããã«ãåé¡ã®ã¬ãã«ã¯é倧ã§ã¯ãªãããããã¯ãããŠããŸãã ãã¹ãŠãéåžžã«æªãã®ã§ããµãŒããŒãšã®ãã¹ãŠã®éä¿¡ãWebãœã±ãããããã³ã°ããŒã«ãŸã§æžãçŽãå¿
èŠããããŸããã æåŸã«ãããµãã¡ãªã§ã¯ãªããã©ãŠã¶ã䜿çšããŠããå Žåã¯websocketã䜿çšãããã以å€ã®å Žåã¯ãã³ã°ããŒãªã³ã°ããšãããªãã·ã§ã³ãæ®ãããã®ãããã¯ã«ã€ããŠããå°ãåå²ããŸãã
ãã®ãããå®çšŒåç°å¢ã§Webãœã±ããã䜿çšããçµéšã¯ãŸãšããªãã®ã«ãªããŸããã ãããŠæè¿ãããã¬ã«é¢ããæåã®èšäºãæžãããã«ä¿ããã€ãã³ããèµ·ãããŸããã
ããã¡ãããœãŒã·ã£ã«ãããã¯ãŒã¯ã«å
¬éãããåŸãèŠã€ãã£ããã¹ãŠã®ã¯ãªãã£ã«ã«/ããããã³ã°ãã°ãä¿®æ£ãããã¹ãŠãéããªã¢ãŒãã§æŽçãå§ããŸããã
ãã®äŸã¯ãäžè¬çã«ãã³ãŒãã«æ¿å
¥ããŠäœ¿çšã§ãããµãŒããŒã³ãŒããå«ãã€ã³ã¿ãŒãããäžã®å¯äžã®ã¬ã€ãã§ãããšããäºå®ã«æ³šç®ããããšæããŸãã ããŠãæ€çŽ¢ãšã³ãžã³ã§ãphp websocket serverããšå
¥åããŸã-èªåã§ã€ã³ã¹ããŒã«ã§ãããã®ãèŠã€ããŠãã ããã
çªç¶ãç§ã¯äžèšã®
èšäºãèªã¿çŽããæåã«ãphpdaemonããšãratchetããžã®ãªã³ã¯ãèŠã€ããŸããã ããã§ã¯ãå·éã«ã³ãŒããèŠãŠã¿ãŸãããã PhpDeamonã§ã¯ãWebSocketæ¥ç¶åŠçã®è
žå
ã§ãWebSocketãããã³ã«ãžã®å°ããªãããéåžžã«éèŠãªåå²ããããŸãã ãŸãã1ã€ã®ã±ãŒã¹ã§ãSafari5ãšå€ãã®éãã©ãŠã¶ãŒã¯ã©ã€ã¢ã³ãããšè¡šç€ºãããŸãã ç§ããããããªãããã ãšèšãããšã¯ãäœãèšããªãããšã§ãã ç§ã®ç®ã®åã§æ°çŸæéã®ãã©ãã·ã¥ãçºçããå€ãã®æéãšèŠãã¿ãããããããžã§ã¯ãå
šäœã«çåãæããããŸããã ä¿¡ããããªãã£ãã®ã§ã確èªããããšã«ããŸããã
ã15æé以å
ã«ãPhpDeamonããWebSocketã«é¢é£ããæå°éã®ã³ãŒããåŒãåºããŸããïŒææ°ããŒãžã§ã³ã®ãã¹ãŠã®ãã©ãŠã¶ãŒã§åäœãããµãŒããŒã³ãŒãèªäœã¯é«è² è·ã§ãåäœããŸãïŒã説æä»ãã§å
¬éããããšæããŸãã ä»ã®äººãç§ãçµéšããªããã°ãªããªãèŠçãçµéšããªãããã«ã ã¯ããã³ãŒãã¯å°ãããããŸããã§ããããç³ãèš³ãããŸãããWebSocketã¯ã¯ã©ã€ã¢ã³ãåŽã§ã¯éåžžã«ã·ã³ãã«ã§ããããµãŒããŒåŽã§ã¯ãã¹ãŠãéåžžã«å€§ãããªããŸãïŒSafariéçºè
ã«å¥ã®ãããããšãããšããŸãããïŒã ãŸããWebSocketã®ã¹ã³ãŒãã¯äž»ã«ã²ãŒã ã§ãããšããäºå®ã«ããããµãŒããŒãœã±ããã®ãã³ããããã³ã°äœ¿çšã®åé¡ãéèŠã§ã-ããã¯ããŒãã¹ã®è€éãã§ãããéåžžã«éèŠã§ããã
ããã§ã¯æ±ºããŠèæ
®ããŸããã
ããçè§£ããããããã«ããªããžã§ã¯ãã®ãªããã¹ãã¢ããªã±ãŒã·ã§ã³ãäœæãããã£ãã®ã§ãã ããããæ®å¿µãªããããã®äŸã®ãã®ã¢ãããŒãã§ã¯å€ãã®ç¹°ãè¿ãã³ãŒããçæãããããã1ã€ã®ã¯ã©ã¹ãš3ã€ã®ç¶æ¿è
ã远å ããå¿
èŠããããŸããã æ®ãã¯ãã¹ãŠãªããžã§ã¯ããªãã§ãã
ãŸããã¯ã©ã€ã¢ã³ãéšå<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>WebSocket test page</title> </head> <body onload="create();"> <script type="text/javascript"> function create() { </script> <button onclick="create();">Create WebSocket</button> <button onclick="ws.send('ping');">Send ping</button> <button onclick="ws.close();">Close WebSocket</button> <div id="log" style="width:300px; height: 300px; border: 1px solid #999999; overflow:auto;"></div> </body> </html>
ç§ã®ã²ãŒã ã§ã¯ã3ã€ã®ãµãŒããŒãœã±ããã䜿çšããå¿
èŠããããŸããã WebSocketãã¯ãŒã«ãŒçšãããã³ãã³ã°ããŒã«çšã ã²ãŒã ã«ã¯ããããã®æ°åŠããããŸãã®ã§ãç§ãã¡ã¯ã¯ãŒã«ãŒãããŠãã³ã³ãã¥ãŒãã£ã³ã°ã®ããã®ã¿ã¹ã¯ãäžããªããã°ãªããŸããã§ããã ãããç®çã§ãã ãã®stream_selectã¯ãããããã¹ãŠã«å
±éã§ããå¿
èŠããããŸããããã§ãªããšãé
å»¶ãçã£ãããã»ããµãŒäœ¿çšãçºçããŸãã ãã®ç¥èã¯ãäœ¿çšæžã¿ã®ç¥çµã®å±±ãšåŒãæãã«åŸãããŸããã
ã¡ã€ã³ãµãŒãã¹ãµã€ã¯ã« $master = stream_socket_server("tcp://127.0.0.1:8081", $errno, $errstr); if (!$master) die("$errstr ($errno)\n"); $sockets = array($master); stream_set_blocking($master, false);
æ°ããã¯ã©ã€ã¢ã³ããšã®æ¥ç¶ã¯éåžžã«æšæºçãªã³ãŒãã§ããããœã±ãããéãããã¯ã¢ãŒãã§ãããšããäºå®ã«ããããã¹ãŠã®çä¿¡ããŒã¿ãæççã«åéããååãªããŒã¿ãããå Žåã«ãããåŠçããå¿
èŠãªãããã³ã«ãçè§£ããã³ãŒãã®æãèšè¿°ããå¿
èŠããããŸããã®ãããã³ã«ã䜿çšããã«ã¯ã䜿çšããŠåãæ¿ããŸãã ãã®1ã€ã®ã¿ã¹ã¯ã¯ãã§ã«å€§éã®ã³ãŒãã§ãããPhpDeamonã§ã¯WebSocketãšã¯é¢ä¿ã®ãªãã³ãŒãã倧éã«ç©ã¿ãŸããïŒ8ã€ã®ç°ãªããµãŒããŒãããã«äžããããšãã§ããŸãïŒã ãã®ãããã¯ã§ã¯ãå€ãã®éšåãåãé¢ããŠåçŽåããããšãã§ããŸããã 圌ã¯WebSocketã«é¢é£ãããã®ã ããæ®ããŸããã
åãæšãŠããããã¡ã€ã«<ws.php> class ws { const MAX_BUFFER_SIZE = 1024 * 1024; protected $socket; public $server = []; protected $headers = []; protected $closed = false; protected $unparsed_data = ''; private $current_header; private $unread_lines = array(); protected $extensions = []; protected $extensionsCleanRegex = '/(?:^|\W)x-webkit-/iS'; protected $state = 0;
ãã®ãããªåãæšãŠããã圢åŒã§ã®ãã®ã¯ã©ã¹ã®æå³ã¯ãã¯ã©ã€ã¢ã³ãã«æ¥ç¶ããããã«ã³ã³ã¹ãã©ã¯ã¿ãŒã§éãããã¯ã¢ãŒããèšå®ããããšã§ãã æ¬¡ã«ãã¡ã€ã³ã«ãŒãã§ãããŒã¿ãå°çãããã³ã«ãããã«èªã¿åããã
unparsed_data ã倿°ã«è¿œå ïŒè¿œå ïŒããŸãïŒããã¯
on_receive_dataã¡ãœããã§ãïŒã MAX_BUFFER_SIZEã®æ¬¡å
ãè¶
ããŠããæªãããšã¯ãŸã£ããèµ·ãããªãããšãçè§£ããããšãéèŠã§ãã æåŸã®äŸã§ã¯ãããã§äœãèµ·ãããããã®å€ãã5ããšèšã£ãŠããã¹ãŠãåŒãç¶ãæ©èœããããšã確èªã§ããŸãã åçŽã«ãæåã®ã¹ãããã§ãããã¡ããã®ããŒã¿ã¯ç¡èŠãããŸã-çµå±ããããã¯äžå®å
šã§ããã2çªç®ã5çªç®ããŸãã¯100çªç®ã®ã¢ãããŒããããæåŸã«ããã¹ãŠã®åä¿¡ããŒã¿ãå
¥åãããåŠçãããŸãã åæã«ãstream_selectã¯ããã¹ãŠã®ããŒã¿ãååŸããããŸã§ãã¡ã€ã³ã«ãŒãã§ãã€ã¯ãç§ãåŸ
æ©ããŸããã äºæ³ãããããŒã¿ã®95ïŒ
ãå®å
šã«èªã¿åããããããªå®æ°ãéžæããå¿
èŠããããŸãã
ããã«ã¡ã€ã³ã«ãŒãïŒããŒã¿ã®æ¬¡ã®éšåãåãåã£ãåŸïŒã§ãèç©ãããããŒã¿ã®åŠçã詊ã¿ãŸãïŒããã¯
on_readã¡ãœããã§ãïŒã wsã¯ã©ã¹ã§ã¯ãon_readã¡ãœããã¯åºæ¬çã«ãæåã®è¡ãèªã¿åããç°å¢å€æ°ãæºåããããããã¹ãŠã®ããããŒãèªã¿åãããããã¹ãŠã®ããããŒãåŠçããããšãã3ã€ã®ã¹ãããã§æ§æãããŸãã æåã®2ã€ã¯èª¬æããå¿
èŠã¯ãããŸããããéããããã³ã°ã¢ãŒãã§ãããããŒã¿ãã©ãã§ãåŒãè£ãããŠãããšããäºå®ã«åããªããã°ãªããªããããããªã倧éã«æžãããŠããŸãã ããããŒã®åŠçã§ã¯ãæåã«èŠæ±ã®åœ¢åŒãæ£ãããã©ããããã§ãã¯ããæ¬¡ã«ããããŒãã¯ã©ã€ã¢ã³ããšéä¿¡ãããããã³ã«ã決å®ããŸãã ãã®çµæã
switch_to_protocolã¡ãœããããã«ããå¿
èŠããã
ãŸã ã å
éšã®ãã®ã¡ãœããã¯ãã¯ã©ã¹ãws_ <protocol>ãã®ã€ã³ã¹ã¿ã³ã¹ã圢æããã¡ã€ã³ã«ãŒãã«æ»ãæºåãããŸãã
ã¡ã€ã³ã«ãŒãã§ã¯ãå®éã«ããã«ç¢ºèªããå¿
èŠããããŸãããªããžã§ã¯ãã眮ãæããå¿
èŠããããã©ããïŒèª°ãããã®å Žæã®å®è£
ãããé©åã«æäŸã§ããå Žå-åžžã«æè¿ããŸãïŒã
次ã«ãã¡ã€ã³ã«ãŒãã§ããœã±ãããéããŠãããã©ããã確èªããå¿
èŠããããŸãã éããŠããå Žåã¯ãã¡ã¢ãªãã¯ãªã¢ããŸãïŒè©³çŽ°ã¯æ¬¡ã®ãããã¯ã§ïŒã
<deamon.php>ãã¡ã€ã«ã®ãã«ããŒãžã§ã³ require('ws.php'); require('ws_v0.php'); require('ws_v13.php'); require('ws_ve.php'); $master = stream_socket_server("tcp://127.0.0.1:8081", $errno, $errstr); if (!$master) die("$errstr ($errno)\n"); $sockets = array($master); $connections = array(); stream_set_blocking($master, false); $my_callback = function($connection, $data, $type) { var_dump('my ws data: ['.$data.'/'.$type.']'); $connection->send_frame('test '.time()); }; while (true) { $read = $sockets; $write = $except = array(); if (($num_changed_streams = stream_select($read, $write, $except, 0, 1000000)) === false) { var_dump('stream_select error'); break; } foreach ($read as $socket) { $index_socket = array_search($socket, $sockets); if ($index_socket == 0) {
ã$ My_callbackããããã«è¿œå ãããŸã-ããã¯ã¯ã©ã€ã¢ã³ãããã®ã«ã¹ã¿ã ã¡ãã»ãŒãžãã³ãã©ã§ãã ãã¡ãããæ¬çªç°å¢ã§ã¯ããããçš®é¡ã®ãªããžã§ã¯ãã«ãã¹ãŠãã©ããã§ããŸãããããã§ã¯é¢æ°å€æ°ã ããçè§£ããããããŸãã 圌女ã«ã€ããŠã¯å°ãåŸã§ã
æ°ããæ¥ç¶ã®åŠçãå®è£
ããã«ãŒãã®æ¬äœãå®è£
ããŸãããããã«ã€ããŠã¯ããå°ãäžã«æžããŸããã
ããã§ãµãŒããŒã³ãŒãã«æ³šæãããã§ãã ãœã±ããããèªã¿åãããããŒã¿ãç©ºã®æååã§ããå ŽåïŒãã¡ãããæŽæ°ã§ç©ºã®æååã®ãã§ãã¯ãèŠãå ŽåïŒããœã±ãããéããå¿
èŠããããŸãã ãããç§ã¯ãã®å¢ããã©ãã ãç§ã«è¡ã飲ãã ã®ãããããŠäœäººã®ãŠãŒã¶ãŒã倱ã£ãã®ãããç¥ããŸããã çªç¶ãSafariã¯ç©ºã®æååãéä¿¡ãããããæšæºãšèŠãªãããã®ã³ãŒãã¯ãŠãŒã¶ãŒãžã®æ¥ç¶ãååŸããŠéããŸãã Yandexãã©ãŠã¶ã¯æã
åãããã«åäœããŸãã çç±ã¯ããããŸãããããã®å ŽåãSafariã®å ŽåãWebSocketã¯ããªãŒãºãããŸãŸã§ããã€ãŸããéãããéããããã³ã°ããã ãã§ãã ç§ã¯ãã®éæ³ã®ãã©ãŠã¶ã«ç¡é¢å¿ã§ã¯ãªãããšã«æ°ã¥ããŸãããïŒ ç§ã¯IE6ãã©ã®ããã«äœãäžãããèŠããŠããŸã-åãæèŠã§ãã
次ã«ã
array_searchã䜿çšããŠã$ socketsé
åãš$ connectionsé
åãåæããçç±ã«ã€ããŠèª¬æããŸãã äºå®ãstream_selectã¯ã¯ãªãŒã³ãª$ãœã±ããé
åã«äžå¯æ¬ ã§ãããä»ã«ã¯äœããããŸããã ããããã©ããããããã$ socketsé
åã®ç¹å®ã®ãœã±ãããwsãªããžã§ã¯ãã«é¢é£ä»ããå¿
èŠããããŸãã ããããã®ãªãã·ã§ã³ã詊ããŠã¿ãŸãã-æçµçã«ãããŒã§åžžã«åæããã2ã€ã®ã¢ã¬ã€ããããããªãªãã·ã§ã³ã§åæ¢ããŸããã 1ã€ã®é
åã§ã¯ãstream_selectã«å¿
èŠãªã¯ãªãŒã³ãœã±ããã2çªç®ã®é
åã§ã¯ãwsã¯ã©ã¹ãŸãã¯ãã®åå«ã®ã€ã³ã¹ã¿ã³ã¹ã 誰ããããè¯ããã®å ŽæãæäŸã§ããå Žå-æäŸããŠããŸãã
泚æãã¹ããã1ã€ã®ã±ãŒã¹ã¯ã
stream_socket_acceptã«æ¬ é¥
ãããå Žåã§ãã ç§ãçè§£ããŠããããã«ãçè«çã«ã¯ããã¹ã¿ãŒãœã±ãããéããããã³ã°ã¢ãŒãã§ãããã¯ã©ã€ã¢ã³ããæ¥ç¶ããã®ã«ååãªããŒã¿ãå°çããŠããªãå Žåã«ã®ã¿å¯èœã§ãã ãããã£ãŠãäœãããŸããã
ãã¡ã€ã«<ws.php>ã®ãã«ããŒãžã§ã³ class ws { private static $hvaltr = ['; ' => '&', ';' => '&', ' ' => '%20']; const maxAllowedPacket = 1024 * 1024 * 1024; const MAX_BUFFER_SIZE = 1024 * 1024; protected $socket; public $server = []; protected $on_frame_user = null; protected $handshaked = false; protected $headers = []; protected $headers_sent = false; protected $closed = false; protected $unparsed_data = ''; private $current_header; private $unread_lines = array(); private $new_instance = null; protected $extensions = []; protected $extensionsCleanRegex = '/(?:^|\W)x-webkit-/iS'; protected $state = 0;
å®éã«ã¯ããWebãœã±ããã¬ãã«ã§ã¯ã©ã€ã¢ã³ãã«æ¥ç¶ãããããã¯ã©ã€ã¢ã³ãããã¡ãã»ãŒãžãåä¿¡ãããããã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããããšãã3ã€ã®ããšã远å ãããŸãã
ãŸããããã€ãã®çè«ãšçšèªã ããã³ãã·ã§ã€ã¯ãã¯ãWebãœã±ããã®èгç¹ãããhttpãä»ããæ¥ç¶ã確ç«ããããã®æé ã§ãã çµå±ã®ãšãããäžé£ã®è³ªåã解決ããå¿
èŠããããŸãããããã·ãšãã£ãã·ã¥ã®åãéšåãçªç Žããæ¹æ³ãéªæªãªããã«ãŒãã身ãå®ãæ¹æ³ã§ãã ããã¬ãŒã ããšããçšèªã¯ã埩å·åããã圢åŒã®ããŒã¿ã§ããããã¯ãã¯ã©ã€ã¢ã³ãããã®ã¡ãã»ãŒãžãŸãã¯ã¯ã©ã€ã¢ã³ããžã®ã¡ãã»ãŒãžã§ãã ããããèšäºã®åé ã§ããã«ã€ããŠæžã䟡å€ã¯ãããŸãããããããã®ããã¬ãŒã ãã®ããã«ããœã±ãããµãŒããŒãããããã³ã°ãœã±ããã¢ãŒãã«ããããšã¯æå³ããããŸããã ãã®ç¬éã
ããã§è¡ãã
ãæ¹æ³ -ããã¯ç§ãäžæ©ä»¥äžç¡ç ã奪ã£ãã ãã®èšäºã§ã¯ããªãã·ã§ã³ã¯ãã¬ãŒã ãå®å
šã«å°çããªãã£ãããŸãã¯2ã€ãäžåºŠã«å°çãããšã¯èŠãªãããŸããã ã¡ãªã¿ã«ãã²ãŒã ãã°ã瀺ããããã«ããããšããã¯éåžžã«å
žåçãªç¶æ³ã§ãã
ããŠè©³çްã«ã
Webãœã±ããã¬ãã«ã§ã®ã¯ã©ã€ã¢ã³ããžã®æ¥ç¶ -ãããã³ã«ïŒws_v0ãªã©ïŒãon_readã¡ãœããããããã¯ããååãªããŒã¿ããããšãã«å
éšã§ãã³ãã·ã§ã€ã¯ããã«ãããšæ³å®ãããŸããæ¬¡ã¯ã芪ã®ãæ¡æãã§ããæ¬¡ã«ãsend_handshake_replyã¡ãœãããäœåããŸããããã¯ãããã³ã«ã«å®è£
ããå¿
èŠããããŸãããã®ãsend_handshake_replyãã¯ããæ¥ç¶ã確ç«ãããããšããéåžžã®ãã©ãŠã¶-éåžžã®åçãããã³Safari-ç¹å¥ãªåçãçè§£ãããããªæ¹æ³ã§ã¯ã©ã€ã¢ã³ãã«å¿çããå¿
èŠããããŸããã¯ã©ã€ã¢ã³ãããã¡ãã»ãŒãžãåä¿¡ãããæããªã¯ã©ã€ã¢ã³ãã¯ãæ¥ç¶ã確ç«ãããããŠãŒã¶ãŒããã®ã¡ãã»ãŒãžããã§ã«å°çããŠãããããªãªãã·ã§ã³ãå®è£
ã§ããããšã«æ³šæããŠãã ããããããã£ãŠããunparsed_dataã倿°ãæ
éã«æ±ãå¿
èŠããããŸããåãããã³ã«ã§ãon_readã¡ãœããã¯éä¿¡ããããã¬ãŒã ã®ãµã€ãºãçè§£ãããã¬ãŒã å
šäœãå°çããããšã確èªãããŠãŒã¶ãŒã®ã¡ãã»ãŒãžã§å°çãããã¬ãŒã ã埩å·åããå¿
èŠããããŸããåãããã³ã«ã§ãããã¯éåžžã«ç°ãªã£ãŠéåžžã«ã«ãŒãªãŒã«è¡ãããŸãïŒãã¬ãŒã ãå®å
šã«å°çãããã©ããã¯ããããŸããããæ¬¡ã®ãã¬ãŒã ã®ãã€ããåãããšã¯ã§ããŸããïŒãããã«ãon_readãã®å
éšã§ãã¯ã©ã€ã¢ã³ãããŒã¿ãåä¿¡ããã³åŸ©å·åããããã®ã¿ã€ããæ±ºå®ããããšïŒã¯ãããã®ããã«æäŸãããŸãïŒããon_frameãã¡ãœããããã«ããŸãã my_callbackãã¡ã€ã³ã«ãŒãã®åïŒãã®çµæã$ my_callbackã¯ã¯ã©ã€ã¢ã³ãããã¡ãã»ãŒãžãåãåããŸããã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããŸãããsend_frameãã¡ãœããã¯ããããã³ã«å
ã«å®è£
ããå¿
èŠãããã ãã§ãã²ãã€ããŸããããã§ã¯ãã¡ãã»ãŒãžãæå·åããŠãŠãŒã¶ãŒã«éä¿¡ããã ãã§ããç°ãªããããã³ã«ã¯ç°ãªãæ¹æ³ã§æå·åããŸããçŸåšã3ã€ã®ãããã³ã«ãv13ãããv0ãããveããæ·»ä»ããŠããŸãããã¡ã€ã«<ws_v13.php> class ws_v13 extends ws { const CONTINUATION = 0; const STRING = 0x1; const BINARY = 0x2; const CONNCLOSE = 0x8; const PING = 0x9; const PONG = 0xA; protected static $opcodes = [ 0 => 'CONTINUATION', 0x1 => 'STRING', 0x2 => 'BINARY', 0x8 => 'CONNCLOSE', 0x9 => 'PING', 0xA => 'PONG', ]; protected $outgoingCompression = 0; protected $framebuf = ''; public function mask($data, $mask) { for ($i = 0, $l = strlen($data), $ml = strlen($mask); $i < $l; $i++) { $data[$i] = $data[$i] ^ $mask[$i % $ml]; } return $data; } public function send_frame($data, $type = null, $cb = null) { if (!$this->handshaked) { return false; } if ($this->closed && $type !== 'CONNCLOSE') { return false; } $fin = 1; $rsv1 = 0; $rsv2 = 0; $rsv3 = 0; $this->write(chr(bindec($fin . $rsv1 . $rsv2 . $rsv3 . str_pad(decbin($this->get_frame_type($type)), 4, '0', STR_PAD_LEFT)))); $dataLength = strlen($data); $isMasked = false; $isMaskedInt = $isMasked ? 128 : 0; if ($dataLength <= 125) { $this->write(chr($dataLength + $isMaskedInt)); } elseif ($dataLength <= 65535) { $this->write(chr(126 + $isMaskedInt) .
ãã¡ã€ã«<ws_v0.php> class ws_v0 extends ws { const STRING = 0x00; const BINARY = 0x80; protected $key; public function send_handshake_reply($extraHeaders = '') { if (!isset($this->server['HTTP_SEC_WEBSOCKET_KEY1']) || !isset($this->server['HTTP_SEC_WEBSOCKET_KEY2'])) { return false; } $final_key = $this->_computeFinalKey($this->server['HTTP_SEC_WEBSOCKET_KEY1'], $this->server['HTTP_SEC_WEBSOCKET_KEY2'], $this->key); $this->key = null; if (!$final_key) { return false; } if (!isset($this->server['HTTP_SEC_WEBSOCKET_ORIGIN'])) { $this->server['HTTP_SEC_WEBSOCKET_ORIGIN'] = ''; } $this->write("HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . "Upgrade: WebSocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Origin: " . $this->server['HTTP_ORIGIN'] . "\r\n" . "Sec-WebSocket-Location: ws://" . $this->server['HTTP_HOST'] . $this->server['REQUEST_URI'] . "\r\n"); if (isset($this->server['HTTP_SEC_WEBSOCKET_PROTOCOL'])) { $this->write("Sec-WebSocket-Protocol: " . $this->server['HTTP_SEC_WEBSOCKET_PROTOCOL']."\r\n"); } $this->write($extraHeaders . "\r\n" . $final_key); return true; } protected function _computeFinalKey($key1, $key2, $data) { if (strlen($data) < 8) { error_log(get_class($this) . '::' . __METHOD__ . ' : Invalid handshake data for client ""');
ãã¡ã€ã«<ws_ve.php> class ws_ve extends ws { const STRING = 0x00; const BINARY = 0x80; public function send_handshake_reply($extraHeaders = '') { if (!isset($this->server['HTTP_SEC_WEBSOCKET_ORIGIN'])) { $this->server['HTTP_SEC_WEBSOCKET_ORIGIN'] = ''; } $this->write("HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . "Upgrade: WebSocket\r\n" . "Connection: Upgrade\r\n" . "Sec-WebSocket-Origin: " . $this->server['HTTP_ORIGIN'] . "\r\n" . "Sec-WebSocket-Location: ws://" . $this->server['HTTP_HOST'] . $this->server['REQUEST_URI'] . "\r\n" ); if (isset($this->server['HTTP_SEC_WEBSOCKET_PROTOCOL'])) { $this->write("Sec-WebSocket-Protocol: " . $this->server['HTTP_SEC_WEBSOCKET_PROTOCOL']."\r\n"); } $this->write($extraHeaders."\r\n"); return true; } protected function _computeKey($key) { $spaces = 0; $digits = ''; for ($i = 0, $s = strlen($key); $i < $s; ++$i) { $c = substr($key, $i, 1); if ($c === "\x20") { ++$spaces; } elseif (ctype_digit($c)) { $digits .= $c; } } if ($spaces > 0) { $result = (float)floor($digits / $spaces); } else { $result = (float)$digits; } return pack('N', $result); } public function send_frame($data, $type = null, $cb = null) { if (!$this->handshaked) { return false; } if ($this->closed && $type !== 'CONNCLOSE') { return false; } if ($type === 'CONNCLOSE') { if ($cb !== null) { $cb($this); return true; } }
VEãããã³ã«ã¯ãŸã ãã¹ããããŠããªãããšã«æ³šæããŠãã ãã-誰ãããã䜿çšããã®ãããããŸãããããããPhpDeamonããã³ãŒããå¿ å®ã«å€æããŠã«ããããŸãããV13ãããã³ã«ã¯ããã¹ãŠã®éåžžã®ãã©ãŠã¶ãŒïŒFireFoxãOperaãChromeãYandexïŒã§äœ¿çšãããŸããIEã§ã䜿çšããŸãïŒIE6以éãç³ãèš³ãããŸããããIEãããã©ãŠã¶ãã«ãªãããšã¯ãããŸãããIEéçºããŒã ã§ãããããã©ãŠã¶ã§ã¯ãªãã·ã³ã¯ã©ã€ã¢ã³ãããšè¿°ã¹ãŠããŸãïŒãV0ãããã³ã«ã¯Safariãã©ãŠã¶ãŒã䜿çšããŸããçµè«ã®ä»£ããã«
泚æããŠãã ãããå¥åº·ã®ããã«äžèšã®ãã¹ãŠã®ã³ãŒãã䜿çšããŠãã ããïŒãã¡ãããéåžžã®ãªããžã§ã¯ãã«ã©ããããããšããå§ãããŸãããã¹ãŠãçè§£ã®ããã«åçŽåãããŠããŸãããã®ã³ãŒãã䜿çšããå Žåã¯ããThanks Anlide and PhpDeamonããšããã³ãŒãã®ã©ããã«æžããŠãã ããããã®çµæãããã«ç€ºãããŠãããœã±ãããµãŒããŒã¯ããã¹ãŠã®ææ°ã®ãã©ãŠã¶ãŒãšäºææ§ããããŸããã¡ã¢ãªãªãŒã¯ãªãã§åäœããè² è·ã®é«ãã·ã¹ãã ã§ã®äœ¿çšã«é©ããŠããŸããæŽæ°ïŒ- èšäºã®èè
ã®ã³ã¡ã³ããç§ã¯ããã¹ãã§åžžã«èšåããŠããŸãïŒhabrahabr.ru/post/301822/#comment_9634636
- read_lintïŒïŒã¡ãœããã«ã¯ãšã©ãŒãå«ãŸããŠããŸããããã¯ãããããŒã®ã¿ãèªã¿åãå¿
èŠãããã«ãããããããhttpãªã¯ãšã¹ãæ¬æã®æ¬æãèªã¿åã£ãŠãããšããããšã§ãã
- â .
- gitbub github.com/anlide/websocket ping-pong , select - â websocket.