一、关于IIOP.NET
IIOP.NET是一个.NET远程通道,它基于IIOP协议,IIOP协议已经被CORBA标准化组织制定。IIOP.NET扮演了ORB(object request broker)的角色。它把.NET的数据类型转换为CORBA的数据类型。
图1 一个典型分布式系统概况图
IIOP.NET是通过使用基于corba的IIOP支持.NET、javaEE和corba组件实现无缝互操作的技术。如图1所示,这种解决方案依赖于.NET Remoting体系结构的可扩展性,以提供透明的对象级的集成,同时不会导致网关或基于SOAP产品引起的性能上的开销。
现今基于.net开发corba应用程序的工具主要有:janeva,IIOP.NET, Remoting.Corba。其中,janeva是Borland公司发布的一个新产品,但其缺点是不开源,并且收费;Remoting.Corba是一个开源的项目,但由于处于初始开发阶段,许多功能尚不具备,比如编译IDL文件,某些corba类型参数也不支持;IIOP.NET 也是一个开源的开发项目,相关的功能也已经成熟,其优势主要体现在:
(1) 性能。IIOP比SOAP更轻量级,更有效;
(2) .NET Remoting通道像它连接的对象一样共享相同的进程,而且既不需要分开的网关,也不需要另外的间接层;
(3) 可靠性。IIOP定义了至多一次调用的语法规则,确保方法调用只处理一次;
(4) 可用性。IIOP.NET提供了灵活强大的CORBA模型,被集成在直观的.NET Remoting中。
二、 IIOP.NET技术集成解决方案
1、定义daqSerive.idl中间件接口文件
// **********************************************************************
//
// Copyright (c) 2013
// 2013.03.13
// liuxuezong, 上海
//
// All Rights Reserved
//
// **********************************************************************
#ifndefdaqns_idl
#definedaqns_idl
//
// version 1.0.0
//
moduledaqns
{
//模拟量属性
structAnalogProperty
{
floatValue; // 值
string Description; // 描述
};
//数字量属性
structDigitalProperty
{
octet Value; // 值
string Description; // 描述
};
//事件属性
structEventProperty
{
string groupcode; //组代码
shortappsysid; // 应用系统
string devicecode; //设备编码
longstamptime; //时标
string message; // 消息内容
};
typedefsequence<AnalogProperty>AnalogPropertySeq;
typedefsequence<DigitalProperty>DigitalPropertySeq;
typedefsequence<EventProperty>EventPropertySeq;
interface DaqService
{
longIsHaveEvent();
AnalogPropertySeq GetAnalogProperty(in string GroupCode,in string DeviceCode);
DigitalPropertySeq GetDigitalProperty(in string GroupCode, in string DeviceCode);
EventPropertySeq GetEventProperty(in octet nMaxNum);
};
};
#endif
//
// EOF DaqService.idl
//
2、服务端实现
本文使用orbacus4.1.2环境构建,详细过程参考<<基于ORBACUS4.1.2编程技术应用说明>>。
3. 建立IIOP.NET开发环境
(1)IIOP.NET下载地址:http://iiop-net.sourceforge.net/index.html;从官方网站上下载项目的源文件并编译,生成相应的dll文件,供程序引用。这里会使用到IIOPChannel.dll,以及IDLToCLSCompiler.exe两个文件。
(2)编译IDL文件。执行命令IDLToCLSCompiler daqservice daqservice.idl ;命令执行完后,会生成daqservice.dll文件,里面为idl文件定义的一些接口。
Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。
C:\Windows\system32>cd E:\IIOPNet.src.1.9.3\IDLToCLSCompiler\IDLCompiler\bin\Deb
ug
C:\Windows\system32>e:
E:\IIOPNet.src.1.9.3\IDLToCLSCompiler\IDLCompiler\bin\Debug>IDLToCLSCompiler daq
service daqservice.idl
processing file: E:\IIOPNet.src.1.9.3\IDLToCLSCompiler\IDLCompiler\bin\Debug\daq
service.idl
E:\IIOPNet.src.1.9.3\IDLToCLSCompiler\IDLCompiler\bin\Debug>
(3)新建工程
图2 新建C#控制台工程
(4)添加daqservice.dll和IIOPChannel引用
图3 添加引用
图4 daqService在C#接口情况
4、三种语言实现代码
(1)、C#客户端代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;
using omg.org.CosNaming;
using daqns;
namespace testncdotnet
{
class Program
{
static void Main(string[] args)
{
string host = "localhost";
int port = 10003;
try
{
// register the channel
IiopClientChannel channel =new IiopClientChannel();
ChannelServices.RegisterChannel(channel,false);
// Access the COS naming service (NameService)...
CorbaInit init =CorbaInit.GetInit();
NamingContext nameService = init.GetNameService(host, port);
// Access the IDL-defined interface
// (which maps to a .NET interface class)
NameComponent[] interfaceName =new NameComponent[] {new NameComponent("daqSevice","") };
daqns.DaqService daq = (daqns.DaqService)nameService.resolve(interfaceName);
// call GetAnalogProperty
AnalogProperty[] result = daq.GetAnalogProperty("ZTL","10.30.02.01.101");
int nCount = result.Count();
for (int i = 0; i < nCount; i++)
{
string strDesc = decodeText(result[i].Description);
string strValue = result[i].Value.ToString();
string strInfo =string.Format("描述:{0},值:{1}", strDesc, strValue);
Console.WriteLine(strInfo);
}
}
catch (Exception e)
{
Console.WriteLine("exception: " + e);
}
}
public static string decodeText(string src)
{
Encoding s_latin1 =Encoding.GetEncoding("GBK");
byte[] bDesc = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(src);
string rlt = s_latin1.GetString(bDesc);
return rlt;
}
}
}
(2)、JAVA客户端代码
package soap;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import daqns.AnalogProperty;
import daqns.DaqServiceHelper;
import daqns.DigitalProperty;
import daqns.EventProperty;
public classrtsip
{
public static void main(String[] args) throws MalformedURLException, Exception
{
try
{
org.omg.CORBA.Object managerObj;
String nameservice ="corbaloc::localhost:10003/NameService";
ORB orb = ORB.init(lpArgs, null);
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(orb
.string_to_object("corbaloc::localhost:10003/NameService"));
NameComponent name = new NameComponent("daqSevice", "");
NameComponent path[] = { name };
managerObj = ncRef.resolve(path);
// Narrow the previous object to obtain the correct type
manager = DaqServiceHelper.narrow(managerObj);
AnalogProperty[] anaPropSeq = manager.GetAnalogProperty("ZTL","10.30.02.01.101");
int nCount = anaPropSeq.length;
for (int i = 0; i < nCount; i++)
{
float fValue = anaPropSeq[i].Value;
String strDesc = decodeText(anaPropSeq[i].Description));
System.out.println(“描述:” + strDesc + “,” +“值:” + fValue);
}
}
catch (Exception e)
{
System.out.println("ERROR : " + e);
}
return 0;
}
public static String decodeText(String src) throws UnsupportedEncodingException
{
byte[] bytes = src.getBytes("ISO-8859-1");
String rlt = new String(bytes,"GBK");
return rlt;
}
}
(3)、C++客户端代码
// testnsc.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <OB/CORBA.h>
#include <OB/CosNaming.h>
#include <time.h>
#include "daqservice_skel.h"
using namespace std;
int main(int argc,char* argv[])
{
// Declare ORB
CORBA::ORB_var orb;
try
{
// Initialize the ORB
orb = CORBA::ORB_init(argc, argv);
//Get a reference to the Naming Service
CORBA::Object_var rootContextObj = orb->resolve_initial_references("NameService");
if (CORBA::is_nil(rootContextObj))
{
cerr << "Nil daqsevice Reference" << endl;
throw 0;
}
CosNaming::NamingContext_var nc =
CosNaming::NamingContext::_narrow(rootContextObj.in());
CosNaming::Name name;
name.length(1);
name[0].id = (constchar *)"daqSevice";
name[0].kind = (constchar *)"";
// Invoke the root context to retrieve the object reference
CORBA::Object_var managerObj = nc->resolve(name);
// Narrow the previous object to obtain the correct type
::daqns::DaqService_var manager = NULL;
manager = ::daqns::DaqService::_narrow(managerObj.in());
if (CORBA::is_nil(manager))
{
cerr << "Nil DaqService Reference" << endl;
throw 0;
}
::daqns::AnalogPropertySeq_var anaPropSeq;
anaPropSeq = manager->GetAnalogProperty(groupcode, devicecode);
if (anaPropSeq)
{
CORBA::ULong nCount = anaPropSeq->length();
for (CORBA::ULong i = 0; i < nCount; i++)
{
::daqns::AnalogProperty analog;
analog = anaPropSeq[i];
sprintf(szMsg, "描述:%s, 值:%0.3f", analog.Description, analog.Value);
cout << szMsg << endl;
}
}
}
catch (const CORBA::Exception& e)
{
cerr << e._name() << endl;
}
return 0;
}
(4)、执行结果(数值为随机数)
查询条件:(类型:模拟量,车站名称:紫藤路,设备编码: 10.30.02.01.101)
描述:弱电机房交流配电屏I路AB相电压,值:75.62486
描述:弱电机房交流配电屏I路BC相电压,值:56.78274
描述:弱电机房交流配电屏I路CA相电压,值:74.30647
描述:弱电机房交流配电屏输出A相电流,值:46.05243
描述:弱电机房交流配电屏输出B相电流,值:186.0958
描述:弱电机房交流配电屏输出C相电流,值:265.6118
描述:弱电机房交流配电屏I路进线频率,值:281.7255
描述:弱电机房交流配电屏II路AB相电压,值:58.69625
描述:弱电机房交流配电屏II路BC相电压,值:233.8969
描述:弱电机房交流配电屏II路CA相电压,值:193.6674
描述:弱电机房交流配电屏II路进线频率,值:197.0275
描述:弱电机房直流配电屏整流器个数,值:272.7439
描述:弱电机房直流配电屏电压降补偿设定值,值:136.6375
描述:弱电机房直流配电屏电池放电告警电压设定,值:276.3878
描述:弱电机房直流配电屏均充阀值电压设定值,值:199.2523
描述:弱电机房直流配电屏交流电压上限,值:45.22843
描述:弱电机房直流配电屏交流电压下限,值:190.9024
描述:弱电机房直流配电屏当前浮充电压,值:170.8609
描述:弱电机房直流配电屏当前均充电压,值:126.6121
描述:弱电机房直流配电屏输出电压高告警设定值,值:282.9066
描述:弱电机房直流配电屏输出电压低告警设定值,值:162.1723
描述:弱电机房直流配电屏输出电压过高关机设定,值:173.571
描述:弱电机房直流配电屏限流设定值,值:160.9363
描述:弱电机房直流配电屏直流输出电压,值:76.5862
描述:弱电机房直流配电屏负载电流,值:119.0863
描述:弱电机房直流配电屏电池组I充/放电电流,值:105.0783
描述:弱电机房直流配电屏电池组II充/放电电流,值:10.98666
描述:弱电机房直流配电屏电池组I温度,值:238.5754
描述:弱电机房直流配电屏电池组II温度,值:58.95261
描述:弱电机房直流配电屏环境温度,值:21.08524
描述:弱电机房直流配电屏电池组I容量,值:116.8249
描述:弱电机房直流配电屏电池组II容量,值:177.224
描述:弱电机房直流配电屏输入电压,值:21.2775
描述:弱电机房直流配电屏输入电流(交流),值:59.30051
描述:弱电机房直流配电屏输入频率,值:46.76656
描述:弱电机房直流配电屏整流器#1电流,值:193.3012
描述:弱电机房直流配电屏整流器#1温度,值:136.2987
描述:弱电机房直流配电屏整流器#2电流,值:181.2891
描述:弱电机房直流配电屏整流器#2温度,值:209.2044
描述:弱电机房直流配电屏整流器#3电流,值:132.3893
描述:弱电机房直流配电屏整流器#3温度,值:205.3407
描述:弱电机房直流配电屏整流器#4电流,值:118.9581
描述:弱电机房直流配电屏整流器#4温度,值:250.7157
描述:弱电机房直流配电屏整流器#5电流,值:177.6635
描述:弱电机房直流配电屏整流器#5温度,值:59.87732
描述:弱电机房直流配电屏整流器#6电流,值:284.8384
描述:弱电机房直流配电屏整流器#6温度,值:262.801
描述:弱电机房UPS后备工作时间,值:117.5115
描述:弱电机房UPS电池充电量,值:296.2371
描述:弱电机房UPS电池电压,值:55.59252
描述:弱电机房UPS电池电流,值:268.7155
描述:弱电机房UPS电池温度,值:172.335
描述:弱电机房UPS输入相数,值:132.6182
描述:弱电机房UPS输入频率,值:188.2015
描述:弱电机房UPS输入A相电压(输入交流),值:212.5553
描述:弱电机房UPS输入B相电压(输入交流),值:14.88693
描述:弱电机房UPS输入C相电压(输入交流),值:85.66851
描述:弱电机房UPS输入最小电压,值:78.06024
描述:弱电机房UPS输入最大电压,值:122.2907
描述:弱电机房UPS输出相数,值:268.5965
描述:弱电机房UPS输出频率,值:213.0589
描述:弱电机房UPS输出电压1,值:218.5339
描述:弱电机房UPS输出电压2,值:268.8162
描述:弱电机房UPS输出电压3,值:118.07
描述:弱电机房UPS输出电流1,值:119.2236
描述:弱电机房UPS输出电流2,值:271.16
描述:弱电机房UPS输出电流3,值:92.58095
描述:弱电机房UPS旁路相数,值:116.4312
描述:弱电机房UPS旁路频率,值:171.1722
描述:弱电机房UPS旁路A相电压,值:106.0671
描述:弱电机房UPS旁路B相电压,值:220.1086
描述:弱电机房UPS旁路C相电压,值:223.6061
图5 daqService应用中的角色
三、结束语
本文通过分析使用.NET应用,并以IIOP.NET方式展现十二五课题接口的示例,阐释了使用C#开发corba应用程序的流程可行性。通过采用IIOP.NET能够达到企业级应用系统的无缝集成的要求,IIOP.NET具有可靠性高,可用性强,紧耦合等特点,并且这个技术是一个开源项目,拥有LGPL许可证。因此,它是一种理想的企业级应用工具和应用系统解决方案。
本文基于CORBA中间件技术,实现不同语言与安监平台间通信,以通用标准化的手段解决了平台之间异构。希望本文能为企业起到抛砖引玉作用,提供在未来不同场景中一个架构思想。
四、资源链接
IIOP.NET | |
Janeva | |
Remoting.Corba |
Technologies:
.NET Remoting | http://msdn.microsoft.com/library/en-us/dndotnet/html/hawkremoting.asp |
RMI / IIOP | |
CORBA | http://www.corba.org |