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/
- websocket学习记录
- websocket 学习 -
- websocket学习
- websocket学习
- websocket 学习
- websocket web 实现记录
- WebSocket发展记录
- websocket踩坑记录
- JAVA知识 简单记录-WebSocket
- 对于js中网络接口websocket,二进制数组arraybuffer,视图对象dataview学习记录。
- WebSocket学习(一)——webSocket简介
- websocket学习笔记
- Websocket学习--简易聊天室
- WebSocket 学习概要
- WebSocket for Ruby 学习
- WebSocket学习笔记一
- tornado websocket 学习历程
- websocket协议学习
- Builder模式很简单
- Android LayoutInflater原理分析,带你一步步深入了解View(一)
- c++内存泄漏处理(积累)
- hdu4619Warm up 2
- uva 1378 - A Funny Stone Game(组合游戏)
- websocket学习记录
- Android中pendingIntent的深入理解
- 【环境搭建】Redhat 5.8系统安装R语言作Arima模型预测
- LeetCode OJ算法题(五十七):Length of Last Word
- cc、gcc、g++、CC的区别概括
- 在项目中运用精益——Five Why
- (搜索)跳棋系列7
- C++调用成员函数需要this指针的情况
- MySQL初始设置