基于Zero-Ice搭建的物联网监控平台

简介: 基于Zero-Ice搭建的物联网远程实时监控平台

[P1] 项目初始态势

开始接手项目时,领导要求很简单,就是做一个本地服务,手机连接上服务,能控制本地系统内的各种设备,至于设备状态如何采集与控制,数据如何分析和存储这里略过,其通信机制类似于下图:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

整个项目,领导只安排了只有我一个项目人员,当然能简单就简单。我将本地数据经过转换汇总,终端采用设备-〉信息点的层级关系显示,当然设备层具有自身属性,信息点层也具有自身属性,终端是瘦客户端,在链接上服务端后,由服务端推送层级结构和相关属性信息给客户端,进行初始化,后续就是实现实时上行推送和下行控制,上行和下行采用独立线程处理。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

一个星期后,安装在项目现场,实现了本地WIFI的手机端远程监控,工程人员和使用人员都觉得OK.

又经历一段时间的功能追加,支持各种类型设备可配置接入,支持蓝牙、串口、网络采集数据,支持实时分析与告警,跨平台部署,自动化调度运维等一系列任务,想来项目应该结题。嗯,领导有了新想法。

[P2]项目变种

采用socket通信,手机端需要设置IP,很麻烦,领导希望工程人员、使用人员只要连上WIFI打开app就能实现远程监控。领导发话,没办法只能照办,为了偷懒,当然采用现成的通信机制改造,最终选型了Zero-ice实现,通信机制类似于:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

我将的ice配置文件如下:

#pragma once
#include <Ice/Identity.ice>

module PCS
{

enum DevTypeICE { UDDev=0,Region, Platform,Entity };
enum PTypeICE { UDPInfo=0,YX, YC, YXS, YCS };

struct DateTimeI {
	int	isec;
	int imsec;
};

struct DateTimeS {
	short year;
	short month;
	short day;
	short hour;
	short minute;
	short second;
	short msec;
};

struct PInfo {
	long		pID;
	string		name;
	string		desc;
	PTypeICE	pType;
	float 		pValue;
};
sequence<PInfo> PInfos;

struct Dev {
	long 		devID;
	DevTypeICE	devType;
	string 		name;
	string		desc;
};
sequence<Dev> Devs;

interface ClientAchieve
{
    void PValueChange(long devID,long pID, DateTimeI itime, float val);
	void addDev(Devs devs);
	void addPInfo(long devID,PInfos pinfos);
};

interface ServerAchieve
{
	void AddClient(::Ice::Identity ident);
	void AddClientID(::Ice::Identity ident,int type);
    void setPValue(long devID, long pID, float val);
};

};
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

至于接口实现代码略过,给出部分服务和客户端的通信连接实现参考:

服务端:

void PCSServer::listen()
{
	CacheDataObj *ptr_CacheDataObj = CacheDataObj::getInstance();
	iceType = ptr_CacheDataObj->getIceType();
	confFile = ptr_CacheDataObj->getIceConfFile();
	try
	{
		Ice::InitializationData initData;
		initData.properties = Ice::createProperties();
#ifdef ICE_STATIC_LIBS
		Ice::registerIceSSL();
#endif
		CLogger::createInstance()->Log(eTipMessage
			,"start load ice config file %s", confFile.c_str());
		initData.properties->load(confFile);
		char ** argv;
		char *p = NULL;
		argv = &p;
		int argc = 0;
		if (iceType > 0) 
		{
			communicator_ = Ice::initialize(argc, argv, initData);
		}
		else {
			communicator_ = this->communicator();
		}
		if (NULL == communicator_) {
			CLogger::createInstance()->Log(eConfigError
				, "communicator initialize fail! [%s %s %d]"
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
	catch (const Ice::Exception& ex)
	{
		CLogger::createInstance()->Log(eSoftError
			, "Ice::Exception[1]:%s [%s %s %d]"
			, ex.ice_id().c_str(), __FILE__, __FUNCTION__, __LINE__);
		disListen();
	}
	catch (const std::string & msg) 
	{
		CLogger::createInstance()->Log(eSoftError
			, "Ice::Exception[2]:%s [%s %s %d]"
			, msg.c_str(), __FILE__, __FUNCTION__, __LINE__);
		disListen();
	}
	catch (const char * msg) 
	{
		CLogger::createInstance()->Log(eSoftError
			, "Ice::Exception[3]:%s [%s %s %d]"
			, msg, __FILE__, __FUNCTION__, __LINE__);
		disListen();
	}
	if (NULL != communicator_) 
	{
		try {
			if (iceType > 0) 
			{
				Ice::ObjectAdapterPtr adapter_pcs = communicator_->createObjectAdapter("SyePcs");
				Ice::Identity id_pcs = Ice::stringToIdentity("SyePcs");
				PCS::ServerAchievePtr pcs_ = new ServerAchieveI(communicator_);
				adapter_pcs->add(pcs_, id_pcs);
				adapter_pcs->activate();
				//fprintf(stderr, "ice server listen!\n");
				CLogger::createInstance()->Log(eTipMessage, "ice server listen!");
				isListen = true;
				communicator_->waitForShutdown();
			}
			else {
				Ice::PropertiesPtr properties = communicator_->getProperties();
				Ice::ObjectAdapterPtr adapter_pcs = communicator_->createObjectAdapter("SyePcs");
				std::string id = communicator_->getProperties()->getPropertyWithDefault("Identity", "PCSIO");
				Ice::Identity id_pcs = Ice::stringToIdentity(id);
				CLogger::createInstance()->Log(eTipMessage
					, "id_pcs.name=%s", id_pcs.name.c_str());
				PCS::ServerAchievePtr pcs_ = new ServerAchieveI(communicator_);
				adapter_pcs->add(pcs_, id_pcs);
				adapter_pcs->activate();
				CLogger::createInstance()->Log(eTipMessage, "ice server listen!");
				isListen = true;
				communicator_->waitForShutdown();
			}
		}
		catch (const Ice::Exception& ex)
		{
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[1]:%s [%s %s %d]"
				, ex.ice_id().c_str(), __FILE__, __FUNCTION__, __LINE__);
			disListen();
		}
		catch (const std::string & msg) 
		{
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[2]:%s [%s %s %d]"
				, msg.c_str(), __FILE__, __FUNCTION__, __LINE__);
			disListen();
		}
		catch (const char * msg) 
		{
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[3]:%s [%s %s %d]"
				, msg, __FILE__, __FUNCTION__, __LINE__);
			disListen();
		}
		catch (...) 
		{
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[4]:unkown error for adapter crate and activate! [%s %s %d]"
				, __FILE__, __FUNCTION__, __LINE__);
			disListen();
		}
	}
	else 
	{
		CLogger::createInstance()->Log(eConfigError
			, "communicator is NULL! [%s %s %d]"
			, __FILE__, __FUNCTION__, __LINE__);
	}
};

void PCSServer::disListen()
{
	if (communicator_)
	{
		try
		{
			isListen = false;
			communicator_->destroy();
		}
		catch (const Ice::Exception& ex)
		{
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception:%s [%s %s %d]"
				, ex.ice_id().c_str()
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
};
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


客户端只给出java的,c++实现类似:

import PCS.*;
import android.annotation.SuppressLint;
import Ice.*;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.UUID;
import java.lang.Thread;

@SuppressLint("NewApi")
public class PcsClient implements Runnable
{
	public PcsClient()
	{
	}
	boolean connectf=false;
	InputStream inputStream =null;
	private Ice.Communicator ic = null;
	private ServerAchievePrx twoway = null;
	private ClientAchieveI pca = null;
	private ObjectAdapter adapter = null;
	private Ice.Identity ident = null;
	private boolean mWorking = false;
	int runType = 1;
	int clientType = 1;
	private Thread mythread = null;
	public void start() { 
		mWorking = true;  
		mythread = new Thread(this);
		mythread.start();
	}
	@Override
	public void run(){ 
		long utime = System.currentTimeMillis();
		while(mWorking){
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				break;
			}
			if(twoway != null&& pca!=null)
			{
				if(System.currentTimeMillis()>(utime+10000))
				{
					//
					if(!pca.getUpdateState())
					{
						disconnect();
						System.out.println("disconnect and  connect again");
						if(!connect())
						{
							System.out.println("connect 2 fail");
							try {
								Thread.sleep(10);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}	
					}
					utime = System.currentTimeMillis();
					//
					pca.setUpdateState(false);	
				}
			}else{
				if(!connect())
				{
					System.out.println("connect 1 fail");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}			
			}
		}
		
	    
	}
	
	public void stop() {      
		mWorking = false;  	    
	    try {    
	    	Thread.sleep(1);
	    	mythread.interrupt();
	        //手动停止    
	        mythread.join();  
	    } catch (InterruptedException e) {  
	        e.printStackTrace();  
	    } 
	    disconnect();	    
	    disCommunicator();
	} 
	public void disCommunicator()
	{
		if (ic != null) {
			try{
				ic.shutdown();
				ic.destroy();
				ic = null;
			}catch (Ice.Exception e) {
				System.out.printf("destroy fail(%s)",e.ice_name());
				e.printStackTrace();
			}
		}		
	}
	public Ice.Communicator getCommunicator()
	{
		System.out.println("getCommunicator");
		if(ic == null){
	        Ice.InitializationData initData = new Ice.InitializationData();
	        System.out.println("InitializationData");
	        initData.properties = Ice.Util.createProperties();
	        System.out.println("createProperties");
	        try
	        {		            
	            Properties properties = new Properties();
	            properties.load(inputStream);
	            for (String name : properties.stringPropertyNames()) {
	                String value = properties.getProperty(name);
	                initData.properties.setProperty(name, value);
	                System.out.printf("name=%s,value=%s\n",name,value);
	            }
	        }
	        catch(IOException ex)
	        {
	            String _error = String.format("Initialization failed %s", ex.toString());
	            System.out.println(_error);
	            try {
					throw ex;
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        }
	        ic = Ice.Util.initialize(initData);
	        System.out.println("initialize");
	        if(ic==null){
	        	System.out.println("invalid Communicator");
	        }
		}
		return ic;
	}
	public boolean connect()
	{
		if(!connectf){
			try {
				twoway = null;
				if(runType>0){
					System.out.println("checkedCast SyePcs.Proxy");
					twoway = ServerAchievePrxHelper.checkedCast(
		        		getCommunicator().propertyToProxy("SyePcs.Proxy").ice_twoway().ice_secure(false));
				}else{
					try{
						System.out.println("checkedCast PCSIO 1");
						twoway = ServerAchievePrxHelper.checkedCast(
								getCommunicator().stringToProxy("PCSIO").ice_twoway().ice_secure(false).ice_timeout(100));		
						System.out.println("checkedCast PCSIO 2");
					}catch(Ice.NotRegisteredException e){
						System.out.println("checkedCast 1 MCSSVCGrid/Query");
						Ice.ObjectPrx proxy = getCommunicator().stringToProxy("MCSSVCGrid/Query");
						IceGrid.QueryPrx query = IceGrid.QueryPrxHelper.checkedCast(proxy);
						twoway = ServerAchievePrxHelper.checkedCast(
								query.findObjectByType("::PCS::PCSIO").ice_twoway().ice_secure(false).ice_timeout(100));
						e.printStackTrace();
						System.out.println("checkedCast 2 MCSSVCGrid/Query");
					}
				}
		        if(twoway != null)
		        {
			        /*ObjectAdapter*/ adapter = getCommunicator().createObjectAdapter("");
			        System.out.println("Communicator create adapter");
			        pca = new ClientAchieveI();
			        /*Ice.Identity*/ ident = getCommunicator().stringToIdentity("ClientAchieve");
			        ident = new Ice.Identity();
			        //System。Guid guid = System。Guid.NewGuid();
			        //ident.name = guid.ToString();
			        UUID uuid = UUID.randomUUID();
			        ident.name = uuid.toString();
			        //ident.name = java.util.UUID.randomUUID();
			        ident.category = "";
			        System.out.println("Communicator get Identity");
			        adapter.add(pca, ident);
			        adapter.activate();
			        System.out.println("activate");
			        twoway.ice_getConnection().setAdapter(adapter);
			        twoway.AddClientID(ident,clientType);
			        System.out.println("AddClient");
			        connectf = true;
			        pca.setUpdateState(true);
		        }else{
		        	System.err.println("invalid proxy,couldn't find a `::PCS::PCSIO' object");
		        	connectf = false;
		        }
			} catch (Ice.Exception e) {
				System.out.println("create Client fail");
				e.printStackTrace();
				connectf = false;
				System.out.println("connectf = false");
			}
		}
		return connectf;
	}
	
	public void disconnect()
	{
		if(pca != null){
			pca = null;
		}
		if(null!=adapter&&null!=ident){
			adapter.remove(ident);
			ident = null;
			adapter.destroy();
		}
		if(twoway != null){
			twoway = null;
		}
		connectf = false;
	}
	
	public void setControl(long devID, long pID, float val){
		if(twoway != null){
			twoway.setPValue(devID, pID, val);
		}
	}
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

由于本地通信不是很饱和,我只将serverPcs设了一个Node,其简化的application.xml配置如下,serverPcs是按需由节点服务icegridnode启动的:

<icegrid>
  <application name="SyeSys">
    <node name="Node01" >
	  <description>测试节点</description>
      <server id="syePcsSrv" 
		exe="PCS_server" 
		pwd="D:\\SYE_MCS_PRO\\pcs_project\\PCS_server\\x64\\PcsSrv"
		ice-version="3.6"
		activation-timeout="60"
		application-distrib="false"
		deactivation-timeout="60"
		activation="on-demand">
        <adapter name="SyePcs" id="SyePcs" endpoints="tcp">
          <object identity="PCSIO" type="::PCS::PCSIO" property="Identity"/>
        </adapter>
      </server>
    </node>
	
  </application>
</icegrid>
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

为了简化与测试,暂时将服务部署本机,后续只要将IP更改即可,并在Host文件将IP与域内自定义站点映射即可,下面以本机地址为例配置了中心服务、节点服务的配置文件,通过节点服务启动serverPcs。

主中心服务配置,一些描述也一并给出,而从中心服务和节点服务只给出配置项:

#
# The IceGrid instance name.
#
IceGrid.InstanceName=MCSSVCGrid #1
Ice.Default.Protocol=tcp
#Ice.Default.Locator=MCSSVCGrid/Locator:default -p 4061 #2
#1 为这个应用实例指定一个唯一的标识
#2  注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到 
#
# IceGrid registry configuration.
#IceGrid 注册表最多创建四组端点,用下面的属性进行配置:
#1)IceGrid.Registry.Client.Endpoints
#支持Ice::Locator IceGrid::Query 的客户端端点。
#2)IceGrid.Registry.Server.Endpoints
#用于对象和对象适配器注册的服务器端端点。
#3)IceGrid.Registry.Admin.Endpoints
#IceGrid::Admin 接口的管理端点( 可选)。
#4)IceGrid.Registry.Internal.Endpoints
#定义IceGrid节点用于与注册表进行通信的内部端点内部接口的端点。这些内部端点必须能被IceGrid节点用于与注册表进行通信的内部端点节点访问。
#
IceGrid.Registry.Client.Endpoints=default -p 4061 	#3
#协议default,其值可通过Ice.Default.Protocol设置,默认是tcp,协议可以设置tcp udp ssll ws wss等 
#-h <ip>指定网址,-p <port> 指定端口, -t <msec> 指定超时毫秒数, 多个Endpoint采用':'间隔
#IceGrid.Registry.Client.Endpoints=default -h 127.0.0.1 -p 4061 	#3
IceGrid.Registry.Server.Endpoints=default 			#4
#IceGrid.Registry.Admin.Endpoints=default  -p 4062
#IcePack.Registry.Admin.Endpoints=default  -p 4062
IceGrid.Registry.Internal.Endpoints=default  		#5
#IceGrid.Registry.ReplicaName=Master	#标识服务名称
#IceGrid.Registry.Data=db\\LMDB_master 				#6
IceGrid.Registry.LMDB.Path=db\\LMDB_master
IceGrid.Registry.DynamicRegistration=1
#IceGrid.Node.CollocateRegistry=1 //定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置,不能有两个节点都配置这个属性只能有一个主Registry配置
   # 3  客户端访问注册服务器的端点信息
   # 4  服务访问注册服务器的端点信息,通常是default
   # 5  内部访问端点信息,通常是default,节点用这个端口和注册服务通信
   # 6  注册服务的数据目录的路径
#
# IceGrid admin clients must use a secure connection to connect to the
# registry or use Glacier2.
#
#IceGrid.Registry.AdminSessionManager.Endpoints=default
IceGrid.Registry.PermissionsVerifier=MCSSVCGrid/NullPermissionsVerifier				#7
#IceGrid.Registry.CryptPasswords=passwords
IceGrid.Registry.AdminPermissionsVerifier=MCSSVCGrid/NullPermissionsVerifier		#8
#IceGrid.Registry.SSLPermissionsVerifier=MCSSVCGrid/NullSSLPermissionsVerifier		#9
#IceGrid.Registry.AdminSSLPermissionsVerifier=MCSSVCGrid/NullSSLPermissionsVerifier	#10
   # 7  设定防火墙安全代理,从而控制客户端访问注册表时可用的权限
   # 8  设定防火墙安全代理,从而控制注册表管理者可用的权限
   # 9  设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制
   # 10  设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制
   
#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB     #11
#IceGrid.SQL.DatabaseType=QSQLITE      #12
#IceGrid.SQL.DatabaseName=register/Registry.db       #13
   # 11  指定Ice对象序列化的机制,如果不设置,默认用Freeze机制
   # 12  指定使用数据库的类型
   #13  指定使用数据库的名称
#

#
#Ice Error andStandard output Set
#
#Ice.StdErr=master/stderr.txt                  #14
#Ice.StdOut= master/stdout.txt    #15
#
   #14  指定标准错误输出文件
   #15  指定标准输出文件

#
# Trace properties.
#
Ice.ProgramName=Master #16
IceGrid.Registry.Trace.Node=2 #17
IceGrid.Registry.Trace.Replica=2 #18
   #16  指定主注册服务的名称
   #17  指定主注册服务跟踪节点信息的级别(0~3),默认为0
   #18  指定主/从热备注册服务的跟踪级别(0~3),默认为0
#
# IceGrid nodeconfiguration.
#
#IceGrid.Node.Name=node_1               #19      
#IceGrid.Node.Endpoints=default         #20
#IceGrid.Node.Data=node_1               #21
#IceGrid.Node.CollocateRegistry=1       #22
#IceGrid.Node.Output=node_1            #23
#IceGrid.Node.RedirectErrToOut=1       #24
   # 19  定义节点的名称,必须唯一
   # 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
   # 21  节点的数据目录的路径
   # 22  定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置
   # 23  节点标准输出信息重定向蹈的目录路径,会自动生成输出文件
   # 24  节点上的服务程序的标准错误重定向到标准输出
   
# Traceproperties.
#
IceGrid.Node.Trace.Activator=1            #25
IceGrid.Node.Trace.Adapter=2             #26
IceGrid.Node.Trace.Server=3              #27
   # 25  激活器跟踪级别,通常有0,1,2,3级,默认是0
   # 26  对象适配器跟踪级别,通常有0,1,2,3级,默认是0
   # 27  服务跟踪级别,通常有0,1,2,3级,默认是0
#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid           #28
IceGridAdmin.Password=mygrid           #29
   # 28  IceGrid管理器登录该应用的用户名
   # 29  IceGrid管理器登录该应用的密码
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


从中心服务配置:

# The IceGrid locator proxy.
#主从注册表之间访问定位器配置
Ice.Default.Locator=MCSSVCGrid/Locator:default -p 4061
#可指定ip
#Ice.Default.Locator=MCSSVCGrid/Locator:default -h 127.0.0.1 -p 4061

# IceGrid registry configuration.
IceGrid.Registry.Client.Endpoints=default -p 14061
#可指定ip
#IceGrid.Registry.Client.Endpoints=default -h 127.0.0.1 -p 14061
IceGrid.Registry.Server.Endpoints=default 
IceGrid.Registry.Internal.Endpoints=default 
IceGrid.Registry.ReplicaName=Slave#指定从注册服务的名称
IceGrid.Registry.LMDB.Path=db/LMDB_slave

# IceGrid admin clients must use a secure connection to connect to the
IceGrid.Registry.PermissionsVerifier=MCSSVCGrid/NullPermissionsVerifier					
IceGrid.Registry.AdminPermissionsVerifier=MCSSVCGrid/NullPermissionsVerifier			

# Trace properties.
Ice.ProgramName=Slave
IceGrid.Registry.Trace.Node=2
IceGrid.Registry.Trace.Replica=2

# Traceproperties.
IceGrid.Node.Trace.Activator=1            

# Dummy usernameand password for icegridadmin.
IceGridAdmin.Username=mygrid           #28
IceGridAdmin.Password=mygrid           #29
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

节点服务的配置:

# The IceGrid locator proxy.
Ice.Default.Locator=MCSSVCGrid/Locator:default -p 4061:default -p 14061

IceGrid.Node.Name=Node01
IceGrid.Node.Endpoints=default
IceGrid.Node.Data=db/node_01
IceGrid.Node.Output=db/node_out_01 

# Trace properties.
Ice.ProgramName=Node
IceGrid.Node.Trace.Replica=2
IceGrid.Node.Trace.Activator=1

#log tracing
Ice.LogFile=iceserv.log
Ice.LogFile.SizeMax=1048576
Ice.PrintStackTraces=2
#Ice.Trace.GC=1
Ice.Trace.Protocol=1
Ice.Trace.Slicing=1
Ice.Trace.Retry=2
Ice.Trace.Network=2
Ice.Trace.Locator=2
#warning
Ice.Warn.Connections=1
Ice.Warn.Datagrams=1
Ice.Warn.Dispatch=1
Ice.Warn.AMICallback=1
#Ice.Warn.Leaks=1

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


配置完成后我们将配置启动脚本,当然也可以通过命令逐个执行,为了便捷,配置数个脚本,以win系统为例:

(1)start_center_server.bat,用于启动主从中心服务

start /b /Min "registry01" icegridregistry --Ice.Config=config.master
start /b /Min "registry02" icegridregistry --Ice.Config=config.slave

(2)start_admin.bat,用于修改更新配置

::如果更改配置,需要重新映射服务,删除数据目录并重新生成或更新,需先启动中心服务,再调用配置服务更新
::start_center_server.bat
icegridadmin --Ice.Config=config.admin -e "application add 'application.xml'"
icegridadmin --Ice.Config=config.admin -e "application update 'application.xml'"

(3)start_server.bat,启动节点服务集,本案例只有一个

cd D:\SYE_MCS_PRO\pcs_project\PCS_server\x64\PcsSrv
start /b /Min "node01" icegridnode --Ice.Config=config.node
cd D:\SYE_MCS_PRO\pcs_project\sye_mcs\mgr

(4)stop_server.bat,关闭服务集使用

taskkill /f /im icegridregistry.exe
taskkill /f /im icegridnode.exe
taskkill /f /im PCS_server.exe

配置完成,先去配置一些服务需要的一些目录,

D:\SYE_MCS_PRO\pcs_project\sye_mcs\mgr\db\LMDB_master,

D:\SYE_MCS_PRO\pcs_project\sye_mcs\mgr\db\LMDB_slave,

D:\SYE_MCS_PRO\pcs_project\PCS_server\x64\PcsSrv\db\node_01,

D:\SYE_MCS_PRO\pcs_project\PCS_server\x64\PcsSrv\db\node_out_01,

我手动配置是为了防止尝试配置测试的就数据信息阻隔目录创建或权限受限,完成目录配置后

,先start_center_server.bat服务,然后启动start_admin.bat(配置有改动时)和start_server.bat。

当服务启动稳定后,serverPcs服务应该是没有启动的,只有客户端连接需求后才会被触发启动。

客户端的ice配置文件config0.client如下:

#
# The IceGrid locator proxy.
#"Ice.Default.Locator"的访问地址与"IceGrid.Registry.Client.Endpoints设置"一致
#
Ice.Default.Locator=MCSSVCGrid/Locator:tcp -h localhost -p 4061:tcp -h localhost -p 14061
#Ice.Default.Locator=MCSSVCGrid/Locator:tcp -h www.syemcs.com -p 4061:tcp -h www.pytest.com -p 14061
#非本地连接,需指定IP
#Ice.Default.Locator=MCSSVCGrid/Locator:tcp -h 192.168.1.102 -p 4061:tcp -h 192.168.1.102 -p 14061
#Ice.Default.Router=MCSSVCGlacier2/router:tcp -h www.syemcs.com -p 4064:ssl -h www.pytest.com -p 4065
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

现在启动测试终端,通过从服务-〉节点服务-〉serverPcs,终端与serverPcs建立了长链接:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

手机终端类似下图

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


服务部署到工程上使用了一段时间,领导开始又不满足了,嗯,想在家里也能远程监控现场设备,顺便来个短信告警、统计报表啥的。好吧,准备升级。

[P3]升级到互联网

嗯,这次在利用Zero-Ice比较熟络了,我设计了通信机制如下:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

我将本地的serverPcs作为客户端,并在阿里云购买了 ECS、数据库等服务,并建立了一个控制中转的门户服务serverMcs来支持各地的serverPcs链接进来,另外建立一个serverDcs来支持互联网终端链接进来,同时将终端升级,将每一个serverPcs推送的数据看作一个区域,即显示格式为区域-〉设备-〉信息点的层级结构。

同样,需要为serverPcs<->serverMcs和app<->serverDcs建立Ice通信接口,其接口文件与本地的终端APP通信类似,

McsInterface.ice:

#pragma once
#include <Ice/Identity.ice>

module MCS
{
//area type for ice communitation
enum AreaTypeICE { UDArea=0,ShowingRoom,SubwayStation };
//virtual device type for ice communitation
enum DevTypeICE { UDDev=0,Region, Platform,Entity };
//piont type for ice communitation
enum PTypeICE { UDPInfo=0,YX, YC, YXS, YCS };
//date time describe by second and millsecond
struct DateTimeI {
	int	isec;
	int imsec;
};
//date time describe by the struct within year mon day hour min second millsecond
struct DateTimeS {
	short year;
	short month;
	short day;
	short hour;
	short minute;
	short second;
	short msec;
};
//ponit desc
struct PInfo {
	long		pID;
	string		name;
	string		desc;
	PTypeICE	pType;
	float 		pValue;
};
sequence<PInfo> PInfos;
dictionary<long, PInfo> PInfoMap;
//device desc
struct Dev {
	long 		devID;
	DevTypeICE	devType;
	string 		name;
	string		desc;
};
sequence<Dev> Devs;
dictionary<long, Dev> DevMap;
//area desc
struct Area
{
	long  areaID;
	AreaTypeICE areaType;
	string name;
	string desc;
};
sequence<Area> Areas;
sequence<long> AreaIDs;
//file comunication format
struct FileBinary
{
	string filename;
	int    startpos;
	int    filesize;
	string filebuf;
	int    buflen;
};
//point desc from server and set point value
struct PValue
{
	long areaID;
	long devID;
	long pID;
	DateTimeI itime;
	float val;
};
//client accomplish it
interface MCSClient
{
	void setPValue(PValue pval);
	int nextFileData(long areaID,out FileBinary filedata);
	bool FileRefresh(long areaID,int fileType,string filename); 
};
//server accomplish it
interface MCSServer
{
	void AddClient(::Ice::Identity ident,int type,AreaIDs areaids);
    void PValueChange(PValue pval);
	//void addArea(Areas areas);
	void addArea(Area area);
	void addDev(long areaID,Devs devs);
	void addPInfo(long areaID,long devID,PInfos pinfos);   
};

};
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


DcsInterface.ice:

#pragma once
#include <Ice/Identity.ice>

module DCS
{
enum AreaTypeICE { UDArea=0,ShowingRoom,SubwayStation };
enum DevTypeICE { UDDev=0,Region, Platform,Entity };
enum PTypeICE { UDPInfo=0,YX, YC, YXS, YCS };

struct DateTimeI {
	int	isec;
	int imsec;
};

struct DateTimeS {
	short year;
	short month;
	short day;
	short hour;
	short minute;
	short second;
	short msec;
};

struct PInfo {
	long		pID;
	string		name;
	string		desc;
	PTypeICE	pType;
	float 		pValue;
};
sequence<PInfo> PInfos;

struct Dev {
	long 		devID;
	DevTypeICE	devType;
	string 		name;
	string		desc;
};
sequence<Dev> Devs;

struct Area {
	long 		areaID;
	AreaTypeICE areaType;
	string 		name;
	string		desc;
};
sequence<Area> Areas;
sequence<long> AreaIDs;

interface ClientAchieve
{
	//for internet
	void PValueChangeI(long areaID,long devID,long pID, DateTimeI itime, float val);
	void addAreaI(Areas devs);
	void addDevI(long areaID,Devs devs);
	void addPInfoI(long areaID,long devID,PInfos pinfos);
};

interface ServerAchieve
{
	//for internet
	void AddClientAreas(::Ice::Identity ident,AreaIDs areaIDList);
    void setPValueI(long areaID,long devID, long pID, float val);
};

};
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

其实现逻辑很简单,就是serverPcs只要重新连接上云端后,推送一次设备-〉信息点整个层级结构信息,然后根据业务需要在变化或定期上送信息点数值和接收下行控制,而对于终端来说,也是瘦客户端,其链接上云端后,先根据其订购和账号权限,获得相应的设备及信息点的初始化推送,在终端建立起区域->设备->信息点的层级显示,后续就是刷新服务端推送数据和下发控制。

通信接口函数的具体实现略过,通信链接实现参考本地(java)即可,下面给出c++客户端通信实现代码示例。

int MCSClientV::Run()
{
	while (!exitflag) 
	{
		if (!m_bConnect)
		{
#ifdef WIN32
			Sleep(1000);
#else
			usleep(1000000);
#endif
			if (connect())
			{
				newConnectEvent();
			}
		}
		else {
			changeUpEvent();
		}
#ifdef WIN32
		Sleep(10);
#else
		usleep(10000);
#endif
	}
	return 0;
}

void MCSClientV::setPValue(const ::MCS::PValue &pval)
{
	if (areaID != pval.areaID) 
	{
		return;
	}
	unsigned long taskID = ptr_ServiceChain->getTaskIDFromDateTime();
	PFrom _pfrom;
	if (ptr_CacheDataObj->getFromInfo(static_cast<unsigned long long>(pval.devID)
		, static_cast<unsigned int>(pval.pID), _pfrom))
	{
		float _val = pval.val;
		ptr_CacheDataObj->getCValue(static_cast<unsigned long long>(pval.devID)
			, static_cast<unsigned int>(pval.pID), _val);
		WDS wd(_pfrom.ipLong, OnSet, _pfrom.pID, _pfrom.pType, _val, 0, "ICE_Control_MCS", taskID);
		ptr_ReceiveData->addWDS(wd);

		CLogger::createInstance()->Log(eControlMessage
			, "TaskID[%lu] and down_node[1] setPValue from ICE MCS,time(%s)"
			",devID(%ld),pID(%ld),val(%.3f)"
			",down_control_map, ip[%s],pID(%d),pType(%d),val(%.3f)"
			, taskID
			, PFunc::getCurrentTime().c_str()
			, pval.devID, pval.pID, pval.val
			, _pfrom.ipStr.c_str()
			, _pfrom.pID, static_cast<int>(_pfrom.pType), _val);
		//
		VerificationCache vit;
		vit.execTime = PFunc::getCurrentTime("%04d%02d%02dT%02d%02d%02dZ");
		vit.taskID = taskID;
		vit.taskDesc = "ICE_Control_MCS";
		vit.devID = static_cast<unsigned long>(pval.devID);
		vit.devDesc = _pfrom.devDesc;
		vit.pID = static_cast<unsigned long>(pval.pID);
		vit.pDesc = _pfrom.pDesc;
		vit.pType = static_cast<unsigned int>(_pfrom.pType);
		vit.val = pval.val;
		vit.limitTimeForCheck = static_cast<unsigned int>(time(NULL)) + 5;
		vit.eway_ = _pfrom.eway;
		ptr_VerificationForControlCache->addVerifyData(vit);
	}
	else {
		PValueRet pret(pval.val);
		ptr_CacheDataObj->setValue(static_cast<unsigned long long>(pval.devID)
			, static_cast<unsigned int>(pval.pID), pret);
		CLogger::createInstance()->Log(eControlMessage
			, "TaskID[%lu] and down_node[1] setPValue from ICE MCS and down_node[0],time(%s)"
			",devID(%ld),pID(%ld),val(%.3f)"
			",ditect set val to virtual ponit control"
			, taskID, PFunc::getCurrentTime().c_str()
			, pval.devID, pval.pID, pret.val_actual);
	}
}

bool MCSClientV::FileRefresh(::Ice::Long areaID, ::Ice::Int filetype, const ::std::string &filename)
{
	return false;
}

::Ice::Int MCSClientV::nextFileData(::Ice::Long areaID, ::MCS::FileBinary &fdata)
{
	return 0;
}

Ice::CommunicatorPtr MCSClientV::communicator()
{
	fprintf(stderr, "MCSClientV::communicator()\n");
	if (m_ic == NULL) 
	{
		char ** argv;
		char *p = NULL;
		argv = &p;
		int argc = 0;
		Ice::InitializationData initData;
		initData.properties = Ice::createProperties();
#ifdef ICE_STATIC_LIBS
		Ice::registerIceSSL();
#endif
		//fprintf(stderr, "load %s start\n", confFile.c_str());
		CLogger::createInstance()->Log(eTipMessage
			, "load %s start"
			, confFile.c_str());
		initData.properties->load(confFile);
		m_ic = Ice::initialize(argc, argv, initData);
	}
	return m_ic;
};

bool MCSClientV::connect()
{
	if (!m_bConnect)
	{
		try {
			fprintf(stderr, "MCS::MCSServerPrx::checkedCast\n");
			if (runType>0) 
			{
				soneway = MCS::MCSServerPrx::checkedCast(
					communicator()->propertyToProxy("SyeMcs.Proxy")->ice_twoway()->ice_secure(true));
			}
			else {
				try
				{
					fprintf(stderr, "checkedCast MCSIO\n");
					soneway = MCS::MCSServerPrx::checkedCast(
						communicator()->stringToProxy("MCSIO")->ice_twoway()->ice_secure(false));
				}
				catch (const Ice::NotRegisteredException&)
				{
					fprintf(stderr, "checkedCast MCSLGrid/Query\n");
					IceGrid::QueryPrx query = IceGrid::QueryPrx::checkedCast(communicator()->stringToProxy("MCSLGrid/Query"));
					soneway = MCS::MCSServerPrx::checkedCast(
						query->findObjectByType("::MCS::MCSIO")->ice_twoway()->ice_secure(false));
				}
			}
			if (!soneway)
			{
				std::cerr <<"couldn't find a `SyeMcs.Proxy' object." << std::endl;
			}
			else {
				std::cerr <<"find a `SyeMcs.Proxy' object." << std::endl;
				//MCS::MCSServerPrx oneway = twoway->ice_oneway();
				//MCS::MCSServerPrx batchOneway = twoway->ice_batchOneway();
				//MCS::MCSServerPrx datagram = twoway->ice_datagram();
				//MCS::MCSServerPrx batchDatagram = twoway->ice_batchDatagram();
				Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("");
				Ice::Identity ident;
				ident.name = IceUtil::generateUUID();
				m_strUUID = ident.name;
				ident.category = "";
				MCS::MCSClientPtr crtwoway = new MCSClientI(this);
				adapter->add(crtwoway, ident);
				adapter->activate();
				soneway->ice_getConnection()->setAdapter(adapter);
				::MCS::AreaIDs aids;
				aids.push_back(areaID);
				//flag client-type client-area-ids-map
				soneway->AddClient(ident,(int)1, aids);
				m_bConnect = true;
			}
		}
		catch (const Ice::Exception& ex)
		{
			//fprintf(stderr, "%s\n", ex.ice_id().c_str());
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[1]:%s, [%s %s %d]"
				, ex.ice_id().c_str()
				, __FILE__, __FUNCTION__, __LINE__);
		}
		catch (const std::string & msg) {
			//fprintf(stderr, "%s\n", msg.c_str());
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[2]:%s, [%s %s %d]"
				, msg.c_str()
				, __FILE__, __FUNCTION__, __LINE__);
		}
		catch (const char * msg) {
			//fprintf(stderr, "%s\n", msg);
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception[3]:%s, [%s %s %d]"
				, msg
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
	return m_bConnect;
};

void MCSClientV::disconnect()
{
	if (m_bConnect) 
	{
		m_bConnect = false;
	}
	if (NULL!=m_ic)
	{
		try
		{
			m_ic->destroy();
			m_ic = NULL;
		}
		catch (const Ice::Exception& ex)
		{
			//fprintf(stderr, "%s\n", ex.ice_id().c_str());
			CLogger::createInstance()->Log(eSoftError
				, "Ice::Exception:%s, [%s %s %d]"
				, ex.ice_id().c_str()
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
}

void MCSClientV::newConnectEvent()
{
	::MCS::Devs _devs;
	if (ptr_CacheDataObj->getDevsToSrv(_devs))
	{
		try {
			//::MCS::Areas areas;
			::MCS::Area area;
			area.areaID = areaID;
			area.areaType = (MCS::AreaTypeICE)areaType;
			area.name = areaName;
			area.desc = areaDesc;
			soneway->addArea(area);
			//
			soneway->addDev(areaID,_devs);
			for (::MCS::Devs::const_iterator itdev = _devs.begin(); itdev != _devs.end(); ++itdev)
			{
				::MCS::PInfos _pinfos;
				if (ptr_CacheDataObj->getPInfosToSrv(itdev->devID, _pinfos))
				{
					soneway->addPInfo(area.areaID,itdev->devID, _pinfos);
				}
			}
		}
		catch (...) 
		{
			//printf("addDev or addPInfo Error:%d\n", static_cast<int>(time(NULL)));
			CLogger::createInstance()->Log(eSoftError
				, "addDev or addPInfo Error:%d, [%s %s %d]"
				, static_cast<int>(time(NULL))
				, __FILE__, __FUNCTION__, __LINE__);
			disconnect();
#ifdef WIN32
			Sleep(1000);
#else
			usleep(1000000);
#endif
		}
	}
}

void MCSClientV::changeUpEvent()
{
	WDC wdls;
	//
	if (ptr_ReceiveData->getFirstWDLS(wdls))
	{
		::MCS::DateTimeI _itime;
		_itime.isec = wdls.evtTimeS;
		_itime.imsec = wdls.evtTimeMS;
		try
		{
			//std::cerr << " PValueChange:" << wdlc.devID << "," << wdlc.pID 
			//	<< "," << wdlc.val << "," << _itime.isec << "," << _itime.imsec << std::endl;
			::MCS::PValue pval;
			pval.areaID = areaID;
			pval.devID = wdls.devID;
			pval.pID = wdls.pID;
			pval.itime = _itime;
			pval.val = wdls.val;
			soneway->PValueChange(pval);
		}
		catch (...)
		{
			CLogger::createInstance()->Log(eTipMessage
				, "PValueChange Error:%d [%s,%s,%d]"
				, static_cast<int>(time(NULL))
				, __FILE__, __FUNCTION__, __LINE__);
			disconnect();
#ifdef WIN32
			Sleep(1000);
#else
			usleep(1000000);
#endif
		}

		if (!ptr_ReceiveData->removeFirstWDLS())
		{
			CLogger::createInstance()->Log(eTipMessage
				, "removeFirstWDLS Error[%s,%s,%d]"
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
}
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

下面给出Zero-Ice云端服务的各个配置信息,其实很类似。

application.xml的简要配置:

<icegrid>
  <application name="SyeMSys">
	<server-template id="syeMcsSrv">
      <parameter name="index"/>
      <server id="syeMcsSrv-${index}" 
		exe="MCS_server" 
		pwd="D:\\SYE_MCS_PRO\\pcs_project\\MCS_server\\x64\\McsSrv"
		ice-version="3.6"
		activation-timeout="60"
		application-distrib="false"
		deactivation-timeout="60"
		activation="on-demand">
        <adapter name="SyeMcs" id="SyeMcs-${index}" endpoints="tcp" replica-group="SyeMcsRe"/>
        <property name="Identity" value="MCSIO"/>
      </server>
    </server-template>
	<replica-group id="SyeMcsRe">
      <load-balancing type="random" n-replicas="2"/>
      <object identity="MCSIO" type="::MCS::MCSIO"/>
    </replica-group>
	<node name="Node21">
	  <description>本地系统门户服务01</description>
      <server-instance template="syeMcsSrv" index="1"/>
      <!--server-instance template="syeMcsSrv" index="2"/-->
    </node>
    <node name="Node22">
	  <description>本地系统门户服务02</description>
      <server-instance template="syeMcsSrv" index="3"/>
      <!--server-instance template="syeMcsSrv" index="4"/-->
    </node>
	
	<server-template id="syeDcsSrv">
      <parameter name="index"/>
      <server id="syeDcsSrv-${index}" 
		exe="DCS_server" 
		pwd="D:\\SYE_MCS_PRO\\pcs_project\\DCS_server\\x64\\DcsSrv"
		ice-version="3.6"
		activation-timeout="60"
		application-distrib="false"
		deactivation-timeout="60"
		activation="on-demand">
        <adapter name="SyeDcs" id="SyeDcs-${index}" endpoints="tcp" replica-group="SyeDcsRe"/>
        <property name="Identity" value="DCSIO"/>
      </server>
    </server-template>
	<replica-group id="SyeDcsRe">
      <load-balancing type="random" n-replicas="2"/>
      <object identity="DCSIO" type="::DCS::DCSIO"/>
    </replica-group>
	<node name="Node11">
	  <description>终端控制门户服务01</description>
      <server-instance template="syeDcsSrv" index="1"/>
    </node>
    <node name="Node12">
	  <description>终端控制门户服务02</description>
      <server-instance template="syeDcsSrv" index="3"/>
    </node>
  </application>
</icegrid>
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

云端的主从中心服务的配置,测试时以本地为例,

config.master:

#
# The IceGrid instance name.
#
IceGrid.InstanceName=MCSLGrid #1
Ice.Default.Protocol=tcp
#Ice.Default.Locator=MCSLGrid/Locator:default -p 5061 #2
   #1 为这个应用实例指定一个唯一的标识
   #2  注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到 
#
# IceGrid registry configuration.
#IceGrid 注册表最多创建四组端点,用下面的属性进行配置:
#1)IceGrid.Registry.Client.Endpoints
#支持Ice::Locator IceGrid::Query 的客户端端点。
#2)IceGrid.Registry.Server.Endpoints
#用于对象和对象适配器注册的服务器端端点。
#3)IceGrid.Registry.Admin.Endpoints
#IceGrid::Admin 接口的管理端点( 可选)。
#4)IceGrid.Registry.Internal.Endpoints
#定义IceGrid节点用于与注册表进行通信的内部端点内部接口的端点。这些内部端点必须能被IceGrid节点用于与注册表进行通信的内部端点节点访问。
#
IceGrid.Registry.Client.Endpoints=default -p 5061 	#3
#协议default,其值可通过Ice.Default.Protocol设置,默认是tcp,协议可以设置tcp udp ssll ws wss等 
#-h <ip>指定网址,-p <port> 指定端口, -t <msec> 指定超时毫秒数, 多个Endpoint采用':'间隔
#IceGrid.Registry.Client.Endpoints=default -h 127.0.0.1 -p 5061 	#3
IceGrid.Registry.Server.Endpoints=default 			#4
#IceGrid.Registry.Admin.Endpoints=default  -p 5062
#IcePack.Registry.Admin.Endpoints=default  -p 5062
IceGrid.Registry.Internal.Endpoints=default  		#5
#IceGrid.Registry.ReplicaName=Master	#标识服务名称
#IceGrid.Registry.Data=db\\LMDB_master 				#6
IceGrid.Registry.LMDB.Path=db\\LMDB_master
IceGrid.Registry.DynamicRegistration=1
#IceGrid.Node.CollocateRegistry=1 //定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置,不能有两个节点都配置这个属性只能有一个主Registry配置
   # 3  客户端访问注册服务器的端点信息
   # 4  服务访问注册服务器的端点信息,通常是default
   # 5  内部访问端点信息,通常是default,节点用这个端口和注册服务通信
   # 6  注册服务的数据目录的路径
#
# IceGrid admin clients must use a secure connection to connect to the
# registry or use Glacier2.
#
#IceGrid.Registry.AdminSessionManager.Endpoints=default
IceGrid.Registry.PermissionsVerifier=MCSLGrid/NullPermissionsVerifier				#7
#IceGrid.Registry.CryptPasswords=passwords
IceGrid.Registry.AdminPermissionsVerifier=MCSLGrid/NullPermissionsVerifier		#8
#IceGrid.Registry.SSLPermissionsVerifier=MCSLGrid/NullSSLPermissionsVerifier		#9
#IceGrid.Registry.AdminSSLPermissionsVerifier=MCSLGrid/NullSSLPermissionsVerifier	#10
   # 7  设定防火墙安全代理,从而控制客户端访问注册表时可用的权限
   # 8  设定防火墙安全代理,从而控制注册表管理者可用的权限
   # 9  设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制
   # 10  设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制
   
#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB     #11
#IceGrid.SQL.DatabaseType=QSQLITE      #12
#IceGrid.SQL.DatabaseName=register/Registry.db       #13
   # 11  指定Ice对象序列化的机制,如果不设置,默认用Freeze机制
   # 12  指定使用数据库的类型
   #13  指定使用数据库的名称
#

#
#Ice Error andStandard output Set
#
#Ice.StdErr=master/stderr.txt                  #14
#Ice.StdOut= master/stdout.txt    #15
#
   #14  指定标准错误输出文件
   #15  指定标准输出文件

#
# Trace properties.
#
Ice.ProgramName=Master #16
IceGrid.Registry.Trace.Node=2 #17
IceGrid.Registry.Trace.Replica=2 #18
   #16  指定主注册服务的名称
   #17  指定主注册服务跟踪节点信息的级别(0~3),默认为0
   #18  指定主/从热备注册服务的跟踪级别(0~3),默认为0
#
# IceGrid nodeconfiguration.
#
#IceGrid.Node.Name=node_1               #19      
#IceGrid.Node.Endpoints=default         #20
#IceGrid.Node.Data=node_1               #21
#IceGrid.Node.CollocateRegistry=1       #22
#IceGrid.Node.Output=node_1            #23
#IceGrid.Node.RedirectErrToOut=1       #24
   # 19  定义节点的名称,必须唯一
   # 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
   # 21  节点的数据目录的路径
   # 22  定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置
   # 23  节点标准输出信息重定向蹈的目录路径,会自动生成输出文件
   # 24  节点上的服务程序的标准错误重定向到标准输出
   
# Traceproperties.
#
IceGrid.Node.Trace.Activator=1            #25
IceGrid.Node.Trace.Adapter=2             #26
IceGrid.Node.Trace.Server=3              #27
   # 25  激活器跟踪级别,通常有0,1,2,3级,默认是0
   # 26  对象适配器跟踪级别,通常有0,1,2,3级,默认是0
   # 27  服务跟踪级别,通常有0,1,2,3级,默认是0
#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid           #28
IceGridAdmin.Password=mygrid           #29
   # 28  IceGrid管理器登录该应用的用户名
   # 29  IceGrid管理器登录该应用的密码
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

从服务的config.slave:

#
# The IceGrid locator proxy.
#主从注册表之间访问定位器配置
#
Ice.Default.Locator=MCSLGrid/Locator:default -p 5061
#可指定ip
#Ice.Default.Locator=MCSLGrid/Locator:default -h 192.168.1.102 -p 5061
#
# The IceGrid instance name.
#
#IceGrid.InstanceName=MCSLGrid

#
# IceGrid registry configuration.
#
IceGrid.Registry.Client.Endpoints=default -p 15061
#可指定ip
#IceGrid.Registry.Client.Endpoints=default -h 127.0.0.1 -p 15061
IceGrid.Registry.Server.Endpoints=default 
IceGrid.Registry.Internal.Endpoints=default 
#IceGrid.Registry.Data=db/LMDB_slave
IceGrid.Registry.ReplicaName=Slave#指定从注册服务的名称
IceGrid.Registry.LMDB.Path=db/LMDB_slave
#
# IceGrid admin clients must use a secure connection to connect to the
# registry or use Glacier2.
#
#IceGrid.Registry.AdminSessionManager.Endpoints=default
IceGrid.Registry.PermissionsVerifier=MCSLGrid/NullPermissionsVerifier					#7
IceGrid.Registry.AdminPermissionsVerifier=MCSLGrid/NullPermissionsVerifier			#8
#IceGrid.Registry.SSLPermissionsVerifier=MCSLGrid/NullSSLPermissionsVerifier			#9
#IceGrid.Registry.AdminSSLPermissionsVerifier=MCSLGrid/NullSSLPermissionsVerifier    	#10

#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB     	#11
#IceGrid.SQL.DatabaseType=QSQLITE      			#12
#IceGrid.SQL.DatabaseName=register/Registry.db  #13
#

#
#Ice Error andStandard output Set
#
#Ice.StdErr=slave_1/stderr.txt                 	#14
#Ice.StdOut=slave_1/stdout.txt     				#15

#
# Trace properties.
#
Ice.ProgramName=Slave
IceGrid.Registry.Trace.Node=2
IceGrid.Registry.Trace.Replica=2

#
# IceGrid nodeconfiguration.
#
#IceGrid.Node.Name=node_2               #19      
#IceGrid.Node.Endpoints=default         #20
#IceGrid.Node.Data=node_2               #21
#IceGrid.Node.CollocateRegistry=1       #22
#IceGrid.Node.Output=node_2             #23
#IceGrid.Node.RedirectErrToOut=1        #24

# Traceproperties.
#
IceGrid.Node.Trace.Activator=1            #25
#IceGrid.Node.Trace.Adapter=2             #26
#IceGrid.Node.Trace.Server=3              #27

#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid           #28
IceGridAdmin.Password=mygrid           #29
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

serverMcs的配置config01.node(config02.node):

#
# The IceGrid locator proxy.
#
Ice.Default.Locator=MCSLGrid/Locator:default -p 5061:default -p 15061
#不是本地节点,需指定ip
#Ice.Default.Locator=MCSLGrid/Locator:default -h 127.0.0.1 -p 5061:default -h 127.0.0.1 -p 15061
#
# IceGrid node configuration.
#"IceGrid.Node.Endpoints"的访问地址与"IceGrid.Registry.Internal.Endpoints=tcp -h localhost"一致
#
IceGrid.Node.Name=Node21
IceGrid.Node.Endpoints=default
#IceGrid.Node.Endpoints=default -h 127.0.0.1
IceGrid.Node.Data=db/node_21
IceGrid.Node.Output=db/node_out_21
#IceGrid.Node.RedirectErrToOut=1
#IceGrid.Node.Name = 172.16.14.165 //服务器地址  

#
# Trace properties.
#
Ice.ProgramName=Node
IceGrid.Node.Trace.Replica=2
IceGrid.Node.Trace.Activator=1

#log tracing
Ice.LogFile=iceserv.log
Ice.LogFile.SizeMax=1048576
Ice.PrintStackTraces=2
#Ice.Trace.GC=1
Ice.Trace.Protocol=1
Ice.Trace.Slicing=1
Ice.Trace.Retry=2
Ice.Trace.Network=2
Ice.Trace.Locator=2
#warning
Ice.Warn.Connections=1
Ice.Warn.Datagrams=1
Ice.Warn.Dispatch=1
Ice.Warn.AMICallback=1
#Ice.Warn.Leaks=1

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

serverDcs的config01.node(config02.node类似):

#
# The IceGrid locator proxy.
#
Ice.Default.Locator=MCSLGrid/Locator:default -p 5061:default -p 15061
#不是本地节点,需指定ip
#Ice.Default.Locator=MCSLGrid/Locator:default -h 127.0.0.1 -p 5061:default -h 127.0.0.1 -p 15061
#
# IceGrid node configuration.
#"IceGrid.Node.Endpoints"的访问地址与"IceGrid.Registry.Internal.Endpoints=tcp -h localhost"一致
#
IceGrid.Node.Name=Node11
IceGrid.Node.Endpoints=default
#IceGrid.Node.Endpoints=default -h 127.0.0.1
IceGrid.Node.Data=db/node_11
IceGrid.Node.Output=db/node_out_11
#IceGrid.Node.RedirectErrToOut=1
#IceGrid.Node.Name = 172.16.14.165 //服务器地址  

#
# Trace properties.
#
Ice.ProgramName=Node
IceGrid.Node.Trace.Replica=2
IceGrid.Node.Trace.Activator=1

#log tracing
Ice.LogFile=iceserv.log
Ice.LogFile.SizeMax=1048576
Ice.PrintStackTraces=2
#Ice.Trace.GC=1
Ice.Trace.Protocol=1
Ice.Trace.Slicing=1
Ice.Trace.Retry=2
Ice.Trace.Network=2
Ice.Trace.Locator=2
#warning
Ice.Warn.Connections=1
Ice.Warn.Datagrams=1
Ice.Warn.Dispatch=1
Ice.Warn.AMICallback=1
#Ice.Warn.Leaks=1

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

配置完成后我们将配置启动脚本,有了本地配置的经验,我同样配置数个脚本,以win系统为例:

(1)start_center_server.bat,用于启动主从中心服务

start /b /MIN "registry11" icegridregistry --Ice.Config=config.master 
start /b /MIN "registry12" icegridregistry --Ice.Config=config.slave

(2)start_admin.bat,用于修改更新配置

::如果更改配置,需要重新映射服务,删除数据目录并重新生成或更新,需先启动中心服务,再调用配置服务更新
::start_center_server.bat

icegridadmin --Ice.Config=config.admin -e "application add 'application.xml'"
icegridadmin --Ice.Config=config.admin -e "application update 'application.xml'"

(3)start_server.bat,启动节点服务集,本案例serverMcs和serverDcs有两个节点服务

cd D:\\SYE_MCS_PRO\\pcs_project\\MCS_server\\x64\\McsSrv
start /b /MIN "node11" icegridnode --Ice.Config=config01.node 
start /b /MIN "node12" icegridnode --Ice.Config=config02.node 
cd D:\\SYE_MCS_PRO\\pcs_project\\DCS_server\\x64\\DcsSrv
start /b /MIN "node21" icegridnode --Ice.Config=config01.node 
start /b /MIN "node22" icegridnode --Ice.Config=config02.node 
cd D:\\SYE_MCS_PRO\\pcs_project\\sye_mcs\\mgrs

(4)stop_server.bat,关闭服务集使用

taskkill /f /im icegridregistry.exe
taskkill /f /im icegridnode.exe
taskkill /f /im glacier2router.exe
taskkill /f /im MCS_server.exe
taskkill /f /im DCS_server.exe

配置完成,先去配置一些服务需要的一些目录,以本地win服务为例,

D:\SYE_MCS_PRO\pcs_project\sye_mcs\mgrs\db\LMDB_master,

D:\SYE_MCS_PRO\pcs_project\sye_mcs\mgrs\db\LMDB_slave,

D:\SYE_MCS_PRO\pcs_project\MCS_server\x64\McsSrv\db\node_21,

D:\SYE_MCS_PRO\pcs_project\MCS_server\x64\McsSrv\db\node_out_21,

D:\SYE_MCS_PRO\pcs_project\DCS_server\x64\DcsSrv\db\node_12,

D:\SYE_MCS_PRO\pcs_project\DCS_server\x64\DcsSrv\db\node_out_12

完成目录配置后

,先start_center_server.bat服务,然后启动start_admin.bat(配置有改动时)和start_server.bat。

当服务启动稳定后,serverPcs服务应该是没有启动的,只有客户端连接需求后才会被触发启动。

serverPcs作为客户端与serverMcs通信,终端app与serverDcs 通信,由于他们的注册主从服务一致,它们的ice配置文件config0.client如下:

#
# The IceGrid locator proxy.
#"Ice.Default.Locator"的访问地址与"IceGrid.Registry.Client.Endpoints设置"一致
#
Ice.Default.Locator=MCSLGrid/Locator:tcp -h localhost -p 5061:tcp -h localhost -p 15061
#Ice.Default.Locator=MCSLGrid/Locator:tcp -h www.syemcs.com -p 5061:tcp -h www.pytest.com -p 15061
#非本地连接,需指定IP
#Ice.Default.Locator=MCSSVCGrid/Locator:tcp -h 192.168.1.102 -p 4061:tcp -h 192.168.1.102 -p 14061
#Ice.Default.Router=MCSSVCGlacier2/router:tcp -h www.syemcs.com -p 4064:ssl -h www.pytest.com -p 4065
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

现在启动测试样例,先启动本地服务集群的脚本(start_center_server.bat,start_admin.bat(配置有改动时),start_server.bat),再启动云端服务集群的脚本(start_center_server.bat,start_admin.bat(配置有改动时),start_server.bat),然后启动终端app测试,展示类似,只多了一级区域:

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

样例走通后,进行linux编译,然后部署在阿里云的ECS上,进行一些优化和调整,重新设计终端UI,撰写维护使用手册,开通给使用人员。嗯,现在每个被授权人可以通过外网通信实现对现场设备的实时监控。

可是项目还没有完结,领导又有新构想了,远程升级、日志备份云端和远程查阅、语音控制、视频发布等等,估计又要追加一堆微服务了。

嘿,没问题,就是能不能招人或找外包,或加点项目预算啥的。

项目开发还在路上,感觉坑越来越深了。

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
相关文章
|
7月前
|
存储 运维 监控
物联网平台常见类别及对应平台(一)
物联网平台常见类别及对应平台(一)
499 0
|
消息中间件 监控 数据可视化
一个基于.Net Core 开源的物联网基础平台
一个基于 .Net 6.0 使用C#语言编写的以实现可见与不可见的物理设备数字孪生的物联网平台。用于数据的收集、处理、可视化、设备管理、设备预警、报警的平台。
409 0
一个基于.Net Core 开源的物联网基础平台
|
5天前
|
人工智能 监控 安全
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
14 3
|
1月前
|
存储 监控 安全
Java基于物联网技术的智慧工地云管理平台源码 依托丰富的设备接口标准库,快速接入工地现场各类型设备
围绕施工安全、质量管理主线,通过物联感知设备全周期、全覆盖实时监测,将管理动作前置,实现从事后被动补救到事前主动预防的转变。例如塔吊运行监测,超重预警,升降机、高支模等机械设备危险监控等,通过安全关键指标设定,全面掌握现场安全情况,防患于未然。
147 5
|
7月前
|
存储 机器学习/深度学习 监控
物联网平台常见类别及对应平台(二)
物联网平台常见类别及对应平台(二)
253 0
|
2月前
|
监控 物联网 大数据
智慧工地管理平台系统源码基于物联网、云计算、大数据等技术
智慧工地平台APP通过对施工过程人机料法环的全面感知、互联互通、智能协同,提高施工现场的生产效率、管理水平和决策能力,实现施工管理的数字化、智能化、精益化。
51 0
|
4月前
|
存储 IDE 物联网
物联网生活平台使用8266远程控制的操作实例
物联网生活平台使用8266远程控制的操作实例
115 0
|
4月前
|
数据采集 监控 物联网
物联网时代的电脑行为监控软件:代码实现与设备连接
随着物联网技术的飞速发展,电脑行为监控软件在日常生活和商业领域中变得愈发重要。这种软件通过对电脑用户行为的监测,提供了有益的数据,有助于改善用户体验、增强安全性,甚至在一些场景中实现自动化操作。本文将探讨物联网时代的电脑行为监控软件的代码实现与设备连接,并重点介绍监控到的数据如何自动提交到网站。
265 0
|
4月前
|
机器学习/深度学习 人工智能 物联网
物联网的数据处理平台有哪些
物联网的数据处理平台有哪些
|
10天前
|
人工智能 监控 数据可视化
Springcloud可视化物联网智慧工地云SaaS平台源码 支持二开和私有化部署
Springcloud可视化物联网智慧工地云SaaS平台源码 支持二开和私有化部署
87 0

相关产品

  • 物联网平台