nodejs之websocket
Posted 依然是等待
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nodejs之websocket相关的知识,希望对你有一定的参考价值。
1 var events = require("events"); 2 var http = require("http"); 3 var crypto = require("crypto"); 4 var util = require("util"); 5 //opcodes for WebSocket frames 6 //http://tools.ietf.org/html/rfc6455#section-5.2 7 var opcodes = 8 { 9 TEXT:1, 10 BINARY:2, 11 CLOSE:8, 12 PING:9, 13 PONG:10 14 }; 15 var WebSocketConnection = function(req,socket,upgradeHead) 16 { 17 var self = this; 18 var key = hashWebSocketKey(req.headers["sec-websocket-key"]); 19 //handshake response 20 //http://tools.ietf.org/html/rfc6455#section-4.2.2 21 socket.write(‘HTTP/1.1 101 Web Socket Protocol Handshake\r\n‘+ 22 ‘Upgrade:WebSocket\r\n‘+ 23 ‘Connection:Upgrade\r\n‘+ 24 ‘sec-websocket-accept: ‘+key+‘\r\n\r\n‘); 25 26 socket.on("data",function(buf) 27 { 28 self.buffer = Buffer.concat([self.buffer,buff]); 29 while(self._processBuffer()) 30 { 31 //process buffer while it contains complete frames 32 } 33 }); 34 35 socket.on("close",function(hac_error) 36 { 37 if(!self.closed) 38 { 39 self.emit("close",1006); 40 self.closed = true; 41 } 42 }); 43 // initialize connection state 44 this.socket = socket; 45 this.buffer = new Buffer(0); 46 this.colsed = false; 47 48 } 49 50 util.inherits(WebSocketConnection,events.EventEmitter); 51 // Send a text or binary message on the WebSocket connection 52 53 WebSocketConnection.prototype.send = function(obj) 54 { 55 var opcode; 56 var payload; 57 if(Buffer.isBuffer(obj)) 58 { 59 opcode = opcodes.BINARY; 60 payload = obj; 61 } 62 else 63 { 64 throw new Error("Cannot send object. Must be string or Buffer"); 65 } 66 this._doSend(opcode,payload); 67 } 68 //Close the WebSocket connection 69 WebSocketConnection.prototype.close = function(code,reason) 70 { 71 var opcode = opcodes.CLOSE; 72 var buffer; 73 //Encode close and reason 74 if(code) 75 { 76 buffer = new Buffer(Buffer.byteLength(reason)+2); 77 buffer.writeUInt16BE(code,0); 78 buffer.write(reason,2); 79 } 80 else 81 { 82 buffer = new Buffer(0); 83 } 84 this._doSend(opcode,buffer); 85 this.close = true; 86 87 } 88 //process incoming bytes 89 WebSocketConnection.prototype._processBuffer = function() 90 { 91 var buf = this.buffer; 92 if(buf.length < 2) 93 { 94 //insufficient data read 95 return; 96 } 97 98 var idx = 2; 99 var b1 = buf.readUInt8(0); 100 var fin = b1 & 0x80; 101 var opcode = b1 & 0x0f; 102 var b2 = buf.readUInt8(1); 103 var mask = b2 & 0x80; 104 var length = b2 & 0x7f; 105 106 if(length > 125) 107 { 108 if(buf.length < 8) 109 { 110 //insufficient data read 111 return; 112 } 113 114 if(length == 126) 115 { 116 length = buf.readUInt16BE(2); 117 idx += 2; 118 } 119 else if(length == 127) 120 { 121 //discard high 4 bits because this server cannot handle huge lengths 122 var highBits = buf.readUInt32BE(2); 123 if(highBits != 0) 124 { 125 this.close(1009,""); 126 } 127 length = buf.readUInt32BE(6); 128 idx += 8; 129 } 130 } 131 132 if(buf.length < idx + 4 + length) 133 { 134 //insufficient data read 135 return; 136 } 137 138 maskBytes = buf.slice(idx,idx+4); 139 idx += 4; 140 var payload = buf.slice(idx,idx+length); 141 payload = unmask(maskBytes,payload); 142 this._handleFreme(opcode,payload); 143 144 this.buffer = buf.slice(idx+length); 145 return true; 146 } 147 148 WebSocketConnection.prototype._handleFrame = function(opcode,buffer) 149 { 150 var payload; 151 switch(opcode) 152 { 153 case opcodes.TEXT: 154 payload = buffer.toString("utf8"); 155 this.emit("data",opcode,payload); 156 break; 157 case opcode.BINARY: 158 payload = buffer; 159 this.emit("data",opcode,payload); 160 break; 161 case opcode.PING: 162 //Respond to pings with pongs 163 this._doSend(opcode.PONG,buffer); 164 break; 165 case opcode.PONG: 166 //Ignore pongs; 167 break; 168 case opcode.CLOSE: 169 //Parse close and reason 170 var code,reason; 171 if(buffer.length >= 2) 172 { 173 code = buffer.readUInt16BE(0); 174 reason = buffer.toString("utf8",2); 175 } 176 this.close(code,reason); 177 this.emit("close",code,reason); 178 break; 179 default: 180 this.close(1002,"unknown opcode"); 181 182 } 183 } 184 //Format and send a WebSocket message 185 WebSocketConnection.prototype._doSend = function(opcode,payload) 186 { 187 this.socket.write(encodeMessage(opcode,payload)); 188 } 189 190 var KEY_SUFFIX = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 191 var hashWebSocketKey = function(key) 192 { 193 var sha1 = crypto.createHash("sha1"); 194 sha1.update(key+KEY_SUFFIX,"ascii"); 195 return sha1.digest("base64"); 196 } 197 198 var unmask = function(maskBytes,data) 199 { 200 var payload = new Buffer(data.length); 201 for(var i=0;i<data.length;i++) 202 { 203 payload[] = maskBytes[i%4] ^ data[i]; 204 } 205 206 return payload; 207 208 } 209 210 var encodeMessage = function(opcode,payload) 211 { 212 var buf; 213 //first byte:fin and opcode 214 var b1 = 0x80 | opcode; 215 //always send message as one frame(fin) 216 //Second byte:mask and length part 1 217 //Followed by 0,2, or 8 additional bytes of continued length 218 var b2 = 0;//server does not mask frames 219 var length = payload.length; 220 if(length < 126) 221 { 222 buf = new Buffer(payload.length + 2 + 0); 223 //zero extra bytes 224 b2 |= length; 225 buf.writeUInt8BE(b1,0); 226 buf.writeUInt8BE(b1,1); 227 payload.copy(buf.2); 228 } 229 else if(length<(1<<16)) 230 { 231 buf = new Buffer(payload.length + 2 + 2); 232 //two bytes extra 233 b2 |= 126; 234 buf.writeUInt8BE(b1,0); 235 buf.writeUInt8BE(b1,1); 236 //add two tyte length 237 buf.writeUInt16BE(length,2); 238 payload.copy(buf,4); 239 } 240 else 241 { 242 buf = new Buffer(payload.length + 2 + 8); 243 //eight bytes extra 244 b2 |= 127; 245 buf.writeUInt8(b1,0); 246 buf.writeUInt8(b1,1); 247 //add eigth byte length 248 //note:this implementation cannt handle lengths greater than 2^32 249 //the 32 bit length is prefixed with 0X0000 250 buf.writeUInt32BE(0,2); 251 buf.writeUInt32BE(length,6); 252 payload.copy(buf,10); 253 } 254 255 return; 256 } 257 258 exports.listen = function(port,host,connectionHandler) 259 { 260 var srv = http.createServer(function(req,res){}); 261 262 srv.on(‘upgrade‘,function(req,socket,upgradeHead) 263 { 264 var ws = new WebSocketConnection(req,socket,upgradeHead); 265 connectionHandler(ws); 266 }); 267 srv.listen(port,host); 268 }; 269 270 //echo.js 271 var websocket = require("./websocket-example"); 272 websocket.listen(9999,"localhost",function(conn) 273 { 274 console.log("connection opened"); 275 conn.on("data",function(opcode,data) 276 { 277 console.log("message: ",data); 278 conn.send(data); 279 }); 280 281 conn.on("close",function(code,reason) 282 { 283 console.log("connection closed: ",code,reason); 284 285 }); 286 287 });
以上是关于nodejs之websocket的主要内容,如果未能解决你的问题,请参考以下文章