-
Notifications
You must be signed in to change notification settings - Fork 52
Hprose 服务器
Hprose 2.0 for Node.js 支持多种底层网络协议绑定的服务器,比如:HTTP 服务器,Socket 服务器和 WebSocket 服务器。
其中 HTTP 服务器支持在 HTTP、HTTPS 协议上通讯。
Socket 服务器支持在 TCP、Unix Socket 协议上通讯,并且支持全双工和半双工两种模式。
WebSocket 服务器支持在 ws、wss 协议上通讯。
尽管支持这么多不同的底层网络协议,但除了在对涉及到底层网络协议的参数设置上有所不同以外,其它的用法都完全相同。因此,我们在下面介绍 Hprose 服务器的功能时,若未涉及到底层网络协议的区别,就以 HTTP 服务器为例来进行说明。
Hprose 的服务器端的实现,分为 Service 和 Server 两部分。
其中 Service 部分是核心功能,包括接收请求,处理请求,服务调用,返回应答等整个服务的处理流程。
而 Server 则主要负责启动和关闭服务器,它包括设置服务地址和端口,设置服务器启动选项,启动服务器,接收来自客户端的连接然后传给 Service 进行处理。
之所以分开,是为了更方便的跟已有的库和框架结合,例如:connect、express 等,这些库和框架都提供了丰富的中间件,在这种情况下,只需要把 Service 作为这些库和框架的中间件来使用就可以了,在这种情况下,我们就不需要使用 Server 了。
分开的另外一个理由是,Server 部分的实现是很简单的,有时候开发者可能会希望把 hprose 服务结合到自己的某个服务器中去,而不是作为一个单独的服务器来运行,在这种情况下,也是直接使用 Service 就可以了。
当开发者没有什么特殊需求,只是希望启动一个独立的 hprose 服务器时,那使用 Server 就是一个最方便的选择了。
创建服务器有多种方式,我们先从最简单的方式说起。
var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var server = new hprose.Server("http://0.0.0.0:8080");
server.add(hello);
server.start();var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem')
};
var server = new hprose.Server("https://0.0.0.0:8080", options);
server.add(hello);
server.start();var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var server = new hprose.Server("tcp://0.0.0.0:8080");
server.add(hello);
server.start();var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
requestCert: true,
ca: [ fs.readFileSync('client-cert.pem') ]
};
var server = new hprose.Server("tls://0.0.0.0:8080", options);
server.add(hello);
server.start();var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var server = new hprose.Server("unix:/tmp/my.sock");
server.add(hello);
server.start();var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var server = new hprose.Server("ws://0.0.0.0:8080");
server.add(hello);
server.start();var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem')
};
var server = new hprose.Server("wss://0.0.0.0:8080", options);
server.add(hello);
server.start();该方法与 Server 构造器函数的参数完全一致,功能也一样。这里只举一例:
var hprose = require("hprose");
function hello(name) {
return "Hello " + name + "!";
}
var options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem')
};
var server = hprose.Server.create("https://0.0.0.0:8080", options);
server.add(hello);
server.start();var hprose = require("hprose");
var connect = require('connect');
function hello(name) {
return "Hello " + name + "!";
}
var service = new hprose.HttpService();
service.add(hello);
var app = connect()
.use(service.handle)
.listen(8080);var hprose = require("hprose");
var express = require('express');
function hello(name) {
return "Hello " + name + "!";
}
var service = new hprose.HttpService();
service.add(hello);
var app = express()
.use(service.handle)
.listen(8080);另外,HttpServer、SocketServer、WebSocketServer 都有单独的构造器函数,但是参数跟 Server 的构造器参数不太一样,相对来说,这些构造器函数的参数更接近底层,所以我们通常不需要直接使用这些构造器。
SocketService 和 WebSocketService 也可以直接使用它们的构造器函数创建服务对象,然后跟其它库或框架结合使用。这里就不再一一举例。
启动服务可以使用以下两个方法:
server.start();
server.listen(...);
start 方法不需要传入参数,它会以默认设置启动服务,这个方法是最常用的。
listen 方法启动服务是需要自己传入参数的,它的参数跟 Node.js 的 http.Server.listen、https.Server.listen、net.Server.listen 等 lesten 方法的参数相同。通常不需要使用该方法。
关闭服务器也提供了两个方法:
server.stop();
server.close(callback);
stop 方法也不需要传入参数。
close 方法的参数 callback 跟 Node.js 的各种服务的 close 方法的 callback 参数相同。通常也不需要使用该方法。
hprose.Service 是所有服务的基类。在它上面提供了以下设置:
该属性有两个用处。一个用处是用来设置底层 socket 连接的空闲超时。另一个是设置推送空闲超时。该属性默认值为 120000,单位是毫秒(ms),即 2 分钟。
当空闲超时后,底层的 socket 连接会收到一个 timeout 事件,但是跟客户端的连接并不会断开或销毁。hprose 默认并不处理该事件,用户如果有需要可以自己处理。
当服务器发布了推送主题后(后面会专门介绍推送),客户端会跟服务器端保持一个长连接,如果达到超时时间,仍然没有任何消息推送给客户端,则返回 null,此时,如果客户端仍然在线的话,则会立即再次发送获取推送主题的请求。服务器端通过这个方式可以获知客户端是否还在线。
该属性用来设置推送的心跳检测间隔时间。该属性默认值为 3000,单位是毫秒,即 3 秒钟。
当服务器端推送数据给客户端后,如果客户端在 heartbeat 时间内没有取走推送数据,则服务器端认为客户端以掉线。对于以掉线的客户端,服务器端会清除为该客户端分配的内存空间,并将该客户端从推送列表中移除。
timeout 和 heartbeat 属性在检测客户端是否离线时是相互配合的,当服务器端没有向客户端推送任何消息时,服务器端需要至少 timeout + heartbeat 的时间才能检测到客户端以离线。当服务器端有向客户端推送消息时,则在推送消息之后经过 heartbeat 时间可以检测到客户端以掉线。
timeout 和 heartbeat 设置的时间越短,检测到客户端离线的时间就越短。但是需要注意以下几个问题:
timeout 时间越短,服务器端和客户端之间的用于检测是否掉线的通讯就越频繁,所以不应该将 timeout 设置的过短,否则会严重增加服务器的负担。
因此,timeout 的设置一般不应少于 30 秒。对于负载比较高的服务器,保持默认值就是一个不错的选项。
对于推送频繁的服务器来说,heartbeat 时间越长,对于已经离线的客户端,在服务器端存储的离线消息就越多,这会严重的占用服务器端的内存,因此,不宜将 heartbeat 的时间设置的过长。
如果 heartbeat 的时间设置的过短,客户端可能会因为网络原因导致不能及时取走推送消息,这就会导致错误的离线判断,当错误离线判断发生后,会丢失一些推送消息。
因此,heartbeat 的选择则应根据客户端的网络情况来决定,如果客户端都是来自局域网,并且客户端数量较少,设置为 1 秒甚至更短的时间也是可以的。而对于比较慢速且不太稳定的移动网络,设置为 5 秒或者 10 秒可能是一个比较合适的取值。对于普通的互联网客户端来说,保持默认值就可以了。
该属性为 Boolean 类型,默认值为 false。
用来设置服务器是否是工作在 debug 模式下,在该模式下,当服务器端发生异常时,将会将详细的错误堆栈信息返回给客户端,否则,只返回错误信息。
该属性为 Boolean 类型,默认值为 false。
该属性表示调用所返回的结果是否为简单数据。简单数据是指:null、数字(包括整数、长整数、浮点数)、Boolean 值、字符串、二进制数据、日期时间等基本类型的数据或者不包含引用的数组、Map 和对象。当该属性设置为 true 时,在进行序列化操作时,将忽略引用处理,加快序列化速度。但如果数据不是简单类型的情况下,将该属性设置为 true,可能会因为死循环导致堆栈溢出的错误。
简单的讲,用 JSON 可以表示的数据都是简单数据。但是对于比较复杂的 JSON 数据,设置 simple 为 true 可能不会加快速度,反而会减慢,比如对象数组。因为默认情况下,hprose 会对对象数组中的重复字符串的键值进行引用处理,这种引用处理可以对序列化起到优化作用。而关闭引用处理,也就关闭了这种优化。
你也可以针对某个服务函数/方法进行单独设置。
因为不同调用的数据可能差别很大,因此,建议不要修改默认设置,而是针对某个服务函数/方法进行单独设置。
该属性为 Boolean 类型,默认值为 false。
该属性表示在调用中是否将 context 自动作为最后一个参数传入调用方法。
你也可以针对某个服务函数/方法进行单独设置。
除非所有的服务方法的参数最后都定义了 context 参数。否则,建议不要修改默认设置,而是针对某个服务函数/方法进行单独设置。
该属性为整型值,默认值为 10000,单位是毫秒。
该属性表示在调用执行时,如果发生异常,将延时一段时间后再返回给客户端。
在关闭该功能的情况下,如果某个服务因为编写错误抛出异常,客户端又反复重试该调用,可能会导致服务器不能正常处理其它业务请求而造成的假死机现象。使用该功能,可以避免这种问题发生。
如果你不需要该功能,设置为 0 就可以关闭它。
该属性可以为对象类型或对象数组类型。默认值为 null。
该属性的作用是可以设置一个或多个 Filter 对象。关于 Filter 对象,我们将作为单独的章节进行介绍,这里暂且略过。
hprose 为发布服务提供了多个方法,这些方法可以随意组合,通过这种组合,你所发布的服务将不会局限于某一个对象,或某一个类,而是可以将不同的函数和方法随意重新组合成一个服务。
server.addFunction(func[, alias[, options]]);该方法的功能上发布一个函数作为一个远程服务。
func 是要发布的函数,如果它是具名函数,则第二个参数 alias 可以省略。如果它是匿名函数,则第二个参数 alias 不可省略。
alias 是函数的别名,该别名是客户端调用时所使用的名字,别名中,你可以使用 _ 分隔符。当客户端调用时,根据不同的语言,可以自动转换成 . 分隔的调用,或者 -> 分隔的调用。在别名中不要使用 . 分隔符。
对于具名函数,你也可以指定一个 alias 参数作为别名。
options 是一个对象,它里面包含了一些对该服务函数的特殊设置,有以下设置项可以设置:
modesimpleonewayasyncuseHarmonyMappassContextscope
该设置表示该服务函数返回的结果类型,它有4个取值,分别是:
-
hprose.Normal(或hprose.ResultMode.Normal) -
hprose.Serialized(或hprose.ResultMode.Serialized) -
hprose.Raw(或hprose.ResultMode.Raw) -
hprose.RawWithEndTag(或hprose.ResultMode.RawWithEndTag)
hprose.Normal 是默认值,表示返回正常的已被反序列化的结果。
hprose.Serialized 表示返回的结果保持序列化的格式。
hprose.Raw 表示返回原始数据。
hprose.RawWithEndTag 表示返回带有结束标记的原始数据。
这四种结果的形式在客户端的相关介绍中已有说明,这里不再重复。
不过要注意的是,这里的设置跟客户端的设置并没有直接关系,这里设置的是服务函数本身返回的数据格式,即使服务函数返回的是 hprose.RawWithEndTag 格式的数据,客户端仍然可以以其它三种格式来接收数据。
该设置通常用于做高性能的缓存或代理服务器。我们在后面介绍 addMissingFunction 方法时再举例说明。
该设置表示本服务函数所返回的结果是否为简单数据。默认值与全局设置一致。前面在属性介绍中已经进行了说明,这里就不在重复。
该设置表示本服务函数是否不需要等待返回值。当该设置为 true 时,调用会异步开始,并且不等待结果,立即返回 null 给客户端。默认值为 false。
该设置表示本服务函数是否为异步函数,异步函数的最后一个参数是一个回调函数,用户需要在异步函数中调用该回调方法来传回返回值,例如:
var hprose = require("hprose");
function hello(name, callback) {
setTimeout(function() {
callback("Hello " + name + "!");
}, 10);
}
var server = hprose.Server.create("http://0.0.0.0:8080");
server.addFunction(hello, { async: true });
server.start();该设置为 Boolean 类型,默认值为 false。
该设置表示在接收服务函数的参数时,如果参数中包含有 Map 类型的数据,是否反序列化为 ECMAScript 6 中的 Map 类型对象。当该属性设置为 false 时(即默认值),Map 类型的数据将会被反序列化为 Object 实例对象的数据。
除非 Map 中的键不是字符串类型,否则没必要设置为 true。
该设置与 server.passContext 属性的功能相同。但在这里它是针对该服务函数的单独设置。例如:
var hprose = require("hprose");
function hello(name, context) {
return 'Hello ' + name + '! -- ' + context.socket.remoteAddress;
}
var server = hprose.Server.create("http://0.0.0.0:8080");
server.addFunction(hello, { passContext: true });
server.start();注意,当 passContext 和 async 同时设置为 true 的时候,服务函数的 context 参数应该放在 callback 参数之前,例如:
var hprose = require("hprose");
function hello(name, context, callback) {
setTimeout(function() {
callback('Hello ' + name + '! -- ' + context.socket.remoteAddress);
}, 10);
}
var server = hprose.Server.create("http://0.0.0.0:8080");
server.addFunction(hello, { passContext: true, async: true });
server.start();该选项表示服务函数/方法执行时,函数/方法中所引用的 this 对象。默认为 undefined。
server.addAsyncFunction(func[, alias[, options]]);该方法与 addFunction 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addFunction 发布异步方法的简写形式。
server.addMissingFunction(func[, options]);该方法用于发布一个用于处理客户端调用缺失服务的函数。缺失服务是指服务器端并没有明确发布的远程函数/方法。例如:
在服务器端没有发布 hello 函数时,在默认情况下,客户端调用该函数,服务器端会返回 `'Can't find this function hello().' 这样一个错误。
但是如果服务器端通过本方法发布了一个用于处理客户端调用缺失服务的 func 函数,则服务器端会返回这个 func 函数的返回值。
该方法还可以用于做代理服务器,例如:
'use strict';
var hprose = require('hprose');
var client = hprose.Client.create('http://www.hprose.com/example/', []);
function proxy(name, args) {
return client.invoke(name, args, { mode: hprose.RawWithEndTag });
}
var server = hprose.Server.create("tcp://0.0.0.0:1234");
server.addMissingFunction(proxy, { mode: hprose.RawWithEndTag });
server.start();现在,客户端对这个服务器所发出的所有请求,都会通过 proxy 函数转发到 http://www.hprose.com/example/ 这个服务上,并把结果直接按照原始方式返回。
另外,我们还知道 client.invoke 方法的返回值是一个 promise 对象,也就是说,服务函数/方法其实也可以直接返回 promise 对象,异步服务不一定非要用 callback 方式。
该方法与 addMissingFunction 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addMissingFunction 发布异步方法的简写形式。
server.addFunctions(funcs[, aliases[, options]]);如果你想同时发布多个方法,可以使用该方法。
funcs 是函数数组,数组元素必须为 function 类型的对象。
aliases 是别名数组,数组元素必须是字符串,并且需要与 funcs 数组中的元素个数一一对应。
当 funcs 中的函数全都是具名函数时,aliases 可以省略。
options 的选项值跟 addFunction 方法相同。
该方法与 addFunctions 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addFunctions 发布异步方法的简写形式。
server.addMethod(method[, obj[, alias[, options]]]);该方法跟 addFunction 类似,它的功能是添加方法。
method 是方法或者方法名,也就是说,可以是函数类型,也可以是字符串。
obj 是 method 所在的对象。如果省略 obj,那么等同于调用:
server.addFunction(method[, alias[, options]]);因此当省略 obj 时,method 不可以是字符串。
alias 是方法的别名。
options 选项值跟 addFunction 方法相同。
该方法与 addMethod 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addMethod 发布异步方法的简写形式。
server.addMissingMethod(method[, obj[, options]])该方法的功能与 addMissingMethod 类似。它们之前的区别跟 addMethod 和 addFunction 相同。这里就不详细介绍了。
该方法与 addMissingMethod 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addMissingMethod 发布异步方法的简写形式。
server.addMethods(methods[, obj[, aliases, [options]]]);该方法的功能与 addFunctions 类似。它们之前的区别跟 addMethod 和 addFunction 相同。这里就不详细介绍了。
该方法与 addMethods 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addMethods 发布异步方法的简写形式。
server.addInstanceMethods(obj[, aliasPrefix[, options]]);该方法用于发布 obj 上所有可以列举的方法(即可以通过 for in 循环得到的)。
aliasPrefix 是别名前缀,例如假设有一个 user 对象,该对象上包含有 add,del,update,query 四个方法。那么当调用:
server.addInstanceMethods(user, 'user');的方式来发布 user 对象上的这四个方法后,等同于这样的发布:
server.addMethods([`add`,`del`,`update`,`query`],
user,
[`user_add`,`user_del`,`user_update`,`user_query`]);即在每个发布的方法名之前都添加了一个 user_ 的前缀。注意这里前缀和方法名之间是使用 _ 分隔的。
当省略 aliasPrefix 参数时,发布的方法名前不会增加任何前缀。
最后的 options 选项值跟 addFunction 方法相同。
该方法与 addInstanceMethods 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 addInstanceMethods 发布异步方法的简写形式。
上面如此之多的 addXXX 方法也许会把你搞晕,也许你不查阅本手册,都记不清该使用哪个方法来发布。
没关系,add 方法就是用来简化上面这些 addXXX 方法的。
add 方法不支持 options 参数。其它参数你只要按照上面任何一个方法的参数来写,add 方法都可以自动根据参数的个数和类型判断该调用哪个方法进行发布,当你不需要设置 options 参数时,它会大大简化你的工作量。
该方法与 add 功能相同,但是 async 选项被默认设置为 true。也就是说,它是 add 发布异步方法的简写形式。
hprose 2.0 最大的亮点就是增加了推送功能的支持,而且这个功能的增加是在不修改现有通讯协议的方式下实现的,因此,这里的推送服务,即使不是 hprose 2.0 的客户端也可以使用。
当然,在旧版本的客户端调用推送服务,需要多写一些代码。所以,如果你所使用的语言支持 hprose 2.0,那么推荐直接使用 hprose 2.0 的推送 API 来做推送,这样会极大的减少你的工作量。
下面我们来介绍一下服务器端增加的关于推送的 API。
server.publish(topic[, options]);该方法用于发布一个推送主题。这个推送的主题实际上是一个自动生成的远程服务方法。它的功能就是实现推送。
topic 为主题名,字符串类型。
options 是发布推送主题的选项,该选项同 add 方法的选项完全不同。这里的选项值包括以下 3 个:
timeoutheartbeatevents
这里 timeout 和 heartbeat 在前面的属性介绍里已经说明过了,这里不再重复。
events 是一个 EventEmitter 对象。你可以在上面定义以下两个事件:
subscribeunsubscribe
这两个事件的参数相同,第一个参数是客户端 id,第二个参数是服务器对象本身。
当编号为 id 的客户端第一次连接该推送主题的时,subscribe 事件会被触发。当编号为 id 的客户端被检测到离线时,unsubscribe 事件会被触发。
如果该主题没有设置 events 选项,则会触发服务器上的这两个事件,但是服务器上的这两个事件的会在开头多一个参数 topic,即 publish 方法发布的 topic 参数。
publish 方法仅仅是告诉客户端,现在有一个叫做 topic 的推送主题可以订阅。
而要真正推送数据给客户端,则需要使用以下几个方法。
server.broadcast(topic, result[, callback]);
server.push(topic, result);这两个方法功能相同,但是 broadcast 方法支持回调,该回调方法有两个参数,这个参数都是数组类型,第一个数组中是所有推送成功的客户端 id,第二个数组中是所有推送失败的客户端 id。
一旦服务器启动,你可以在任何地方进行数据推送。比如在其它的服务方法中,在服务器事件中,甚至在服务器外的并行运行的函数中。例如:
时间推送服务器
var hprose = require('hprose');
var server = hprose.Server.create("http://0.0.0.0:8080");
server.publish('time');
setInterval(function() {
server.push('time', new Date());
}, 1000);
server.start();时间显示客户端
var hprose = require('hprose');
var client = hprose.Client.create("http://127.0.0.1:8080");
var count = 0;
client.subscribe('time', function(date) {
if (++count > 10) {
client.unsubscribe('time');
}
else {
console.log(date);
}
});该程序运行结果为:
Sat Aug 08 2015 20:54:44 GMT+0800 (CST)
Sat Aug 08 2015 20:54:45 GMT+0800 (CST)
Sat Aug 08 2015 20:54:46 GMT+0800 (CST)
Sat Aug 08 2015 20:54:47 GMT+0800 (CST)
Sat Aug 08 2015 20:54:48 GMT+0800 (CST)
Sat Aug 08 2015 20:54:49 GMT+0800 (CST)
Sat Aug 08 2015 20:54:50 GMT+0800 (CST)
Sat Aug 08 2015 20:54:51 GMT+0800 (CST)
Sat Aug 08 2015 20:54:52 GMT+0800 (CST)
Sat Aug 08 2015 20:54:53 GMT+0800 (CST)
有时候,你可能想在某个服务方法中推送数据给客户端,但是该服务方法可能在其它文件中定义。因此,你得不到 server 对象。那这时还能进行推送吗?
答案是可以,没问题。我们前面说过,在服务方法中我们可以得到一个 context 参数,这个 context 参数中就包含有一个 clients 对象,这个对象上就包含了所有跟推送有关的方法,这些方法跟 server 对象上的推送方法是完全一样的,例如:
context.clients.broadcast(topic, result[, callback]);
context.clients.push(topic, result);我们再来看一个例子:
服务器
var hprose = require('hprose');
function hello(name, context) {
context.clients.push("news", "this is a pushed message: " + name);
context.clients.broadcast("news", {x: 1,
y: 2,
message: "this is a pushed object:" + name});
return 'Hello ' + name + '! -- ' + context.socket.remoteAddress;
}
var server = hprose.Server.create("ws://0.0.0.0:8080");
server.addFunction(hello, {passContext: true});
server.publish('news');
server.start();客户端
var hprose = require('hprose');
var client = hprose.Client.create("ws://127.0.0.1:8080", ['hello']);
client.subscribe('news', function(news) {
console.log(news);
});
client.hello('hprose').then(function(result) {
console.log(result);
});假设我们运行两个客户端,则第一个客户端显示:
this is a pushed message: hprose
Hello hprose! -- 127.0.0.1
{ x: 1, y: 2, message: 'this is a pushed object:hprose' }
this is a pushed message: hprose
{ x: 1, y: 2, message: 'this is a pushed object:hprose' }
第二个客户端显示:
this is a pushed message: hprose
Hello hprose! -- 127.0.0.1
{ x: 1, y: 2, message: 'this is a pushed object:hprose' }
这两个客户端显示结果之后并不会退出,如果有其它客户端再次运行时,这两个客户端还会继续显示推送信息。也就是说,对于已经执行了 subscribe 的客户端,在未执行对应的 unsubscribe 方法之前,该客户端会一直运行,接收推送数据,即使服务器已经关闭,客户端也不会退出。
server.multicast(topic, ids, result[, callback]);
server.push(topic, ids, result);
context.clients.multicast(topic, ids, result[, callback]);
context.clients.push(topic, ids, result);跟广播类似,多播也有这样几种形式。跟广播相比,多播多了一个 ids 参数,它是一个客户端 id 的数组。也就是说,你可以向指定的一组客户端推送消息。
server.unicast(topic, id, result[, callback]);
server.push(topic, id, result);
context.clients.unicast(topic, id, result[, callback]);
context.clients.push(topic, id, result);单播是跟多播的形式也类似,只不过客户端 ids 数组参数变成了一个客户端 id 参数。
但是还有一点要注意,unicast 的回调方法跟 broadcast 和 multicast 不同,unicast 的回调方法只有一个参数,而且是一个 Boolean 值,该值为 true 是表示推送成功,为 false 表示推送失败。
server.idlist(topic);
context.clients.idlist(topic);该方法用于获取当前在线的所有客户端的 id 列表。
server.exist(topic, id);
context.clients.exist(topic, id);该方法用于快速判断 id 是否在当前在线的客户端列表中。
注意,客户端在线状态是针对主题的,同一个客户端可能针对一个主题处于在线状态,但是针对另一个主题却处于离线状态,这种情况是正常的。