websocket学习记录

经过三天艰苦地探索,终于初探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 + 文件名 启动

<?php
class 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;
}
// Utilities
function $(id){ return document.getElementById(id); }
function log(msg){ $("log").innerHTML+="<br>"+msg; }
function onkey(event){ if(event.keyCode==13){ send(); } }
</script>
</head>
<body οnlοad="init()">
 <h3>WebSocket v2.00</h3>
 <div id="log"></div>
 <input id="msg" type="textbox" οnkeypress="onkey(event)"/>
 <button οnclick="send()">Send</button>
 <button οnclick="quit()">Quit</button>
</body>
</html>

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值