客户端上的Websocket:
socket.send('helloworld');
Node.js:上的Websocket
socket.ondata = function(d, start, end){
// I suppose that the start and end indicates the location of the
// actual data 'hello world' after the headers
var data = d.toString('utf8', start, end);
// Then I'm just printing it
console.log(data);
});
但我在终端上收到了这个:�����]���1���/��
:O
我试着理解这个医生:https://www.rfc-editor.org/rfc/rfc6455#section-5.2但这很难理解,因为我不知道应该使用什么,我的意思是,即使使用toString
,我也看不到数据?
我试着用这个问题来回答和测试我如何在服务器端发送和接收WebSocket消息?但我无法让它工作,有了这个答案,我得到了一个像这样的数组[假,真,假,假,真的,真,假的]等等……我真的不知道该怎么办……:\
所以我有点困惑,在我从客户端获得数据后,我该怎么办才能获得真正的消息?
我使用的是没有任何库的原始客户端和node.js API
您正在使用哪个node.js库?根据您正在挂接的socket.ondata看起来像HTTP服务器API这一事实来判断。WebSockets不是HTTP。它有一个HTTP兼容的握手,这样WebSocket和HTTP服务就可以在同一个端口上运行,但这就是相似性的终点。握手之后,WebSockets是一种框架式全双工、长寿命的消息传输,与常规TCP套接字相比,它更类似于HTTP。
如果你想在node.js中实现你自己的WebSocket服务器,你需要直接使用套接字库(或者在现有的WebSocketserver代码上构建/借用)。
下面是一个基于Node.js的WebSocket服务器,它从WebSocket桥接到TCP套接字:https://github.com/kanaka/websockify/blob/master/other/websockify.js请注意,它是针对协议的前一个Hixie版本的(我还没有机会或动机更新它)。该协议的现代HyBI版本非常不同,但您可能能够从该实现中收集一些有用的信息。
实际上,可以从Node的HTTP API开始。这正是我在编写WebSocket Node模块时所做的https://github.com/Worlize/WebSocket-Node
如果你不想使用现有的WebSocket库(尽管你真的应该只使用现有的库),那么你需要能够解析RFC定义的二进制数据格式。它非常清楚数据的格式以及如何解释数据。从每一帧中,您必须读入所有标志,解释帧大小,可能读取遮罩关键点,并在从导线中读取内容时取消遮罩。
这就是你看不到任何可识别的东西的原因之一。。。在WebSockets中,所有客户端到服务器的通信都会被混淆,方法是使用XOR对内容应用随机掩码,以防可能毒害不了解WebSockets的旧代理服务器的缓存。
有两件事-
-
您正在使用哪个node.js版本?我从未见过带有start和endpt的数据事件。发出的事件只是以buffer/string作为参数的数据。
-
更重要的是,如果您正在挂接HTTP套接字,则应该处理HTTP数据包。它包含助听器、车身和拖车。那里可能有垃圾。
以下是本文的解决方案:
https://medium.com/hackernoon/implementing-a-websocket-server-with-node-js-d9b78ec5ffa8
parseMessage(buffer) {
const firstByte = buffer.readUInt8(0);
//const isFinalFrame = Boolean((firstByte >>> 7) & 0x1);
//const [reserved1, reserved2, reserved3] = [ Boolean((firstByte >>> 6) & 0x1),
Boolean((firstByte >>> 5) & 0x1), Boolean((firstByte >>> 4) & 0x1) ];
const opCode = firstByte & 0xF;
// We can return null to signify that this is a connection termination frame
if (opCode === 0x8)
return null;
// We only care about text frames from this point onward
if (opCode !== 0x1)
return;
const secondByte = buffer.readUInt8(1);
const isMasked = Boolean((secondByte >>> 7) & 0x1);
// Keep track of our current position as we advance through the buffer
let currentOffset = 2; let payloadLength = secondByte & 0x7F;
if (payloadLength > 125) {
if (payloadLength === 126) {
payloadLength = buffer.readUInt16BE(currentOffset);
currentOffset += 2;
} else {
// 127
// If this has a value, the frame size is ridiculously huge!
//const leftPart = buffer.readUInt32BE(currentOffset);
//const rightPart = buffer.readUInt32BE(currentOffset += 4);
// Honestly, if the frame length requires 64 bits, you're probably doing it wrong.
// In Node.js you'll require the BigInt type, or a special library to handle this.
throw new Error('Large payloads not currently implemented');
}
}
const data = Buffer.alloc(payloadLength);
// Only unmask the data if the masking bit was set to 1
if (isMasked) {
let maskingKey = buffer.readUInt32BE(currentOffset);
currentOffset += 4;
// Loop through the source buffer one byte at a time, keeping track of which
// byte in the masking key to use in the next XOR calculation
for (let i = 0, j = 0; i < payloadLength; ++i, j = i % 4) {
// Extract the correct byte mask from the masking key
const shift = j == 3 ? 0 : (3 - j) << 3;
const mask = (shift == 0 ? maskingKey : (maskingKey >>> shift)) & 0xFF;
// Read a byte from the source buffer
const source = buffer.readUInt8(currentOffset++);
// XOR the source byte and write the result to the data
data.writeUInt8(mask ^ source, i);
}
} else {
// Not masked - we can just read the data as-is
buffer.copy(data, 0, currentOffset++);
}
return data
}