我目前正在尝试使用gRPC Node.js API设置服务器流。为此,我想在服务器端写入流时,客户端立即接收到数据事件。
如果我仅在服务器端调用write,那么我现在在客户端什么都没有收到。但是,一旦我在服务器上调用end函数,客户端就会收到所有数据事件。
为了测试这一点,我使用了一个无限的while循环在服务器端编写消息。然后,客户端不接收消息(数据事件)。相反,如果我使用for循环并随后调用end,则在调用end时,客户端会收到所有消息(数据事件)。
我的.proto文件:
syntax = "proto3";
message ControlMessage {
enum Control {
Undefined = 0;
Start = 1;
Stop = 2;
}
Control control = 1;
}
message ImageMessage {
enum ImageType {
Raw = 0;
Mono8 = 1;
RGB8 = 2;
}
ImageType type = 1;
int32 width = 2;
int32 height = 3;
bytes image = 4;
}
service StartImageTransmission {
rpc Start(ControlMessage) returns (stream ImageMessage);
}
在服务器端,我实现了启动功能,并试图无休止地向呼叫写入消息:
function doStart(call) {
var imgMsg = {type: "Mono8", width: 600, height: 600, image: new ArrayBuffer(600*600)};
//for(var i = 0; i < 10; i++) {
while(true) {
call.write(imgMsg);
console.log("Message sent");
}
call.end();
}
我将该功能注册为服务器中的服务:
var server = new grpc.Server();
server.addService(protoDescriptor.StartImageTransmission.service, {Start: doStart});
在客户端,我会生成一个适当的调用并注册数据和结束事件:
var call = client.Start({control: 0});
call.on('data', (imgMessage) => {
console.log('received image message');
});
call.read();
call.on('end', () => {console.log('end');});
我也试图用python编写服务器端。在这种情况下,节点客户端不仅在服务器端结束流传输后立即接收消息。因此,我猜对于使用Node API编写的服务器也应该可行。
答案 0 :(得分:1)
问题似乎在于,无尽的while循环阻塞了节点中的所有后台任务。一种可能的解决方案是使用setTimeout
创建循环。以下代码对我有用:
首先在gRPC调用中将call
对象存储在数组中:
function doStart(call) {
calls.push(call);
}
对于发送给所有客户端,我使用setTimeout:
function sendToAllClients() {
calls.forEach((call) => {
call.write(imgMsg);
});
setTimeout(sendToAllClients, 10);
}
setTimeout(sendToAllClients, 10);
有用的stackoverflow公式:Why does a while loop block the event loop?