国内知名网站建设排名,app制作教程培训,企业实缴公示在什么网站做,临平网站建设摘要
在这一篇文章中#xff0c;写了如何在node端和web端#xff0c;实现一个WebSocket通信。 WebSocket在node端和客户端的使用
而在node端里面#xff0c;我们使用了ws模块来创建WebSocket和WebSocketServer#xff0c;那ws模块是如何做到可以和客户端进行双向通信的呢…摘要
在这一篇文章中写了如何在node端和web端实现一个WebSocket通信。 WebSocket在node端和客户端的使用
而在node端里面我们使用了ws模块来创建WebSocket和WebSocketServer那ws模块是如何做到可以和客户端进行双向通信的呢
426状态码
在HTTP中426表示“Upgrade Required”即客户端需要通过HTTP协议的升级版进行访问。这个状态码主要用在WebSockets协议中表示客户端需要使用WebSockets协议来连接服务器。
什么意思呢例如我们创建一个HTTP服务如果这么写
const http require(http)const server http.createServer((req, res) {const body http.STATUS_CODES[426];res.writeHead(426, {Content-Type: text/align,Content-Length: body.length})res.end(body)
})server.listen(8080)就是告诉客户端如果你访问我这边的服务那么你就要进行升级服务。也就是使用WebSocket对我进行访问
那有一个问题如果客户端使用了WebSocket访问服务端要怎么进行响应呢
还直接在createServer里面的回调中处理吗
upgrade事件
在这里面如果客户端通过WebSocket进行访问服务端会触发服务端server的upgrade事件也就是说会进下面的回调函数里。
server.on(upgrade,(req, socket, head) {// 固定格式const key req.headers[sec-websocket-key];const digest createHash(sha1).update(key 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,).digest(base64);const headers [HTTP/1.1 101 Switching Protocols,Upgrade: websocket,Connection: Upgrade,Sec-WebSocket-Accept: ${digest}];socket.write(headers.concat(\r\n).join(\r\n));// 客户端发送的消息socket.on(data, (data) {console.log(data.toString());})// 服务端向客户端发送消息socket.write(你好)
})这个回调中通过socket来进行和客户端进行双向通信。
转码
但是只有上面的例子似乎每次拿到的数据都是乱码。这是因为WebSocket之间的通信的报文不能通过Buffer的toString直接转码。这里提供一下在网上找到的转码方法
server.on(upgrade, (req, socket, head) {const key req.headers[sec-websocket-key];const digest createHash(sha1).update(key 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,).digest(base64);const headers [HTTP/1.1 101 Switching Protocols,Upgrade: websocket,Connection: Upgrade,Sec-WebSocket-Accept: ${digest}];socket.write(headers.concat(\r\n).join(\r\n));socket.on(data,(data) {console.log(decodeSocketFrame(data).payloadBuf.toString())socket.write(encodeSocketFrame({fin:1,opcode:1,payloadBuf:Buffer.from(你好)}))})
})function decodeSocketFrame (bufData){let bufIndex 0const byte1 bufData.readUInt8(bufIndex).toString(2)const byte2 bufData.readUInt8(bufIndex).toString(2)console.log(byte1);console.log(byte2);const frame {fin:parseInt(byte1.substring(0,1),2),// RSV是保留字段暂时不计算opcode:parseInt(byte1.substring(4,8),2),mask:parseInt(byte2.substring(0,1),2),payloadLen:parseInt(byte2.substring(1,8),2),}// 如果frame.payloadLen为126或127说明这个长度不够了要使用扩展长度了// 如果frame.payloadLen为126则使用Extended payload length同时为16/8字节数// 如果frame.payloadLen为127则使用Extended payload length同时为64/8字节数// 注意payloadLen得长度单位是字节(bytes)而不是比特(bit)if(frame.payloadLen126) {frame.payloadLen bufData.readUIntBE(bufIndex,2);bufIndex2;} else if(frame.payloadLen127) {// 虽然是8字节但是前四字节目前留空因为int型是4字节不留空int会溢出bufIndex4;frame.payloadLen bufData.readUIntBE(bufIndex,4);bufIndex4;}if(frame.mask){const payloadBufList []// maskingKey为4字节数据frame.maskingKey[bufData[bufIndex],bufData[bufIndex],bufData[bufIndex],bufData[bufIndex]];for(let i0;iframe.payloadLen;i) {payloadBufList.push(bufData[bufIndexi]^frame.maskingKey[i%4]);}frame.payloadBuf Buffer.from(payloadBufList)} else {frame.payloadBuf bufData.slice(bufIndex,bufIndexframe.payloadLen)}return frame
}function encodeSocketFrame (frame){const frameBufList [];// 对fin位移七位则为10000000加opcode为10000001const header (frame.fin7)frame.opcode;frameBufList.push(header)const bufBits Buffer.byteLength(frame.payloadBuf);let payloadLen bufBits;let extBuf;if(bufBits126) {//65536是2**16即两字节数字极限if(bufBits65536) {extBuf Buffer.allocUnsafe(8);buf.writeUInt32BE(bufBits, 4);payloadLen 127;} else {extBuf Buffer.allocUnsafe(2);buf.writeUInt16BE(bufBits, 0);payloadLen 126;}}let payloadLenBinStr payloadLen.toString(2);while(payloadLenBinStr.length8){payloadLenBinStr0payloadLenBinStr;}frameBufList.push(parseInt(payloadLenBinStr,2));if(bufBits126) {frameBufList.push(extBuf);}frameBufList.push(...frame.payloadBuf)return Buffer.from(frameBufList)
}WebSocketServer的实现
有了上面的基础基本知道双向通信是怎么做到的了。就来看一下WebSocketServer的实现。 当我们使用的时候我们是以这种方式
const WebSocketServer require(ws)const wss new WebSocketServer(8080);
wss.on(connection, (ws) {})我们知道connection是httpServer的回调为什么在WebSocketServer中可以使用呢
export default class WebSocketServer {constructor(port) {this._server http.createServer((req, res) {const body http.STATUS_CODES[426];res.writeHead(426, {Content-Type: text/align,Content-Length: body.length})res.end(body)})this._server.listen(port);const connectionEmit this.emit.bind(this, connection);const closeEmit this.emit.bind(this, close);// 其他事件都是http能监听到的;const map {connection: connectionEmit,close: closeEmit}for(let emitName in map) {this._server.on(emitName, map[emitName])}}
}在WebSocketServer中如果客户端触发了http的事件时它便将其转发到WebSocket实例上面。 然后再处理自己的逻辑。 文章转载自: http://www.morning.tzzfy.cn.gov.cn.tzzfy.cn http://www.morning.wdpt.cn.gov.cn.wdpt.cn http://www.morning.tdhxp.cn.gov.cn.tdhxp.cn http://www.morning.mzcrs.cn.gov.cn.mzcrs.cn http://www.morning.flmxl.cn.gov.cn.flmxl.cn http://www.morning.gbnsq.cn.gov.cn.gbnsq.cn http://www.morning.kmprl.cn.gov.cn.kmprl.cn http://www.morning.hytqt.cn.gov.cn.hytqt.cn http://www.morning.nlzpj.cn.gov.cn.nlzpj.cn http://www.morning.xfjwm.cn.gov.cn.xfjwm.cn http://www.morning.phzrq.cn.gov.cn.phzrq.cn http://www.morning.bscsp.cn.gov.cn.bscsp.cn http://www.morning.jtfcd.cn.gov.cn.jtfcd.cn http://www.morning.nlbw.cn.gov.cn.nlbw.cn http://www.morning.wkmyt.cn.gov.cn.wkmyt.cn http://www.morning.rwlnk.cn.gov.cn.rwlnk.cn http://www.morning.rcjyc.cn.gov.cn.rcjyc.cn http://www.morning.jqbpn.cn.gov.cn.jqbpn.cn http://www.morning.nnhrp.cn.gov.cn.nnhrp.cn http://www.morning.fgtls.cn.gov.cn.fgtls.cn http://www.morning.rjrz.cn.gov.cn.rjrz.cn http://www.morning.nlgmr.cn.gov.cn.nlgmr.cn http://www.morning.mdjtk.cn.gov.cn.mdjtk.cn http://www.morning.kryxk.cn.gov.cn.kryxk.cn http://www.morning.lysrt.cn.gov.cn.lysrt.cn http://www.morning.qyhcg.cn.gov.cn.qyhcg.cn http://www.morning.bqwnp.cn.gov.cn.bqwnp.cn http://www.morning.kdgcx.cn.gov.cn.kdgcx.cn http://www.morning.dlhxj.cn.gov.cn.dlhxj.cn http://www.morning.cytr.cn.gov.cn.cytr.cn http://www.morning.bssjp.cn.gov.cn.bssjp.cn http://www.morning.sdktr.com.gov.cn.sdktr.com http://www.morning.httzf.cn.gov.cn.httzf.cn http://www.morning.jbctp.cn.gov.cn.jbctp.cn http://www.morning.zrpbf.cn.gov.cn.zrpbf.cn http://www.morning.ggtkk.cn.gov.cn.ggtkk.cn http://www.morning.rwcw.cn.gov.cn.rwcw.cn http://www.morning.krnzm.cn.gov.cn.krnzm.cn http://www.morning.bqppr.cn.gov.cn.bqppr.cn http://www.morning.wgxtz.cn.gov.cn.wgxtz.cn http://www.morning.fbylq.cn.gov.cn.fbylq.cn http://www.morning.lpyjq.cn.gov.cn.lpyjq.cn http://www.morning.nfbnl.cn.gov.cn.nfbnl.cn http://www.morning.fsfz.cn.gov.cn.fsfz.cn http://www.morning.xlwpz.cn.gov.cn.xlwpz.cn http://www.morning.rtbhz.cn.gov.cn.rtbhz.cn http://www.morning.sfcfy.cn.gov.cn.sfcfy.cn http://www.morning.wdxr.cn.gov.cn.wdxr.cn http://www.morning.wmfny.cn.gov.cn.wmfny.cn http://www.morning.rwnx.cn.gov.cn.rwnx.cn http://www.morning.whclz.cn.gov.cn.whclz.cn http://www.morning.ktrzt.cn.gov.cn.ktrzt.cn http://www.morning.xllrf.cn.gov.cn.xllrf.cn http://www.morning.zmbzl.cn.gov.cn.zmbzl.cn http://www.morning.jnzfs.cn.gov.cn.jnzfs.cn http://www.morning.nknt.cn.gov.cn.nknt.cn http://www.morning.fengnue.com.gov.cn.fengnue.com http://www.morning.jkwwm.cn.gov.cn.jkwwm.cn http://www.morning.mbfj.cn.gov.cn.mbfj.cn http://www.morning.lmcrc.cn.gov.cn.lmcrc.cn http://www.morning.zwmjq.cn.gov.cn.zwmjq.cn http://www.morning.hnpkr.cn.gov.cn.hnpkr.cn http://www.morning.fmrrr.cn.gov.cn.fmrrr.cn http://www.morning.taipinghl.cn.gov.cn.taipinghl.cn http://www.morning.kcsx.cn.gov.cn.kcsx.cn http://www.morning.qstkk.cn.gov.cn.qstkk.cn http://www.morning.tdnbw.cn.gov.cn.tdnbw.cn http://www.morning.coatingonline.com.cn.gov.cn.coatingonline.com.cn http://www.morning.qzmnr.cn.gov.cn.qzmnr.cn http://www.morning.dfndz.cn.gov.cn.dfndz.cn http://www.morning.thrgp.cn.gov.cn.thrgp.cn http://www.morning.qkwxp.cn.gov.cn.qkwxp.cn http://www.morning.qphgp.cn.gov.cn.qphgp.cn http://www.morning.zmnyj.cn.gov.cn.zmnyj.cn http://www.morning.gmmxh.cn.gov.cn.gmmxh.cn http://www.morning.tssmk.cn.gov.cn.tssmk.cn http://www.morning.tdgwg.cn.gov.cn.tdgwg.cn http://www.morning.ktbjk.cn.gov.cn.ktbjk.cn http://www.morning.jcrfm.cn.gov.cn.jcrfm.cn http://www.morning.yrnll.cn.gov.cn.yrnll.cn