|
4 | 4 | * @Last Modified by: victorsun
|
5 | 5 | * @Last Modified time: 2017-08-24 21:35:48
|
6 | 6 | */
|
| 7 | + |
| 8 | +// 【 协议 】 |
| 9 | +// 0 1 2 3 |
| 10 | +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
| 11 | +// +-+-+-+-+-------+-+-------------+-------------------------------+ |
| 12 | +// |F|R|R|R| opcode|M| Payload len | Extended payload length | |
| 13 | +// |I|S|S|S| (4) |A| (7) | (16/64) | |
| 14 | +// |N|V|V|V| |S| | (if payload len==126/127) | |
| 15 | +// | |1|2|3| |K| | | |
| 16 | +// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + |
| 17 | +// | Extended payload length continued, if payload len == 127 | |
| 18 | +// + - - - - - - - - - - - - - - - +-------------------------------+ |
| 19 | +// | |Masking-key, if MASK set to 1 | |
| 20 | +// +-------------------------------+-------------------------------+ |
| 21 | +// | Masking-key (continued) | Payload Data | |
| 22 | +// +-------------------------------- - - - - - - - - - - - - - - - + |
| 23 | +// : Payload Data continued ... : |
| 24 | +// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |
| 25 | +// | Payload Data continued ... | |
| 26 | +// +---------------------------------------------------------------+ |
| 27 | +// |
| 28 | +// FIN 1bit 表示信息的最后一帧,flag,也就是标记符 |
| 29 | +// RSV 1-3 1bit each 以后备用的 默认都为 0 |
| 30 | +// Opcode 4bit 帧类型,见下表 |
| 31 | +// Mask 1bit 掩码,是否加密数据,默认必须置为1 |
| 32 | +// Payload 7bit 数据的长度 |
| 33 | +// Masking-key 1 or 4 bit 掩码 |
| 34 | +// Payload data (x + y) bytes 数据 |
| 35 | +// Extension data x bytes 扩展数据 |
| 36 | +// Application data y bytes 程序数据 |
| 37 | + |
| 38 | +// -+--------+-------------------------------------+-----------| |
| 39 | +// |Opcode | Meaning | Reference | |
| 40 | +// -+--------+-------------------------------------+-----------| |
| 41 | +// | 0 | Continuation Frame | RFC 6455 | |
| 42 | +// -+--------+-------------------------------------+-----------| |
| 43 | +// | 1 | Text Frame | RFC 6455 | |
| 44 | +// -+--------+-------------------------------------+-----------| |
| 45 | +// | 2 | Binary Frame | RFC 6455 | |
| 46 | +// -+--------+-------------------------------------+-----------| |
| 47 | +// | 8 | Connection Close Frame | RFC 6455 | |
| 48 | +// -+--------+-------------------------------------+-----------| |
| 49 | +// | 9 | Ping Frame | RFC 6455 | |
| 50 | +// -+--------+-------------------------------------+-----------| |
| 51 | +// | 10 | Pong Frame | RFC 6455 | |
| 52 | +// -+--------+-------------------------------------+-----------| |
| 53 | +// |
| 54 | +// 【 握手连接 】 |
| 55 | +// +--------+ 1.发送Sec-WebSocket-Key +---------+ |
| 56 | +// | | --------------------------------> | | |
| 57 | +// | | 2.加密返回Sec-WebSocket-Accept | | |
| 58 | +// | client | <-------------------------------- | server | |
| 59 | +// | | 3.本地校验 | | |
| 60 | +// | | --------------------------------> | | |
| 61 | +// +--------+ +--------+ |
| 62 | +// 【 1. client => server 】 |
| 63 | +/* |
| 64 | +GET /chat HTTP/1.1 |
| 65 | +Host: server.example.com |
| 66 | +Upgrade: websocket |
| 67 | +Connection: Upgrade |
| 68 | +Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== |
| 69 | +Origin: http://example.com |
| 70 | +Sec-WebSocket-Protocol: chat, superchat |
| 71 | +Sec-WebSocket-Version: 13 |
| 72 | + */ |
| 73 | +// 客户端发了一串 Base64 加密的密钥 Sec-WebSocket-Key |
| 74 | +// 【 2. server => client 】 |
| 75 | +/* |
| 76 | +HTTP/1.1 101 Switching Protocols |
| 77 | +Upgrade: websocket |
| 78 | +Connection: Upgrade |
| 79 | +Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= |
| 80 | +Sec-WebSocket-Protocol: chat |
| 81 | + */ |
| 82 | +// Server 返回了 Sec-WebSocket-Accept 这个应答,这个应答内容是通过一定的方式生成的。生成算法是: |
| 83 | +// mask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // 这是算法中要用到的固定字符串 |
| 84 | +// 【 accept = base64( sha1( key + mask ) ); 】 |
| 85 | +// 分解动作: |
| 86 | +// 1. t = "GhlIHNhbXBsZSBub25jZQ==" + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" |
| 87 | +// -> "GhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" |
| 88 | +// 2. s = sha1(t) |
| 89 | +// -> 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 |
| 90 | +// 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea |
| 91 | +// 3. base64(s) |
| 92 | +// -> "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" |
| 93 | +// 上面 Server 端返回的 HTTP 状态码是 101,如果不是 101 ,就说明握手一开始就失败了 |
| 94 | + |
| 95 | + |
7 | 96 | //服务器程序
|
8 | 97 | var crypto = require('crypto');
|
9 |
| -var WS = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; |
| 98 | +var WS = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; // 算法中要用到的固定字符串 |
10 | 99 | require('net').createServer(function(o){
|
11 | 100 | var key;
|
12 | 101 | o.on('data',function(e){
|
| 102 | + //握手 |
13 | 103 | if(!key){
|
14 |
| - //握手 |
15 | 104 | key = e.toString().match(/Sec-WebSocket-Key: (.+)/)[1];
|
| 105 | + // 算法:accept = base64( sha1( key + mask ) ); |
16 | 106 | key = crypto.createHash('sha1').update(key + WS).digest('base64');
|
17 | 107 | o.write('HTTP/1.1 101 Switching Protocols\r\n');
|
18 | 108 | o.write('Upgrade: websocket\r\n');
|
19 | 109 | o.write('Connection: Upgrade\r\n');
|
20 | 110 | o.write('Sec-WebSocket-Accept: ' + key + '\r\n');
|
21 | 111 | o.write('\r\n');
|
22 |
| - }else{ |
| 112 | + console.log("建立连接"); |
| 113 | + } |
| 114 | + // 接收数据 |
| 115 | + else{ |
23 | 116 | // 输出之前解析帧
|
24 |
| - console.log(decodeDataFrame(e)); |
| 117 | + var frame= decodeDataFrame(e); |
| 118 | + console.log(frame); |
| 119 | + // 关闭之前 |
| 120 | + if(frame.Opcode==8){ |
| 121 | + console.log("断开连接"); |
| 122 | + o.end(); // 断开连接 |
| 123 | + }else{ |
| 124 | + // 主动断开连接 |
| 125 | + // o.write(encodeDataFrame({ |
| 126 | + // FIN:1, |
| 127 | + // Opcode:8, |
| 128 | + // PayloadData:"断开" |
| 129 | + // })); |
| 130 | + } |
25 | 131 | };
|
26 | 132 | });
|
27 | 133 | }).listen(8000);
|
28 | 134 |
|
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 | 135 |
|
| 136 | +// decodeDataFrame 解析客户端传来的二进制数据,得到的数据格式是: |
| 137 | +// { |
| 138 | +// FIN: 1, |
| 139 | +// Opcode: 1, |
| 140 | +// Mask: 1, |
| 141 | +// PayloadLength: 4, |
| 142 | +// MaskingKey: [ 159, 18, 207, 93 ], |
| 143 | +// PayLoadData: '握手成功' |
| 144 | +// } |
40 | 145 | function decodeDataFrame(e){
|
41 | 146 | var i=0,j,s,frame={
|
42 | 147 | //解析前两个字节的基本数据
|
@@ -67,7 +172,6 @@ function decodeDataFrame(e){
|
67 | 172 | return frame;
|
68 | 173 | }
|
69 | 174 |
|
70 |
| -//NodeJS |
71 | 175 | function encodeDataFrame(e){
|
72 | 176 | var s=[],o=new Buffer(e.PayloadData),l=o.length;
|
73 | 177 | //输入第一个字节
|
|
0 commit comments