ICE学习之C# Java之间通讯

简介:
 进alibaba以来一直听说我们有部分产品之间的通讯是采用ICE架构的,它是一种简洁的分布式网络中间件。但是由于项目紧张一直没有时间研究,这两天终于有时间研究一把(而且据老大说我们今年要对旺旺提供给内部的接口进行测试,该部分的设计又是采用ICE通讯的),所以也是不得已不学习的。为此查了好多资料 ,  终于也弄明白了是怎么回事,并且实战了一把,也把自己学习的历程总结一下,方便后来者。
         首先,必须明白ICE是作为一种中间件语言,那么它必须是标准的,简易的。事实也是如此,如下例子,在ICE文档中只需要申明module名称,接口名称,方法名称。
01     #ifndef SIMPLE_ICE
02     #define SIMPLE_ICE
03    
04     module Demo {
05         interface Printer
06         {
07             void printString(string s);
08         };
09     };
10     #endif
 
        其次,支持不同语言之间通讯的。也就是说服务器端拿着ICE的文档去编写服务器端的代码,它可能采取c++也可能采用C#也可能采用java来编写服务器端的代码。而客户端用户拿着ICE的文档,去编写客户端的代码。而他们编译出来的代码是可以相互通信的,因为他们采用了同一个桥梁ICE。下面将通过两个个例子说明
l  如何编写一个C#的ICE服务和一个C#的客户端进行通讯
l  如何编写一个C#的ICE服务和一个java的客户端进行通讯。
例子一:快速搭建一个C#的ICE服务和一个C#的客户端代码。
1.         首先需要下载ice的安装包,地址如下: http://www.zeroc.com/download.html
2.         在下载安装完之后,设置系统的环境变量,Path = Path+ ;安装目录/bin
3.         仔细阅读安装目录中的readme,其中对于每一种语言如何编写服务器端和客户端代码都有描述。
4.         打开vs2005编辑器,加载C#的demo。目录=安装目录\democs\demo.sln。
5.         在demo的solution中有很多工程,我们选择Printer来进行实验。编译PrinterS,PrinterC。
6.         打开一个cmd窗体,cd到工程目录,运行server.exe.启动ICE服务。
7.  再打开一个cmd窗体,cd到工程目录,允许client.exe,再到server.exe的窗体查阅是否成功调用,如果出现hello world说明通过C#编写的客户端调用C#编写的ICE服务成功。
         那么我们回头研究一下,ICE的服务器端和客户端是如何编码的。(我一般喜欢倒推式的学习方式,这样往往效率比较高点)。
         首先必须了解服务器端代码是如何生成的。服务器端开发者最早拿到的是一个ice文档,那么就需要把ice文档转换为c#语言能认识的类。命令如下:
01  slice2cs.exe Printer.ice 
这条命令会在当前目录下产生Printer.cs文件如下。在下面这段代码中完成代理类的生成,以及ICE自身需要的服务鉴别函数PrinterPrx checkedCast等声明。
001  #if __MonoCS__
002 
003  using _System = System;
004  using _Microsoft = Microsoft;
005  #else
006 
007  using _System = global::System;
008  using _Microsoft = global::Microsoft;
009  #endif
010 
011  namespace Demo
012  {
013      public sealed class PrinterHelper
014      {
015          public PrinterHelper(Ice.InputStream inS__)
016          {
017              _in = inS__;
018              _pp = new IceInternal.ParamPatcher<Demo.Printer>("::Demo::Printer");
019          }
020 
021          public static void write(Ice.OutputStream outS__, Printer v__)
022          {
023              outS__.writeObject(v__);
024          }
025 
026          public void read()
027          {
028              _in.readObject(_pp);
029          }
030 
031          public Demo.Printer value
032          {
033              get
034              {
035                  return (Demo.Printer)_pp.value;
036              }
037          }
038 
039          private Ice.InputStream _in;
040          private IceInternal.ParamPatcher<Demo.Printer> _pp;
041      }
042 
043      public interface Printer : Ice.Object, PrinterOperations_, PrinterOperationsNC_
044      {
045      }
046  }
047 
048  namespace Demo
049  {
050      public interface PrinterPrx : Ice.ObjectPrx
051      {
052          void printString(string s);
053          void printString(string s, _System.Collections.Generic.Dictionary<string, string> context__);
054      }
055  }
。。。
。。。。
。。。
116          #region Checked and unchecked cast operations
117 
118          public static PrinterPrx checkedCast(Ice.ObjectPrx b)
119          {
120              if(b == null)
121              {
122                  return null;
123              }
124              PrinterPrx r = b as PrinterPrx;
125              if((r == null) && b.ice_isA("::Demo::Printer"))
126              {
127                  PrinterPrxHelper h = new PrinterPrxHelper();
128                  h.copyFrom__(b);
129                  r = h;
130              }
131              return r;
132          }
133 
134          public static PrinterPrx checkedCast(Ice.ObjectPrx b, _System.Collections.Generic.Dictionary<string, string> ctx)
135          {
136              if(b == null)
137              {
138                  return null;
139              }
140              PrinterPrx r = b as PrinterPrx;
141              if((r == null) && b.ice_isA("::Demo::Printer", ctx))
142              {
143                  PrinterPrxHelper h = new PrinterPrxHelper();
144                  h.copyFrom__(b);
145                  r = h;
146              }
147              return r;
148          }
。。。。
 
     有了printer.cs后,就需要新建一个服务器端的工程了。加入Printer.cs文件,最后建立Server.cs文件。如安装包自带的文件目录如下:

我们再来看看Server.cs的代码。
01     using System;
02     using System.Reflection;
03    
04     [assembly: CLSCompliant(true)]
05    
06     [assembly: AssemblyTitle("IcePrinterServer")]
07     [assembly: AssemblyDescription("Ice printer demo server")]
08     [assembly: AssemblyCompany("ZeroC, Inc.")]
09    
10     public class PrinterI : Demo.PrinterDisp_
11     {
12         public override void printString(string s, Ice.Current current)
13         {
14             Console.WriteLine(s);
15         }
16     }
17    
18     public class Server
19     {
20         public static void Main(string[] args)
21         {
22             int status = 0;
23             Ice.Communicator ic = null;
24             try {
25                 ic = Ice.Util.initialize(ref args);
26                 Ice.ObjectAdapter adapter
27                     = ic.createObjectAdapterWithEndpoints(
28                         "SimplePrinterAdapter", "default -p 10000");
29                 Ice.Object obj = new PrinterI();
30                 adapter.add(
31                         obj,
32                         ic.stringToIdentity("SimplePrinter"));
33                 adapter.activate();
34                 ic.waitForShutdown();
35             } catch (Exception e) {
36                 Console.Error.WriteLine(e);
37                 status = 1;
38             }
39             if (ic != null)
40             {
41                 // Clean up
42                 //
43                 try {
44                     ic.destroy();
45                 } catch (Exception e) {
46                     Console.Error.WriteLine(e);
47                     status = 1;
48                 }
49             }
50             if(status != 0)
51             {
52                 System.Environment.Exit(status);
53             }
54         }
55     }
 
             代码26到38为关键功能,主要完成以下任务。
             * 创建一个对象适配器(ObjectAdapter)对象IOAdapter,并初始化之。
             * 参数" SimplePrinterAdapter ":表示适配器的名字。
             * 参数"default -p 10000":表示适配器使用缺省协议(TCP/IP)在端口10000处监听到来的请求。
             * 服务器配置完成.
* 为PrinterI接口创建一个servant.
             * 将新的servant添加到适配器,
             * 并将这个新的servant命名为" SimplePrinter "
* 激活适配器,以使服务器开始处理来自客户的请求
* 挂起发出调用的线程,直到服务器实现终止为止.
             * 或者是通过发出一个调用关闭运行时(run time)的指令来使服务器终止.
 在完成C#服务器端代码之后,我们需要完成C#客户端的代码,同样需要引入代理类。程序目录如下图:

客户端程序如下:
01     using Demo;
02     using System;
03     using System.Reflection;
04    
05     [assembly: CLSCompliant(true)]
06    
07     [assembly: AssemblyTitle("IcePrinterClient")]
08     [assembly: AssemblyDescription("Ice printer demo client")]
09     [assembly: AssemblyCompany("ZeroC, Inc.")]
10    
11     public class Client
12     {
13         public static void Main(string[] args)
14         {
15             int status = 0;
16             Ice.Communicator ic = null;
17             try {
18                 ic = Ice.Util.initialize(ref args);
19                 Ice.ObjectPrx obj = ic.stringToProxy(
20                         "SimplePrinter:default -p 10000");
21                 PrinterPrx printer = PrinterPrxHelper.checkedCast(obj);
22                 if (printer == null)
23                     throw new ApplicationException("Invalid proxy");
24    
25                 printer.printString("Hello World!");
26             } catch (Exception e) {
27                 Console.Error.WriteLine(e);
28                 status = 1;
29             }
30             if (ic != null) {
31                 // Clean up
32                 //
33                 try {
34                     ic.destroy();
35                 } catch (Exception e) {
36                     Console.Error.WriteLine(e);
37                     status = 1;
38                 }
39             }
40             if(status != 0)
41             {
42                 System.Environment.Exit(status);
43             }
44         }
45     }

上述代码主要完成如下功能
         * 获取远程对象的代理
         * 创建一个代理对象,并用通信器的stringToProxy()方法初始化之。
         * 参数:" SimplePrinter:default -p 10000"
         * 测试向下转换是否成功。如果不成功抛出异常信息"Invalid proxy".
         * 如果成功调用远程方法printer.printString("Hello World!");
因此在之前做第一个实验的时候,在服务器端会打印出Hello world。至此我们就知道了如何使用C#进行ICE的服务调用。
         下面我们将做第二个例子,通过java的客户端来调用C#的服务器端。服务器端的搭建和例子一一样,这里就不再赘述。这里主要讲述客户端代码如何实现。
         首先必须和C#一样有ICE文件生成代理类,命令如下:
slice2java Printer.ice
上述命令会生成一个含java代理类的文件夹Demo,目录结构如下图:
新建java工程,引入安装包中的jar包,jar包目录=ice安装目录\lib\*.jar
引入demo的文件夹到工程中。
新增测试类,TestPrinter代码如下:
 
01     package Demo;
02    
03     public class TestPrinter {
04              public static void main(String[] args) {  
05             int status = 0;  
06             Ice.Communicator ic = null;  
07             try {  
08                 ic = Ice.Util.initialize(args);  
09     //          Ice.ObjectPrx base = ic  
10     //                  .stringToProxy("SimplePrinter:tcp -h 172.17.12.101 -p 10000");  
11                 Ice.ObjectPrx base = ic  
12                 .stringToProxy("SimplePrinter:default -p 10000");  
13      
14                 PrinterPrx test = PrinterPrxHelper.checkedCast(base);  
15                 if (test == null)  
16                     throw new Error("Invalid proxy");  
17                 System.out.println("go");  
18                 test.printString("My first Ice ");
19                 //System.out.println("ok");  
20             } catch (Ice.LocalException e) {  
21                 e.printStackTrace();  
22                 status = 1;  
23             } catch (Exception e) {  
24                 System.err.println(e.getMessage());  
25                 status = 1;  
26             }  
27             if (ic != null) {  
28                 // Clean up  
29                 //  
30                 try {  
31                     ic.destroy();  
32                 } catch (Exception e) {  
33                     System.err.println(e.getMessage());  
34                     status = 1;  
35                 }  
36             }  
37             System.exit(status);  
38         }  
39    
40     }

从C#和java的客户端代码比较看,实质上两者是一样的。运行java的代码再服务器端会显示My first Ice。
 


本文转自elbertchen 51CTO博客,原文链接:http://blog.51cto.com/linkyou/283224,如需转载请自行联系原作者

相关文章
|
2天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
2天前
|
Dubbo Java 应用服务中间件
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
|
2天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
2天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
2天前
|
Java API
Java从入门到精通:2.1.5深入学习Java核心技术之文件操作
Java从入门到精通:2.1.5深入学习Java核心技术之文件操作
|
2天前
|
并行计算 算法 安全
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
|
6天前
|
JavaScript Java 测试技术
基于Java的驾考自主学习预约平台的设计与实现(源码+lw+部署文档+讲解等)
基于Java的驾考自主学习预约平台的设计与实现(源码+lw+部署文档+讲解等)
18 0
|
7天前
|
JavaScript Java 测试技术
基于Java的精品课程在线学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的精品课程在线学习系统的设计与实现(源码+lw+部署文档+讲解等)
26 1
|
7天前
|
JavaScript Java 测试技术
基于Java的中文学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的中文学习系统的设计与实现(源码+lw+部署文档+讲解等)
23 0
|
13天前
|
Java 存储
键值之道:深入学习Java中强大的HashMap(二)
键值之道:深入学习Java中强大的HashMap
20 0
键值之道:深入学习Java中强大的HashMap(二)