electron + grpc 项目中grpc 启动出错
项目中用的electron 13.1.7, @grpc/grpc-js 1.3.6
一开始在外面独立试了试grpc的demo, 用的还是grpc, 而不是@grpc/grpc-js
放到electron,重新npm install 之后,报了错,才改为@grpc的。
grpc的serve端文件中,把bind函数替换成bindAsync函数,出现如下报错
App threw an error during load
TypeError: callback must be a function
at Server.bindAsync (C:\Users\zhijue\project\electron\node_modules\@grpc\grpc-js\build\src\server.js:147:19)
at main (C:\Users\zhijue\project\electron\greeter_server.js:56:10)
at Object.<anonymous> (C:\Users\zhijue\project\electron\greeter_server.js:61:1)
at Module._compile (internal/modules/cjs/loader.js:1078:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1108:10)
at Module.load (internal/modules/cjs/loader.js:935:32)
at Module._load (internal/modules/cjs/loader.js:776:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12913)
at Module.require (internal/modules/cjs/loader.js:959:19)
at require (internal/modules/cjs/helpers.js:88:18)
去看了源码文件,发现这个新函数要多传一个回调
bind(port, creds) { // 原来的bind
throw new Error('Not implemented. Use ```bindAsync() instead');
}
bindAsync(port, creds, callback) { // 现在的函数
但是对于这个回调函数,我没太看懂,源码里面是这么调用callback的
const resolverListener = {
onSuccessfulResolution: (addressList, serviceConfig, serviceConfigError) => {
// We only want one resolution result. Discard all future results
resolverListener.onSuccessfulResolution = () => { };
if (addressList.length === 0) {
callback(new Error(`No addresses resolved for port ${port}`), 0);
return;
}
let bindResultPromise;
if (subchannel_1.isTcpSubchannelAddress(addressList[0])) {
if (addressList[0].port === 0) {
bindResultPromise = bindWildcardPort(addressList);
}
else {
bindResultPromise = bindSpecificPort(addressList, addressList[0].port, 0);
}
}
else {
// Use an arbitrary non-zero port for non-TCP addresses
bindResultPromise = bindSpecificPort(addressList, 1, 0);
}
bindResultPromise.then((bindResult) => {
if (bindResult.count === 0) {
const errorString = `No address added out of total ${addressList.length} resolved`;
logging.log(constants_1.LogVerbosity.ERROR, errorString);
callback(new Error(errorString), 0);
}
else {
if (bindResult.count < addressList.length) {
logging.log(constants_1.LogVerbosity.INFO, `WARNING Only ${bindResult.count} addresses added out of total ${addressList.length} resolved`);
}
callback(null, bindResult.port);
}
}, (error) => {
const errorString = `No address added out of total ${addressList.length} resolved`;
logging.log(constants_1.LogVerbosity.ERROR, errorString);
callback(new Error(errorString), 0);
});
},
onError: (error) => {
callback(new Error(error.details), 0);
},
};
然后在服务端代码中,我传了一个空函数进去
function main() {
const server = new grpc.Server();
server.addService(hello_proto.Greeter.service, {
SayHello: sayHello2,
printAge: printAge2
});
server.bindAsync('127.0.0.1:50051', grpc.ServerCredentials.createInsecure(),function(){});
server.start();
console.log('server start......')
}
main()
出现如下报错
App threw an error during load
Error: server must be bound in order to start
at Server.start (C:\Users\zhijue\project\electron\node_modules\@grpc\grpc-js\build\src\server.js:336:19)
at main (C:\Users\zhijue\project\electron\greeter_server.js:57:10)
at Object.<anonymous> (C:\Users\zhijue\project\electron\greeter_server.js:61:1)
at Module._compile (internal/modules/cjs/loader.js:1078:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1108:10)
at Module.load (internal/modules/cjs/loader.js:935:32)
at Module._load (internal/modules/cjs/loader.js:776:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12913)
at Module.require (internal/modules/cjs/loader.js:959:19)
at require (internal/modules/cjs/helpers.js:88:18)
No address added out of total 1 resolved
下面是我对源码的一些分析:
首先是在bindAsybc函数中,有一个bindSpectficPort的函数中,会把一个http2服务加入http2ServerList数组中,然后在start()函数中,会对http2ServerList数组进行判断,如果为空数组,就会抛出错误。但是通过console.log发现,在进入了bindSpectficPort函数中后,并没有执行http2ServerList数组添加的操作,然后执行start函数了,所以一定会报错的
不知道有没有哪位大佬能看一看
下面为bindSpectficPorth函数源码
const bindSpecificPort = (addressList, portNum, previousCount) => {
if (addressList.length === 0) {
return Promise.resolve({ port: portNum, count: previousCount });
}
return Promise.all(addressList.map((address) => {
trace('Attempting to bind ' + subchannel_1.subchannelAddressToString(address));
let addr;
if (subchannel_1.isTcpSubchannelAddress(address)) {
addr = {
host: address.host,
port: portNum,
};
}
else {
addr = address;
}
const http2Server = setupServer();
return new Promise((resolve, reject) => {
function onError(err) {
resolve(err);
}
http2Server.once('error', onError);
http2Server.listen(addr, () => {
trace('Successfully bound ' + subchannel_1.subchannelAddressToString(address));
console.log('push1')
this.http2ServerList.push(http2Server);
const boundAddress = http2Server.address();
if (typeof boundAddress === 'string') {
resolve(portNum);
}
else {
resolve(boundAddress.port);
}
http2Server.removeListener('error', onError);
});
});
})).then((results) => {
let count = 0;
for (const result of results) {
if (typeof result === 'number') {
count += 1;
if (result !== portNum) {
throw new Error('Invalid state: multiple port numbers added from single address');
}
}
}
return {
port: portNum,
count: count + previousCount,
};
});
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第二天一早,我在知乎上发现了一个demo,终于发现了问题所在,在原来的bind函数的写法中,start()函数放在函数下面,但是在bindAsync中,start()应该放在回调函数中,这样就不会出现上述的问题。
参考文章链接 在Node.js中使用grpc-知乎