当前位置: 首页 > 工具软件 > Zeroc ICE > 使用案例 >

Zeroc ice3.7 js 初体验

晏望
2023-12-01

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 版本有如下区别:

  1. 3.7版本将所有类放在com.zeroc包下。譬如,原来的Ice.ObjectPrx需要更改为com.zeroc.Ice.ObjectPrx;
  2. 3.7版本不再有#PrxHelper类,checkedCast方法直接在#Prx类下调用(#表示接口名称);
  3. 3.7版本不再使用#holder变量来存放返回值,返回值被以<接口名>.<方法名>Result的类型在调用函数时直接返回。

js版本的ice无法实现它自己的服务端,所以服务端一般需要使用其它语言版本的,如c、c++、python、java等。此处用java。

接口文件(Manager.ice)

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包

服务端-1(statusManagerI.java)

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;
	}
}

服务端-2(Server.java)

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");

客户端部分(connection.js)

  (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配置,同时官网例子是打印字符串而没有获取参数),但中间还是吃了很多苦头,总结为:

  1. 服务端需要用websocket配置
  2. 在看别人的例子时,意外收获 服务端多种配置的方法
  3. 客户端需要异步连接,调用接口函数时返回的是Promise对象,而不直接是获取到的数据,需要调用then 函数才能获取数据(这一步真的花了挺久)
  4. js 的 自定义及分发事件在开始时不怎么熟悉

虽然项目不大,但是这些苦头吃下来,也花了些日子,但还是收获挺大,值得纪念。

另外,ice3.7 js 的库文件和生成的接口文件中,有 const 和 class 关键字,同时客户端使用了 async 和await 异步操作方式,所以 前端页面 无法适配 IE 浏览器(目前使用的是IE11版本)。

谨此,祝好!

 类似资料: