问题描述
socket对象创建后是否可以设置highWaterMark:
is it possible to set the highWaterMark of a socket object after it was created:
var http = require('http');
var server = http.createServer();
server.on('upgrade', function(req, socket, head) {
socket.on('data', function(chunk) {
var frame = new WebSocketFrame(chunk);
// skip invalid frames
if (!frame.isValid()) return;
// if the length in the head is unequal to the chunk
// node has maybe split it
if (chunk.length != WebSocketFrame.getLength()) {
socket.once('data', listenOnMissingChunks);
});
});
});
function listenOnMissingChunks(chunk, frame) {
frame.addChunkToPayload(chunk);
if (WebSocketFrame.getLength()) {
// if still corrupted listen once more
} else {
// else proceed
}
}
上面的代码示例不起作用.但是我该怎么做呢?
The above code example does not work. But how do I do it instead?
进一步说明:当我收到大的 WebSocket 帧时,它们会被分成多个数据事件.这使得解析帧变得困难,因为我不知道这是一个分裂的还是损坏的帧.
Further explaination:When I receive big WebSocket frames they get split into multiple data events. This makes it hard to parse the frames because I do not know if this is a splitted or corrupted frame.
推荐答案
我想你误解了 TCP 套接字的本质.尽管 TCP 通过 IP 数据包发送其数据,但 TCP 不是数据包协议.TCP 套接字只是数据的流.因此,将data
事件视为逻辑消息 是不正确的.换句话说,一端的 socket.write
不等同于另一端的单个 data
事件.
I think you misunderstand the nature of a TCP socket. Despite the fact that TCP sends its data over IP packets, TCP is not a packet protocol. A TCP socket is simply a stream of data. Thus, it is incorrect to view the data
event as a logical message. In other words, one socket.write
on one end does not equate to a single data
event on the other.
对套接字的单次写入不能 1:1 映射到单个 data
事件的原因有很多:
There are many reasons that a single write to a socket does not map 1:1 to a single data
event:
- 发送方的网络堆栈可能会将多个小写操作合并到一个 IP 数据包中.(Nagle 算法)
- 如果 IP 数据包的大小超过任何一跳的 MTU.
- 接收方的网络堆栈可能将多个数据包合并为一个
data
事件(如您的应用程序所见).
- The sender's network stack may combine multiple small writes into a single IP packet. (The Nagle algorithm)
- An IP packet may be fragmented (split into multiple packets) along its journey if its size exceeds any one hop's MTU.
- The receiver's network stack may combine multiple packets into a single
data
event (as seen by your application).
因此,单个data
事件可能包含多条消息、一条消息或一条消息的一部分.
Because of this, a single data
event might contain multiple messages, a single message, or only part of a message.
为了正确处理通过流发送的消息,您必须缓冲传入数据,直到获得完整的消息.
In order to correctly handle messages sent over a stream, you must buffer incoming data until you have a complete message.
var net = require('net');
var max = 1024 * 1024 // 1 MB, the maximum amount of data that we will buffer (prevent a bad server from crashing us by filling up RAM)
, allocate = 4096; // how much memory to allocate at once, 4 kB (there's no point in wasting 1 MB of RAM to buffer a few bytes)
, buffer=new Buffer(allocate) // create a new buffer that allocates 4 kB to start
, nread=0 // how many bytes we've buffered so far
, nproc=0 // how many bytes in the buffer we've processed (to avoid looping over the entire buffer every time data is received)
, client = net.connect({host:'example.com', port: 8124}); // connect to the server
client.on('data', function(chunk) {
if (nread + chunk.length > buffer.length) { // if the buffer is too small to hold the data
var need = Math.min(chunk.length, allocate); // allocate at least 4kB
if (nread + need > max) throw new Error('Buffer overflow'); // uh-oh, we're all full - TODO you'll want to handle this more gracefully
var newbuf = new Buffer(buffer.length + need); // because Buffers can't be resized, we must allocate a new one
buffer.copy(newbuf); // and copy the old one's data to the new one
buffer = newbuf; // the old, small buffer will be garbage collected
}
chunk.copy(buffer, nread); // copy the received chunk of data into the buffer
nread += chunk.length; // add this chunk's length to the total number of bytes buffered
pump(); // look at the buffer to see if we've received enough data to act
});
client.on('end', function() {
// handle disconnect
});
client.on('error', function(err) {
// handle errors
});
function find(byte) { // look for a specific byte in the buffer
for (var i = nproc; i < nread; i++) { // look through the buffer, starting from where we left off last time
if (buffer.readUInt8(i, true) == byte) { // we've found one
return i;
}
}
}
function slice(bytes) { // discard bytes from the beginning of a buffer
buffer = buffer.slice(bytes); // slice off the bytes
nread -= bytes; // note that we've removed bytes
nproc = 0; // and reset the processed bytes counter
}
function pump() {
var pos; // position of a NULL character
while ((pos = find(0x00)) >= 0) { // keep going while there's a NULL (0x00) somewhere in the buffer
if (pos == 0) { // if there's more than one NULL in a row, the buffer will now start with a NULL
slice(1); // discard it
continue; // so that the next iteration will start with data
}
process(buffer.slice(0,pos)); // hand off the message
slice(pos+1); // and slice the processed data off the buffer
}
}
function process(msg) { // here's where we do something with a message
if (msg.length > 0) { // ignore empty messages
// here's where you have to decide what to do with the data you've received
// experiment with the protocol
}
}
这篇关于Nodejs:设置socket对象的highWaterMark的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!