Skip to content

Commit 605db77

Browse files
websocket
1 parent e7cada6 commit 605db77

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+1058
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>hook</title>
6+
</head>
7+
<body>
8+
<script language="JavaScript" type="text/javascript">
9+
// 钩子一
10+
var load_func_init = function() {
11+
alert("load_func_init");
12+
}
13+
// 钩子二
14+
var load_func_scroll = function() {
15+
alert("load_func_scroll");
16+
}
17+
18+
// 创建一个JS钩子,处理钩子的对象
19+
var Hook = (function() {
20+
// 返回一个对象,这是一个的钩子对象
21+
return {
22+
init: function(parameter) {
23+
this.callHook(parameter);
24+
},
25+
callHook: function(parameter) {
26+
var s = parameter + "_func";
27+
var f = [];
28+
for (var h in window) {
29+
if (h.indexOf(s) != 0) continue;
30+
f.push(h);
31+
}
32+
this.actionHook(f);
33+
},
34+
actionHook: function(array_hook) {
35+
var _s, _func, _array = array_hook || [],
36+
len = _array.length;
37+
if (0 === len) return;
38+
for (var i = 0; i < len; i++) {
39+
_s = _array[i];
40+
_func = window[_s];
41+
if (_func === undefined) continue;
42+
_func.apply();
43+
}
44+
}
45+
}
46+
}());
47+
onload = function() {
48+
// 页面加载完成后使用钩子(调用)
49+
Hook.init("load");
50+
}
51+
52+
</script>
53+
</body>
54+
</html>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>websocket</title>
6+
</head>
7+
<body>
8+
9+
<script>
10+
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
11+
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
12+
(3)数据格式比较轻量,性能开销小,通信高效。
13+
(4)可以发送文本,也可以发送二进制数据。
14+
(5)没有同源限制,客户端可以与任意服务器通信。
15+
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
16+
17+
</script>
18+
</body>
19+
</html>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Document</title>
6+
</head>
7+
<body>
8+
9+
<script>
10+
var ws=new WebSocket("ws://127.0.0.1:8000");
11+
ws.onerror=function(e){
12+
console.log(e);
13+
};
14+
ws.onopen=function(e){
15+
console.log("握手成功");
16+
};
17+
</script>
18+
</body>
19+
</html>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* @Author: victorsun
3+
* @Date: 2017-08-24 21:19:43
4+
* @Last Modified by: victorsun
5+
* @Last Modified time: 2017-08-24 21:35:48
6+
*/
7+
//服务器程序
8+
var crypto = require('crypto');
9+
var WS = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
10+
require('net').createServer(function(o){
11+
var key;
12+
o.on('data',function(e){
13+
if(!key){
14+
//握手
15+
key = e.toString().match(/Sec-WebSocket-Key: (.+)/)[1];
16+
key = crypto.createHash('sha1').update(key + WS).digest('base64');
17+
o.write('HTTP/1.1 101 Switching Protocols\r\n');
18+
o.write('Upgrade: websocket\r\n');
19+
o.write('Connection: Upgrade\r\n');
20+
o.write('Sec-WebSocket-Accept: ' + key + '\r\n');
21+
o.write('\r\n');
22+
}else{
23+
// 输出之前解析帧
24+
console.log(decodeDataFrame(e));
25+
};
26+
});
27+
}).listen(8000);
28+
29+
// 【 协议 】
30+
// FIN 1bit 表示信息的最后一帧,flag,也就是标记符
31+
// RSV 1-3 1bit each 以后备用的 默认都为 0
32+
// Opcode 4bit 帧类型,稍后细说
33+
// Mask 1bit 掩码,是否加密数据,默认必须置为1 (这里很蛋疼)
34+
// Payload 7bit 数据的长度
35+
// Masking-key 1 or 4 bit 掩码
36+
// Payload data (x + y) bytes 数据
37+
// Extension data x bytes 扩展数据
38+
// Application data y bytes 程序数据
39+
40+
function decodeDataFrame(e){
41+
var i=0,j,s,frame={
42+
//解析前两个字节的基本数据
43+
FIN:e[i]>>7,Opcode:e[i++]&15,Mask:e[i]>>7,
44+
PayloadLength:e[i++]&0x7F
45+
};
46+
//处理特殊长度126和127
47+
if(frame.PayloadLength==126)
48+
frame.length=(e[i++]<<8)+e[i++];
49+
if(frame.PayloadLength==127)
50+
i+=4, //长度一般用四字节的整型,前四个字节通常为长整形留空的
51+
frame.length=(e[i++]<<24)+(e[i++]<<16)+(e[i++]<<8)+e[i++];
52+
//判断是否使用掩码
53+
if(frame.Mask){
54+
//获取掩码实体
55+
frame.MaskingKey=[e[i++],e[i++],e[i++],e[i++]];
56+
//对数据和掩码做异或运算
57+
for(j=0,s=[];j<frame.PayloadLength;j++)
58+
s.push(e[i+j]^frame.MaskingKey[j%4]);
59+
}else s=e.slice(i,frame.PayloadLength); //否则直接使用数据
60+
//数组转换成缓冲区来使用
61+
s=new Buffer(s);
62+
//如果有必要则把缓冲区转换成字符串来使用
63+
if(frame.Opcode==1)s=s.toString();
64+
//设置上数据部分
65+
frame.PayloadData=s;
66+
//返回数据帧
67+
return frame;
68+
}
69+
70+
//NodeJS
71+
function encodeDataFrame(e){
72+
var s=[],o=new Buffer(e.PayloadData),l=o.length;
73+
//输入第一个字节
74+
s.push((e.FIN<<7)+e.Opcode);
75+
//输入第二个字节,判断它的长度并放入相应的后续长度消息
76+
//永远不使用掩码
77+
if(l<126)s.push(l);
78+
else if(l<0x10000)s.push(126,(l&0xFF00)>>2,l&0xFF);
79+
else s.push(
80+
127, 0,0,0,0, //8字节数据,前4字节一般没用留空
81+
(l&0xFF000000)>>6,(l&0xFF0000)>>4,(l&0xFF00)>>2,l&0xFF
82+
);
83+
//返回头部分和数据部分的合并缓冲区
84+
return Buffer.concat([new Buffer(s),o]);
85+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
class WS {
3+
var $master;
4+
var $sockets = array();
5+
var $debug = false;
6+
var $handshake = false;
7+
8+
function __construct($address, $port){
9+
$this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
10+
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
11+
socket_bind($this->master, $address, $port) or die("socket_bind() failed");
12+
socket_listen($this->master,20) or die("socket_listen() failed");
13+
14+
$this->sockets[] = $this->master;
15+
$this->say("Server Started : ".date('Y-m-d H:i:s'));
16+
$this->say("Listening on : ".$address." port ".$port);
17+
$this->say("Master socket : ".$this->master."\n");
18+
19+
while(true){
20+
$socketArr = $this->sockets;
21+
$write = NULL;
22+
$except = NULL;
23+
socket_select($socketArr, $write, $except, NULL); //自动选择来消息的socket 如果是握手 自动选择主机
24+
foreach ($socketArr as $socket){
25+
if ($socket == $this->master){ //主机
26+
$client = socket_accept($this->master);
27+
if ($client < 0){
28+
$this->log("socket_accept() failed");
29+
continue;
30+
} else{
31+
$this->connect($client);
32+
}
33+
} else {
34+
$this->log("^^^^");
35+
$bytes = @socket_recv($socket,$buffer,2048,0);
36+
$this->log("^^^^");
37+
if ($bytes == 0){
38+
$this->disConnect($socket);
39+
}
40+
else{
41+
if (!$this->handshake){
42+
$this->doHandShake($socket, $buffer);
43+
}
44+
else{
45+
$buffer = $this->decode($buffer);
46+
$this->send($socket, $buffer);
47+
}
48+
}
49+
}
50+
}
51+
}
52+
}
53+
54+
function send($client, $msg){
55+
$this->log("> " . $msg);
56+
$msg = $this->frame($msg);
57+
socket_write($client, $msg, strlen($msg));
58+
$this->log("! " . strlen($msg));
59+
}
60+
function connect($socket){
61+
array_push($this->sockets, $socket);
62+
$this->say("\n" . $socket . " CONNECTED!");
63+
$this->say(date("Y-n-d H:i:s"));
64+
}
65+
function disConnect($socket){
66+
$index = array_search($socket, $this->sockets);
67+
socket_close($socket);
68+
$this->say($socket . " DISCONNECTED!");
69+
if ($index >= 0){
70+
array_splice($this->sockets, $index, 1);
71+
}
72+
}
73+
function doHandShake($socket, $buffer){
74+
$this->log("\nRequesting handshake...");
75+
$this->log($buffer);
76+
list($resource, $host, $origin, $key) = $this->getHeaders($buffer);
77+
$this->log("Handshaking...");
78+
$upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .
79+
"Upgrade: websocket\r\n" .
80+
"Connection: Upgrade\r\n" .
81+
"Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n\r\n"; //必须以两个回车结尾
82+
$this->log($upgrade);
83+
$sent = socket_write($socket, $upgrade, strlen($upgrade));
84+
$this->handshake=true;
85+
$this->log("Done handshaking...");
86+
return true;
87+
}
88+
89+
function getHeaders($req){
90+
$r = $h = $o = $key = null;
91+
if (preg_match("/GET (.*) HTTP/" ,$req,$match)) { $r = $match[1]; }
92+
if (preg_match("/Host: (.*)\r\n/" ,$req,$match)) { $h = $match[1]; }
93+
if (preg_match("/Origin: (.*)\r\n/" ,$req,$match)) { $o = $match[1]; }
94+
if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$req,$match)) { $key = $match[1]; }
95+
return array($r, $h, $o, $key);
96+
}
97+
98+
function calcKey($key){
99+
//基于websocket version 13
100+
$accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
101+
return $accept;
102+
}
103+
104+
function decode($buffer) {
105+
$len = $masks = $data = $decoded = null;
106+
$len = ord($buffer[1]) & 127;
107+
108+
if ($len === 126) {
109+
$masks = substr($buffer, 4, 4);
110+
$data = substr($buffer, 8);
111+
}
112+
else if ($len === 127) {
113+
$masks = substr($buffer, 10, 4);
114+
$data = substr($buffer, 14);
115+
}
116+
else {
117+
$masks = substr($buffer, 2, 4);
118+
$data = substr($buffer, 6);
119+
}
120+
for ($index = 0; $index < strlen($data); $index++) {
121+
$decoded .= $data[$index] ^ $masks[$index % 4];
122+
}
123+
return $decoded;
124+
}
125+
126+
function frame($s){
127+
$a = str_split($s, 125);
128+
if (count($a) == 1){
129+
return "\x81" . chr(strlen($a[0])) . $a[0];
130+
}
131+
$ns = "";
132+
foreach ($a as $o){
133+
$ns .= "\x81" . chr(strlen($o)) . $o;
134+
}
135+
return $ns;
136+
}
137+
138+
139+
function say($msg = ""){
140+
echo $msg . "\n";
141+
}
142+
function log($msg = ""){
143+
if ($this->debug){
144+
echo $msg . "\n";
145+
}
146+
}
147+
}
148+
149+
150+
new WS('localhost', 4000);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script type="text/javascript">
2+
var ws = new WebSocket("ws://localhost:4000");
3+
ws.onopen = function(){
4+
console.log("握手成功");
5+
}
6+
ws.onmessage = function(e){
7+
console.log("message:" + e.data);
8+
}
9+
ws.onerror = function(){
10+
console.log("error");
11+
}
12+
</script>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#websocket
2+
服务器运行
3+
```shell
4+
php websocket.php
5+
```
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!doctype html>
2+
<head>
3+
<meta charset="utf-8">
4+
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
5+
<title>HTML5 websocket 网页聊天室</title>
6+
<link rel="stylesheet" href="./css/chatroom.css">
7+
</head>
8+
9+
<body>
10+
<div id="ltian">
11+
<div id="us" class="jb"></div>
12+
<div id="ct"></div>
13+
<a href="javascript:;" class="qp" onClick="this.parentNode.children[1].innerHTML=''">清屏</a>
14+
</div>
15+
<div class="rin">
16+
<button id="sd">发送</button>
17+
<span><img src="./sk/t.png" title="表情" id="imgbq"><img src="./sk/e.png" title="上传图片"><form><input type="file" title="上传图片" id="upimg"></form></span>
18+
<p><input id="nrong"></p>
19+
</div>
20+
<div id="ems"><p></p><p class="tc"></p></div>
21+
22+
<script src="./js/websocket.js" type="text/javascript"></script>
23+
<script src="./js/chatroom.js"></script>
24+
</body>
25+
</html>

0 commit comments

Comments
 (0)