websocket学习记录

来源:互联网 发布:柏拉图聊天软件 编辑:程序博客网 时间:2024/06/05 21:25

经过三天艰苦地探索,终于初探websocket成功

环境,chrome 版本 36.0.1985.125

参考:

wiki关于websocket 握手协议 : http://zh.wikipedia.org/wiki/WebSocket#.E6.8F.A1.E6.89.8B.E5.8D.8F.E8.AE.AE

les5332295 : http://blog.csdn.net/les5332295/article/details/7014799

一:握手协议



这是chrome发给我的数据,我们只需要关心,Sec-WebSocket-Key的值

把“Sec-WebSocket-Key”加上一个魔幻字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。使用 SHA-1 加密,之后进行 BASE-64编码,将结果做为 “Sec-WebSocket-Accept” 头的值,返回给客户端.

这是发送给浏览器的内容

当浏览器接收到正确的Sec-WebSocket-Accept之后,websocket连接就建立成功了,这时发送数据要按照websocket协议进行

二:收发数据

1.首先是client to server

示例:

"hi"

服务器接收到的数据的16进制为:


0x81: 0x81是固定的

0x82 第二个字节是字符串长度 0x02加上固定值0x80

70 b1 28 71 接下来4个字节是密码字符串,用来加密字符串,

0x18 0xd8 之后的数据是加密后的字符串(0x18 0xd8就是加密后的h 和 i)

加密方法是这样:

密码:   makr[4]浏览器随机生成

要加密的字符串:   data[n]长度n

加密后的字符串: res[n]长度n

for(i=0;i<n;++i)

res[i]=data[i]^mark[i%4];//  ^ 异或


示例中的0x18='h'^0x70

0xd8='i'^0xb1


2.然后是server to client

示例:

"zup human"

服务器发送数据的16进制是这样的


0x81 同样0x81是固定的

0x09 第二个字节是字符串长度    "zup human"的长度是9

0x75~0x6e 接下来是没有加密的字符串

(图中 '>' 字符之后的是发送的数据)


具体协议请参考: (本人英语很差,没有领悟)

英文资料 : http://datatracker.ietf.org/doc/rfc6455/?include_text=1


三:下面我的测试代码

服务器:

用命令 php + 文件名 启动

<?phpclass WebSocket{    var $master;    var $sockets = array();    var $users   = array();    var $debug   = true;    function __construct($address,$port){        error_reporting(E_ALL);        set_time_limit(0);        ob_implicit_flush();        $this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)     or die("socket_create() failed");        socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1)  or die("socket_option() failed");        socket_bind($this->master, $address, $port)                    or die("socket_bind() failed");        socket_listen($this->master,20)                                or die("socket_listen() failed");        $this->sockets[] = $this->master;        $this->say("Server Started : ".date('Y-m-d H:i:s'));        $this->say("Listening on   : ".$address." port ".$port);        $this->say("Master socket  : ".$this->master."\n");        while(true){            $changed = $this->sockets;            socket_select($changed,$write=NULL,$except=NULL,NULL);            foreach($changed as $socket){                if($socket==$this->master){                    $client=socket_accept($this->master);                    if($client<0){$this->log("socket_accept() failed"); continue; }                    else{$this->connect($client); }                }                else{                    $bytes = @socket_recv($socket,$buffer,2048,0);                    if($bytes==0){ $this->disconnect($socket); }                    else{                        $user = $this->getuserbysocket($socket);                        $this->log("handshake:".$user->handshake);                        if(!$user->handshake){ $this->dohandshake($user,$buffer); }                        else{                            $payload = $this->read($buffer,$bytes);                            $this->process($user,$payload);                         }                    }                }            }        }    }    function process($user,$msg){        $this->send($user->socket,$msg);    }    function read($buffer,$bytes){        for($i=0;$i<$bytes;++$i){            printf("%x ",ord($buffer[$i]));        }        printf("\n");        if ($bytes<126) {            $this->log(dechex(ord($buffer[0])));            $this->log(dechex(ord($buffer[1])));            $mask="";            for ($i = 0; $i <= 3; $i++) {                $mask.=$buffer[2+$i];            }            $payload="";            $payload_start = 6;            for ($i = $payload_start; $i < $bytes; $i++) {                $payload.=$mask[($i - $payload_start) % 4]^$buffer[$i];                 }        }        return $payload;    }    function send($client,$msg){        $msg = chr(0x81).chr(strlen($msg)).$msg;        for($i=0;$i<strlen($msg);++$i){            printf("%x ",ord($msg[$i]));        }        printf("\n");        $this->say("> ".$msg);        socket_write($client,$msg,strlen($msg));        //@socket_send($client,$msg,strlen($msg),0);        $this->say("! ".strlen($msg));    }    function connect($socket){        $user = new User();        $user->id = uniqid();        $user->socket = $socket;        array_push($this->users,$user);        array_push($this->sockets,$socket);        $this->log($socket." CONNECTED!");        $this->log(date("d\n/Y ")."at ".date("H:i:s T"));    }    function disconnect($socket){        $found=null;        $n=count($this->users);        for($i=0;$i<$n;$i++){            if($this->users[$i]->socket==$socket){ $found=$i; break; }        }        if(!is_null($found)){ array_splice($this->users,$found,1); }        $index=array_search($socket,$this->sockets);        socket_close($socket);        $this->log($socket." DISCONNECTED!");        if($index>=0){ array_splice($this->sockets,$index,1); }    }    function dohandshake($user,$buffer){        $this->log("\nRequesting handshake...");        $this->log($buffer);        list($resource,$upgrade,$connection,$host,$origin,$key,$version) = $this->getheaders($buffer);        $this->log("Handshaking...");        $upgrade  = "HTTP/1.1 101 Switching Protocols\r\n" .        "Upgrade: websocket\r\n" .        "Connection: Upgrade\r\n" .        "Sec-WebSocket-Accept: " . base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true)) . "\r\n".        "Sec-WebSocket-Origin: null\r\n" .        "Sec-WebSocket-Location: ws://" . $host . $resource . "\r\n" .        "\r\n";        socket_write($user->socket,$upgrade,strlen($upgrade));        $user->handshake=true;        $this->log($upgrade);        $this->log("Done handshaking...");        return true;    }    function getheaders($req){        if(preg_match("/GET (.*) HTTP/"                     ,$req,$match)){ $r=$match[1]; }        if(preg_match("/Upgrade: (.*)\r\n/"                 ,$req,$match)){ $u=$match[1]; }        if(preg_match("/Connection: (.*)\r\n/"              ,$req,$match)){ $c=$match[1]; }        if(preg_match("/Host: (.*)\r\n/"                    ,$req,$match)){ $h=$match[1]; }        if(preg_match("/Origin: (.*)\r\n/"                  ,$req,$match)){ $o=$match[1]; }        if(preg_match("/Sec-WebSocket-Key: (.*)\r\n/"       ,$req,$match)){ $k=$match[1]; }        if(preg_match("/Sec-WebSocket-Version: (.*)\r\n/"   ,$req,$match)){ $v=$match[1]; }        return array($r,$u,$c,$h,$o,$k,$v);    }    function getuserbysocket($socket){        $found=null;        foreach($this->users as $user){            if($user->socket==$socket){ $found=$user; break; }        }        return $found;    }    function     say($msg=""){ echo $msg."\n"; }    function     log($msg=""){ if($this->debug){ echo "\n--->".$msg."\n"; } }}class User{    var $id;    var $socket;    var $handshake;}$master = new ChatBot("localhost",12345);?>

客户端

用chrome打开

<html><head><title>WebSocket</title><style> html,body{font:normal 0.9em arial,helvetica;} #log {width:440px; height:200px; border:1px solid #7F9DB9; overflow:auto;} #msg {width:330px;}</style><script>var socket;function init(){  var host = "ws://localhost:12345/websocket/php/server.php";  try{    log("init");    socket = new WebSocket(host);    log('WebSocket - status '+socket.readyState);    socket.onopen    = function(msg){ log("Welcome - status "+this.readyState); };    socket.onmessage = function(msg){ log("Received: "+msg.data); };    socket.onclose   = function(msg){ log("Disconnected - status "+this.readyState); };  }  catch(ex){ log(ex); }  $("msg").focus();}function send(){  var txt,msg;  txt = $("msg");  msg = txt.value;  if(!msg){ alert("Message can not be empty"); return; }  txt.value="";  txt.focus();  try{ socket.send(msg); log('Sent: '+msg); } catch(ex){ log(ex); }}function quit(){  log("Goodbye!");  socket.close();  socket=null;}// Utilitiesfunction $(id){ return document.getElementById(id); }function log(msg){ $("log").innerHTML+="<br>"+msg; }function onkey(event){ if(event.keyCode==13){ send(); } }</script></head><body onload="init()"> <h3>WebSocket v2.00</h3> <div id="log"></div> <input id="msg" type="textbox" onkeypress="onkey(event)"/> <button onclick="send()">Send</button> <button onclick="quit()">Quit</button></body></html>

代码参考来源 https://code.google.com/p/phpwebsocket/

0 0
原创粉丝点击