前面的例子都是用了1这个操作码(Opcode)来传输文本的。没错,1这个操作码就是传输文本(UTF-8)的。还用到了在分片过程中把操作码设置为0,0也只是分片时用的。操作码是4位的,取值当然不止这两个,除了指定传输数据类型外还有其它用途的操作码。
规范文档中也提供了一个表格
|Opcode | Meaning | Reference | -+--------+-------------------------------------+-----------| | 0 | Continuation Frame | RFC 6455 | -+--------+-------------------------------------+-----------| | 1 | Text Frame | RFC 6455 | -+--------+-------------------------------------+-----------| | 2 | Binary Frame | RFC 6455 | -+--------+-------------------------------------+-----------| | 8 | Connection Close Frame | RFC 6455 | -+--------+-------------------------------------+-----------| | 9 | Ping Frame | RFC 6455 | -+--------+-------------------------------------+-----------| | 10 | Pong Frame | RFC 6455 | -+--------+-------------------------------------+-----------|
目前就这么多个操作码被定义,其它都是预留的。0和1这两个之前的例子用过的就不说了。2这个操作码是告诉服务器不要把数据转换成字符串,直接当做二进制数据来用。这会在传输图片之类的操作中用到,至于传输图片的例子以后再给吧。这篇主要是介绍后三个操作码。
8这个操作码是服务器向客户端请求结束当前连接用的,不要以为这很简单,WebSocket的建立连接需要握手协议,那么关闭也需要双方的协商,还有关闭的代码什么的,总之很麻烦,下回再介绍。
9和10这两个状态码就简单些了,它们是成对的。服务器向客户端发送一个Ping帧时客户端会自动返回一个Pong帧,并且数据部分与发送的完全相同。如果不同或收不到,则说明网络有问题。下面是例子
(encodeDataFrame与decodeDataFrame函数见生成数据帧和解析数据帧)
//客户端程序 var ws=new WebSocket("ws://127.0.0.1:8000");
//服务器程序 var crypto=require('crypto'); var WS='258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; require('net').createServer(function(o){ var key; o.on('data',function(e){ if(!key){ //握手 key=e.toString().match(/Sec-WebSocket-Key: (.+)/)[1]; key=crypto.createHash('sha1').update(key+WS).digest('base64'); o.write('HTTP/1.1 101 Switching Protocols\r\n'); o.write('Upgrade: websocket\r\n'); o.write('Connection: Upgrade\r\n'); o.write('Sec-WebSocket-Accept: '+key+'\r\n'); o.write('\r\n'); //握手成功后给客户端发送个Ping包 o.write(encodeDataFrame({FIN:1,Opcode:9,PayloadData:"数据"})); }else{ //解析客户端传过来的数据帧并输出 var data=decodeDataFrame(e); data.PayloadData=data.PayloadData.toString(); console.log(e); }; }); }).listen(8000);
Chrome调试工具截图:
NodeJS控制台截图: