使用websocket发送字节流,先构造一个大缓存区,然后每次都在该缓冲区填充数据,填充完后把有效数据发送出去,大概写法如下:
let buf=new ArrayBuffer(512);
//只发送从第10个字节开始的20个字节长度的数据
let pack=new Uint8Array(buf,10,20);
sock.send(pack);
该段代码在浏览器里面可以正确的发送20个字节的数据,但在native下,发送了512个字节的数据!即把大的缓冲区发出去了。
阅读了一下C++代码发现jswarpper/v8/object.cpp中的getTypedArrayData函数有问题,这个函数没有考虑到Uint8Array在ArrayBuffer中的偏移和长度,原始代码如下:
bool Object::getTypedArrayData(uint8_t** ptr, size_t* length) const
{
assert(isTypedArray());
v8::Local<v8::Object> obj = const_cast<Object*>(this)->_obj.handle(__isolate);
v8::Local<v8::Uint8Array> arr = v8::Local<v8::Uint8Array>::Cast(obj);
v8::ArrayBuffer::Contents content = arr->Buffer()->GetContents();
*ptr = (uint8_t*)content.Data(); //内部的buffer
*length = content.ByteLength(); //内部的buffer数据长度
return true;
}
这个段代码得到的数据和长度是Uint8Array内部ArrayBuffer的数据和长度,未考虑到UInt8Array只是ArrayBuffer中一部分的情况。
这段代码是不是应该这样写呢?
bool Object::getTypedArrayData(uint8_t** ptr, size_t* length) const
{
assert(isTypedArray());
v8::Local<v8::Object> obj = const_cast<Object*>(this)->_obj.handle(__isolate);
v8::Local<v8::Uint8Array> arr = v8::Local<v8::Uint8Array>::Cast(obj);
v8::ArrayBuffer::Contents content = arr->Buffer()->GetContents();
//*ptr = (uint8_t*)content.Data();
//*length = content.ByteLength();
*ptr = ((uint8_t*)content.Data())+arr->ByteOffset();
*length = arr->ByteLength();
return true;
}
经测试,修改之后,服务器收到的数据长度不再是固定长度512,而是实际数据长度。