Zeroc ice 是一个比较好用的分布式框架,之前在项目中也一直在用,用的是3.5版本。从3.6版本开始,ice就开始支持 js 使用。这回因为项目 html 页面中也需要用到 ice,所以直接用了 3.7版本。
但是因为服务端用的都是较低版本的ice,3.3、3.5之类的,不支持js,所以只能用3.7版本再搭建一层服务端,最后才是客户端和前端页面。
3.6以上版本的 ice js库文件可以在下面网址中找到。
传送门: ice js库
3.7 和 之前用的3.5 版本有如下区别:
js版本的ice无法实现它自己的服务端,所以服务端一般需要使用其它语言版本的,如c、c++、python、java等。此处用java。
module Manager{
dictionary<string, string> temp;
dictionary<string, temp> dicparam;
interface statusManager
{
void getStatusofAllOtherDevices(out dicparam para);
};
};
因为需要在中间再搭建一层服务端,所以需要将接口文件同时转换为java文件和js文件
slice2java Manager.ice //服务端用,生成Manager文件夹,放在java项目的src文件夹下。因为用的ice3.7,所以需要引入ice3.7的jar包
slice2js Manager.ice //客户端用,生成Manager.js文件,html文件中需要引入ice库文件和生成的这个文件
服务端用的 ice 3.7 的 jar 包 可以在下面的连接中找到。
传送门:ice3.7 jar包
import java.util.HashMap;
import java.util.Map;
import com.zeroc.Ice.Current;
import Manager.statusManager;
//这里也存在ice3.5 和 3.7版本的差别。3.5生成的文件夹中包含很多文件,在3.5版本中 statusManagerI extends _statusManagerDsp .
public class statusManagerI implements statusManager{
public statusManagerI() {
//implementation
}
@Override
public Map<String, Map<String, String>> getStatusofAllOtherDevices(Current current) {
Map<String, String> map = new HashMap<String,String>();
Map<String, Map<String, String>> value = new HashMap<String, Map<String, String>>();
//implementation
return value;
}
}
public class Server
{
public static void main(String[] args)
{
//这里可以看到类已经收藏到com.zeroc包下了
try(com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args))
{
com.zeroc.Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("StatusManagerAdapter", "ws -h localhost -p 10000:default -h localhost -p 10001");
com.zeroc.Ice.Object object = new statusManagerI();
adapter.add(object, com.zeroc.Ice.Util.stringToIdentity("StatusManager"));
adapter.activate();
communicator.waitForShutdown();
}
}
}
在测试阶段时,服务端和客户端之间的连接怎么都不通,因为官网给的操作手册中,对 js 版本的服务端只是提了一下,说要使用其它服务端,却没有更详细的说明。如下
The server must be started before the client. Since Ice for JavaScript
does not currently include a complete server-side implementation, we
need to use a server from another language mapping.
除此之外,没有更多的说明,导致服务端一直使用的之前的配置方法,所以怎么都连不上。
之前的配置方法:
communicator.createObjectAdapterWithEndpoints("StatusManagerAdapter", "default -h localhost -p 10000");
面向 js 应该使用的配置方法
communicator.createObjectAdapterWithEndpoints("StatusManagerAdapter", "ws -h localhost -p 10000");
default 指向的是tcp连接,但面向js时,服务端需要设置为面向websocket连接,所以 default应该改为 ws。
在寻找并阅读他人的例子时,了解到可以面向多个配置,配置之间用 :隔开。为了既可以面向js 又可以面向一般的如java、c等语言,服务端设置成既面向js又面向一般普通语言
communicator.createObjectAdapterWithEndpoints("StatusManagerAdapter", "ws -h localhost -p 10000:default -h localhost -p 10001");
(function () {
var communicator = Ice.initialize();
//异步连接,用async和await,在测试中发现不用async和await进行异步连接的话,调用接口时会报错为接口函数未定义。
async function connection1() {
if(isIceDestroy){
isIceDestroy = false;
communicator = Ice.initialize();
}
$('#connect').attr('disabled','');
$('#disconnect').removeAttr('disabled');
var m = new Map();
try {
setState(State.Busy);
const hostname = document.location.hostname || "127.0.0.1";
const proxy = communicator.stringToProxy(`StatusManager:ws -h ${hostname} -p 10000`);
const printer = await Manager.statusManagerPrx.checkedCast(proxy);
//自定义和初始化事件
if (printer) {
await (setInterval(function () {
// 异步操作, 接口调用后返回的是 Promise 对象,需要使用 then函数获取数据,then 函数接受两个参数,第一个是请求成功的处理函数,第二个是请求失败时的处理函数。
printer.getStatusofAllOtherDevices().then(function (result) {
//获取数据并分发
}, function (error) {
alert("[ Getting status error ] : \n\n" + error);
})
}, 1000));
setValue();//监听事件,获取数据并做处理
} else {
alert("Invalid proxy");
}
} catch (ex) {
console.log(ex.toString());
} finally {
setState(State.Idle);
}
}
const State =
{
Idle: 0,
Busy: 1
};
//连接和断开连接按钮的事件绑定,最开始的时候断开连接不使能,连接和断开连接互斥,还有几句相关操作放在连接函数之内。
function setState(newState) {
switch (newState) {
case State.Idle:
$("#connect").click(connect1);
$("#disconnect").click(function(){
if(communicator){
communicator.destroy();
isIceDestroy = true;
}
$("#connect").removeAttr('disabled');
$('#disconnect').attr('disabled','');
});
break;
case State.Busy:
$("#connect").off("click");
$("#disconnect").off("click");
break;
default:break;
}
}
至此,ice 3.7 的 js 体验就告一段落了。这个项目其实不难,就是采集数据并做数据处理。虽然参照了官网手册给的例子(官网例子没有说服务端需要ws配置,同时官网例子是打印字符串而没有获取参数),但中间还是吃了很多苦头,总结为:
虽然项目不大,但是这些苦头吃下来,也花了些日子,但还是收获挺大,值得纪念。
另外,ice3.7 js 的库文件和生成的接口文件中,有 const 和 class 关键字,同时客户端使用了 async 和await 异步操作方式,所以 前端页面 无法适配 IE 浏览器(目前使用的是IE11版本)。
谨此,祝好!