-
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 秒可能是一个比较合适的取值。对于普通的互联网客户端来说,保持默认值就可以了。