使用 XML-RPC 对用 C#、Ruby 和 Java 编写的分布式应用程序进行编程

发布于 2024-09-29 13:29:54 字数 5320 浏览 6 评论 0原文

我的任务是编写一个分布式事件管理工具,其中每个客户端(Ruby、C# 或 Java 客户端)将所有更改与注册客户端列表同步。我必须使用 XML-RPC 来实现目标。我和我的团队已经用每种语言编写了 XML-RPC 客户端和服务器,并将在下面提供相关源代码。如果您需要更多代码,请告诉我。

问题是我可以让 Java 和 C# 相互通信。 Ruby 可以与其他语言进行通信,但 C#(可能还有 Java,尚未测试)在处理 Ruby 服务器时存在问题。我猜问题出在端点上。首先让我给你一些代码。阅读时请注意,代码实际上是由团队编写的,命名约定略有不同:

C# 客户端

Uri _address = new Uri("http://" + _s + ":8000/xmlrpc/EventManagerService");
ChannelFactory<IEventManagerWCF_XML_RPC> _factory = new ChannelFactory<IEventManagerWCF_XML_RPC>(new WebHttpBinding(WebHttpSecurityMode.None), new EndpointAddress(_address));
_factory.Endpoint.Behaviors.Add(new XmlRpcEndpointBehavior());
IEventManagerWCF_XML_RPC _proxy = _factory.CreateChannel();

_proxy 不会保留给定 URI 的客户端。它们存储在字典中,并在需要同步事件时使用。在修改的情况下会发生这样的同步;

 foreach(IEventManagerWCF_XML_RPC proxy in this.peers.Values)
        proxy.modify(_id, _field, _newValue);

以下是 IEventManagerWCF_XML_RPC 接口的摘录;

 [OperationContract(Action = "EventManagerService.modify")]
 bool modify(int id, string field, string newValue);

C# XML RPC 服务

 Uri _baseAddress = new Uri("http://localhost:8000/xmlrpc");
 _eventManagerHost = new ServiceHost(typeof(EventManagerService), _baseAddress);
     try
     {
     ServiceEndpoint epXmlRpc = _eventManagerHost.AddServiceEndpoint(typeof(IEventManagerWCF_XML_RPC), new WebHttpBinding(WebHttpSecurityMode.None), "EventManagerService");
     epXmlRpc.Behaviors.Add(new XmlRpcEndpointBehavior());

     ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
     smb.HttpGetEnabled = true;
     _eventManagerHost.Description.Behaviors.Add(smb);
     _eventManagerHost.Open();
     }
     catch (CommunicationException ce)
     {
     Console.WriteLine("An exception occurred: {0}", ce.Message);
     _eventManagerHost.Abort();
     }

我想这里没什么特别的。让我们继续讨论 Java 代码!

Java 客户端

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try {
  config.setServerURL(new URL("http://"+ip+":8000/xmlrpc/EventManagerService"));

} 
catch (MalformedURLException e) {  
  e.printStackTrace();
}

config.setEnabledForExtensions(true);  
config.setConnectionTimeout(60 * 1000);
config.setReplyTimeout(60 * 1000);      
XmlRpcClient client = new XmlRpcClient();
client.setTransportFactory(new XmlRpcCommonsTransportFactory(client));
client.setConfig(config);
xmlRpcPeers.put(ip, client); 

xmlRpcPeers 现在拥有不同的客户端。它们的名称如下;

for(XmlRpcClient peer : this.xmlRpcPeers.values())
  {
   try {
    peer.execute("EventManagerService.modify", params);
   } catch (Exception e) {
    e.printStackTrace();
   }
  }

Java Server 有自己的类,并通过简单的 new 调用进行实例化;

public class Server extends Thread{

/**
* Server port
*/
  private static final int port = 8000;

  /**
   * Starts the XML-RPC server
   */
  public void run(){
   WebServer webServer = new WebServer(port);        
   XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();   

   PropertyHandlerMapping phm = new PropertyHandlerMapping();
   try
   {
    phm.addHandler("EventManagerService", lu.uni.binfo.ds.EventManager_Java.EventManagerService.class);
   } 
   catch (XmlRpcException e1) 
   {
    e1.printStackTrace();
   }           
      xmlRpcServer.setHandlerMapping(phm);        
      XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
      serverConfig.setEnabledForExtensions(true);
      serverConfig.setContentLengthOptional(false);          
      try 
      {
        webServer.start();
      } 
      catch (IOException e) 
      {
        e.printStackTrace();
      }
   }
}

到目前为止,一切似乎都进展顺利。添加 Ruby 是最麻烦的事情。这是相关代码;

Ruby 客户端 Ruby 客户端也存储在字典中。它的填充如下;

@devices_XMLRPC[key] = EventManagerClient_XMLRPC.new(tokens[0]).device

该类的代码为:

class EventManagerClient_XMLRPC
  @uri
  @device
  attr_accessor :uri, :device

  def initialize(uri)
    @uri = uri
    @device = XMLRPC::Client.new2(
            uri="http://" << @uri.to_s << ":8000/xmlrpc/EventManagerService", proxy=nil, timeout=30)
  end
end

同步修改的调用如下所示:

@devices_XMLRPC.each_value { |client| client.call("EventManagerService.modify", tokens[0], field, value) }

Ruby Server

server = XMLRPC::Server.new(8000, "127.0.0.1")
server.add_handler("xmlrpc/EventManagerService", EventManagerService.instance)
puts "Server ready!"
server.serve

EventManagerService 类:

class EventManagerService
  include Singleton
  @manager

  def initialize()
    @manager = EventManager.instance
  end

  def modify(id, field, newValue)
      puts "modify called"
      @manager.modify([id, field, newValue], 1)
  end

end

EventManager 是所有逻辑所在的类。

尝试从 C# 与 Ruby 通信时出现的错误是 EndPointNotFoundException,内容如下:

在 http://ip:8000/xmlrpc/EventManagerService 上没有侦听可以接受消息的端点。[ ...]

我尝试摆弄端点声明,但似乎无法让它工作。 Ruby 文档也没有帮助。我需要帮助!

I am tasked with writing a distributed event managing tool where each client, either a Ruby, C# or Java Client, synchronises all changes with a list of registered clients. I have to use XML-RPC to achieve the goal. My team and I have written up an XML-RPC client and server in each language and will provide the relevant source code below. If you require more code, please let me know.

The problem is that I can get Java and C# to communicate with each other. Ruby can communicate with the others but C# (and maybe Java, haven't tested yet) have problems addressing the Ruby server. I guess the problem is with the Endpoint. First let me give you some code. When reading please be aware that the code is actually written by a team and naming conventions differ a bit:

C# client

Uri _address = new Uri("http://" + _s + ":8000/xmlrpc/EventManagerService");
ChannelFactory<IEventManagerWCF_XML_RPC> _factory = new ChannelFactory<IEventManagerWCF_XML_RPC>(new WebHttpBinding(WebHttpSecurityMode.None), new EndpointAddress(_address));
_factory.Endpoint.Behaviors.Add(new XmlRpcEndpointBehavior());
IEventManagerWCF_XML_RPC _proxy = _factory.CreateChannel();

_proxy will not hold the client for a given URI. Those are stored in a dictionary and used when the need arises to synchronise events. One such synchronisation would happen in the case of a modification;

 foreach(IEventManagerWCF_XML_RPC proxy in this.peers.Values)
        proxy.modify(_id, _field, _newValue);

Here is an extract from the IEventManagerWCF_XML_RPC interface;

 [OperationContract(Action = "EventManagerService.modify")]
 bool modify(int id, string field, string newValue);

C# XML RPC service

 Uri _baseAddress = new Uri("http://localhost:8000/xmlrpc");
 _eventManagerHost = new ServiceHost(typeof(EventManagerService), _baseAddress);
     try
     {
     ServiceEndpoint epXmlRpc = _eventManagerHost.AddServiceEndpoint(typeof(IEventManagerWCF_XML_RPC), new WebHttpBinding(WebHttpSecurityMode.None), "EventManagerService");
     epXmlRpc.Behaviors.Add(new XmlRpcEndpointBehavior());

     ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
     smb.HttpGetEnabled = true;
     _eventManagerHost.Description.Behaviors.Add(smb);
     _eventManagerHost.Open();
     }
     catch (CommunicationException ce)
     {
     Console.WriteLine("An exception occurred: {0}", ce.Message);
     _eventManagerHost.Abort();
     }

Nothing special here I guess. Lets move on to the Java code!

Java Client

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try {
  config.setServerURL(new URL("http://"+ip+":8000/xmlrpc/EventManagerService"));

} 
catch (MalformedURLException e) {  
  e.printStackTrace();
}

config.setEnabledForExtensions(true);  
config.setConnectionTimeout(60 * 1000);
config.setReplyTimeout(60 * 1000);      
XmlRpcClient client = new XmlRpcClient();
client.setTransportFactory(new XmlRpcCommonsTransportFactory(client));
client.setConfig(config);
xmlRpcPeers.put(ip, client); 

xmlRpcPeers now holds the different clients. They are called as follows;

for(XmlRpcClient peer : this.xmlRpcPeers.values())
  {
   try {
    peer.execute("EventManagerService.modify", params);
   } catch (Exception e) {
    e.printStackTrace();
   }
  }

The Java Server has it's own class and is instantiated with a simple new call;

public class Server extends Thread{

/**
* Server port
*/
  private static final int port = 8000;

  /**
   * Starts the XML-RPC server
   */
  public void run(){
   WebServer webServer = new WebServer(port);        
   XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();   

   PropertyHandlerMapping phm = new PropertyHandlerMapping();
   try
   {
    phm.addHandler("EventManagerService", lu.uni.binfo.ds.EventManager_Java.EventManagerService.class);
   } 
   catch (XmlRpcException e1) 
   {
    e1.printStackTrace();
   }           
      xmlRpcServer.setHandlerMapping(phm);        
      XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
      serverConfig.setEnabledForExtensions(true);
      serverConfig.setContentLengthOptional(false);          
      try 
      {
        webServer.start();
      } 
      catch (IOException e) 
      {
        e.printStackTrace();
      }
   }
}

Up till now everything seemed to work fine. Adding Ruby to the mix is what gives the most trouble. Here is the relevant code;

Ruby Client
Ruby clients are also stored in a dictionary. It is populated as follows;

@devices_XMLRPC[key] = EventManagerClient_XMLRPC.new(tokens[0]).device

The code for the class is:

class EventManagerClient_XMLRPC
  @uri
  @device
  attr_accessor :uri, :device

  def initialize(uri)
    @uri = uri
    @device = XMLRPC::Client.new2(
            uri="http://" << @uri.to_s << ":8000/xmlrpc/EventManagerService", proxy=nil, timeout=30)
  end
end

A call to synchronise on modifications looks like this:

@devices_XMLRPC.each_value { |client| client.call("EventManagerService.modify", tokens[0], field, value) }

Ruby Server

server = XMLRPC::Server.new(8000, "127.0.0.1")
server.add_handler("xmlrpc/EventManagerService", EventManagerService.instance)
puts "Server ready!"
server.serve

The EventManagerService class:

class EventManagerService
  include Singleton
  @manager

  def initialize()
    @manager = EventManager.instance
  end

  def modify(id, field, newValue)
      puts "modify called"
      @manager.modify([id, field, newValue], 1)
  end

end

EventManager being the class where all the logic resides.

The error when trying to communicate from C# to Ruby is an EndPointNotFoundException that reads:

There was no endpoint listening at http://ip:8000/xmlrpc/EventManagerService that could accept the message.[...]

I tried fiddling around with the endpoint declaration but cannot seem to get it to work. The Ruby documentation does not help either. I am in need of help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自我难过 2024-10-06 13:29:54

您可以尝试使用 WireShark 检查线路上的流量。使用此工具,您将能够查看在不同应用程序之间传输的实际 HTTP 数据。也许这提供了一个关于为什么 Ruby 和 C# 之间通信出现问题的提示。

You could try inspecting the traffic that goes over the line with WireShark. With this tool, you would be able to see the actual HTTP data that is transferred between the different applications. Maybe this provides a hint as to why you have problems communicating between Ruby and C#.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文