Programming a distributed application written in C#, Ruby and Java using XML-RPC
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!
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#.
精彩评论