环境及功能设定
Client:生成CoAP消息,用WebSocket发送至ProxyProxy: 提取CoAP消息,转发至Server,并将响应回发至ClientServer:接受CoAP消息,解析、再重新封装后,回复
具体使用的模块:
Client:用`coap-packet`模块的`generate`方法生成CoAP消息;用`nodejs-websocket`模块的`sendBinary()`方法发消息;用`nodejs-websocket`模块的`on('binary', callback)`事件监听接收响应。Proxy:用`nodejs-websocket`模块的`on('binary', callback)`事件监听接收WebSocket消息;用`UDP dgram`模块(Node.js自带)的`send()`方法,把作为payload的CoAP消息转发给Server;用`UDP dgram`模块的`on('message', callback)`事件监听接收响应;用`nodejs-websocket`模块的`sendBinary()`方法,把响应回发至Client。Server:用`UDP dgram`模块的`on('message', callback)`事件监听接收响应;用`UDP dgram`模块(Node.js自带)的`send()`方法,把作为payload的CoAP消息转发给Server。
Q. proxy怎么正确接受client通过sendBinary()发送来的数据?
`conn.on('binary', ballback)`怎么用?test.js内容有无借鉴?
A. 借鉴websocket模块中test.js的getServer()
函数
function getServer(ontext, onbinary) { testConn.removeAllListeners(); if (ontext) testConn.on('text', ontext); if (onbinary) testConn.on('binary', onbinary); }
和调用了它的测试片段。 ``` it('should send binary data', function(done){ var client = getClient(), buffer = getBuffer(17); Client.sendBinary(buffer); getServer(null, function (inStream) { inStream.on('readable', function () { compareBuffers(inStream.read(), buffer) }); inStream.on('end', done); });})```
Node.js用Buffer类处理二进制数据
JS善于处理字符串,但不善于处理二进制数据。JS没有字节类型,也没有结构化类型、字节数组类型,只有数值类型和字符串类型。
Node.js需要处理像TCP流或文件流时,必须要处理二进制数据。Node.js定义了一个Buffer类来解决这个问题。缓冲区的长度以字节为计量单位,并且可以随机地设置和获取缓冲区中的数据。类:BUFFER
- 构造方法 1.new Buffer(size):分配一个新的buffer大小是size的8位字节 2.new Buffer(array):分配一个新的buffer使用一个8位字节array数组 3.new Buffer(str, [encoding]):encoding String类型-使用什么编码方式,参数可选
- 类方法 1.Buffer.isEncoding(encoding):如果给定的编码encoding是有效的,返回 true,否则返回false 2.Buffer.isBuffer(obj):测试这个obj是否是一个Buffer. 返回Boolean 3.Buffer.concat(list, [totalLength]):list {Array}数组类型,Buffer数组,用于被连接。totalLength {Number}类型 上述Buffer数组的所有Buffer的总大小
- 写入缓冲区 var buffer = new Buffer(8);//创建一个分配了8个字节内存的缓冲区 console.log(buffer.write('a','utf8'));//输出1 这会将字符"a"写入缓冲区,node返回经过编码以后写入缓冲区的字节数量,这里的字母a的utf-8编码占用1个字节。
- 复制缓冲区 Node.js提供了一个将Buffer对象整体内容复制到另一个Buffer对象中的方法。我们只能在已经存在的Buffer对象之间复制,所以必须创建它们。 buffer.copy(bufferToCopyTo) 其中,bufferToCopyTo是要复制的目标Buffer对象。如下示例:
var buffer1 = new Buffer(8);buffer1.write('nice to meet u','utf8');var buffer2 = new Buffer(8);buffer1.copy(buffer2);console.log(buffer2.toString());//nice to meet u
Node.js的流模块
Node.js中很多对象都实现了流,一个例子是TCP套接字,可以在其上进行读写操作;另一个例子是文件,可以对其进行顺序地追加和读取。按流的可操作性有可读流和可写流之分。
在类UNIX系统Stream是通过"|"实现对流的操作,node.js中对流的操作是通过.pipe()方法。
可读流操作
在创建或者获取一个可读流(如:读取一个文件后、收到一个client端HTTPt responses后)之后,可以对其进行一些控制和操作。例如:可以通过暂停和恢复来控制数据的流动、可以在收到数据时得到data通知、可以在流终止时关闭传输。
- 'data' 事件等待数据传输
var readable = getReadableStreamSomehow(); //getReadableStreamSomehow()是一个获得可读流的方法readable.on('data', function(chunk) { //本次得到的数据块chunk console.log('got %d bytes of data', chunk.length);});
- 流的暂停与恢复 可读流就像一个阀门,可以通暂停来数据流动,可以通resume()方法恢复传输。示例如下:
var readable = getReadableStreamSomehow();readable.on('data', function(chunk) { console.log('got %d bytes of data', chunk.length); readable.pause(); //暂停 console.log('接下来的1秒数据传输将会暂停'); setTimeout(function() { console.log('数据传输恢复'); readable.resume(); //恢复 }, 1000);});
- 流传输结束
流传输结果后会收到"end"事件,通过监听"end"事件可以进行一些流传输结束后的处理。示例如下:
var readable = getReadableStreamSomehow(); //getReadableStreamSomehow()是一个获得可读流的方法readable.on('data', function(chunk) { //本次得到的数据块chunk console.log('got %d bytes of data', chunk.length);});readable.on('end', function() { console.log('数据传输结束');});
可写流操作
- 将数据写入可写流 向流写入数据时,可以传送缓冲区Buffer数据或字符串。写入时,可设置第二个可选参数设置数据编码。示例如下:
var file = fs.createWriteStream('example.txt');file.write('itbilu.com');//写入数据时,可以设置编码格式file.write('aXRiaWx1LmNvbQ==', 'base64');//写缓冲区Buffer数据var buf = new Buffer('itbilu.com');file.write(buf);
- 可写流的完成与清空 向流写入数据时,你会知道缓冲区数据是否被立即刷新,如果没有被刷新数据会被存储到内存中。在流成功刷新挂起的缓冲区时,stream会发送“drain”事件。写入完成后会发送“finish”事件。示例如下:
var writer = fs.createWriteStream('example.txt');//假设这是一个可能会被挂起的缓冲区var buf = new Buffer('itbilu.com');writer.write(buf);//刷新挂起的缓冲区时可写流缓冲区被清空,发送drain事件writer.on('drain', fuction(){ //对挂起事件的处理})//写入完成或调用end()方法后,将会发送finish事件writer.on('finish', function() { console.error('所有数据已经写入完成.');});
总结:Buffer是数据缓冲区对象,是二制数据在内存中的表现形式。Buffer中的数据可以按stream的形式传递到其它对象中。
wireshark对协议的识别
抓包遇到一个问题:有的包不被识别为COAP,只能显示UDP
《TCP/IP详解》中关于协议的分用:
1. 链路层:以太网首部中有不同帧类型用于表示以太网中帧内的数据; 2. IP数据包的首部:也有专门的8位协议类型,用于表示IP包中的上层协议类型(TCP是6,UDP是17); 3. 传输层的两个常用协议TCP和UDP首部中,并没有协议类型的字段,TCP和UDP包内的应用程协议的类型依靠的是TCP和UDP包首部的端口号来进行区分。对于一些常用的应用层协议IETF都规定了相应的熟知端口号。CoAP是5683。
wireshark可以针对非熟知端口的已知应用层协议设置相应的解码方式。具体的方法是:选中无法识别的报文->右键单击->Decode As->选择相应的应用层协议。