I'm trying to write a program for Client/Server communication using RMI and this subject is new to me. I've looked at ton of examples to see if I can try to understand it and they all seem to be designed using local host. My program won't be run on localhost, it will be connecting to Server which is a whole different machine.
If anyone can show me just a simple example of how to establish a connection between two different machines using RMI that would be awesome. I don't need to see how its done for localhost, I've seen like million of those.
Thanks
You only have to change the client.
Change its Naming.lookup() string, from "localhost" to the server's hostname or IP address. The server's Naming string in the bind() or rebind() call does not change from "localhost", because the server and its Registry are always on the same host.
If you are using Registry instead of Naming, again you only have to change the client's LocateRegistry.getRegistry() call.
Let us assume we are connecting two Systems , A(server) with IP address 192.168.1.2 and B (client) with IP address 192.168.1.3 .
You should start the registry on server,i.e., system A then the Server Program should bind the Object like
Naming.rebind("rmi://192.168.1.2/myObject",obj);
Then compile the Client Program on system B which has the lookup function as
myInterface objHandle = (myInterface)Naming.lookup("rmi://192.168.1.2/myObject");
The main catch is that the two systems have to be on the same network for communicating, you might have to create your own network.
Related
I know this is something repetead but couldn't find the solution to my problem...
I am trying to implement a simulated distributed system and I struggling a lot with the connectivity through RMI.
I have three different components, grid schedulers, resources managers and clients. The three of them interact among themselves. The behaviour is the following: the user looks up resource manager reference on the registry and then invokes a remote method which will invoke another one in the grid scheduler and eventually one method in the user will be invoked delivering the results. If I execute the whole system in local everything works as expected.
Now the thing is, I am trying to move one of the resource mananger nodes to a EC2 Amazon instance with public address A.A.A.A, the rest of the system will run locally on my laptop with public address B.B.B.B. I allowed TCP traffic on the port 1099 TCP/UDP on the security group policy, also set the java.security.policy to grant all permision in both machines. To create the registry in every component I do:
LocateRegistry.createRegistry(1099);
Then the components will discover themselves by
Naming.lookup(url)
Now, user will look up for ip address A.A.A.A/component the public address of the Amazon instance. I can check that sometimes it gets the reference, sometimes it doesn't (NotBoundException). However, when it does gets the reference and tries to call the method I get:
java.rmi.ConnectException: Connection refused to host: INTERNAL IP OF AMAZON INSTANCE nested exception is: java.net.ConnectException: Connection timed out: connec.
Am I doing something wrong? I tried to set the property
java.rmi.server.hostname
To the public ip A.A.A.A in the Amazon instance and I got same results. I also tried doing the same on my laptop to the public address B.B.B.B and I got "connection refused IP B.B.B.B is not a localhost address"
I also opened the port in the router of my houe just in case that's the problem but it doesn't seem to be...
Am I missing something?
Thanks in advance.
Okay apparently, the issue was that even if the server listens on port 1099 then the port you use to connect the stub is random so I had to open all TCP ports in the security group of AWS. In that way it's working, however even if I turned off my windows firewall and open all the ports in the router it wasn't working my laptop - AWS, just different instances in AWS. But well, I can live with that...
Regarding the hostname you have to set it to the private address returned by
hostname -i
If you're going to deploy it inside AWS or to the public IP if you're connecting different instances such as your laptop and one EC2.
I hope this helps people on the same situation (have seen couple of questions with the same issue but no response).
Have a nice day!
I want to simply connect two machines on the same network via a TCP Server/Client socket connection.
Right now, I need the IPv4 address from the machine hosting the server in order to connect the client.
localhost works fine when I'm running the server and the client on the same computer, but that's not very useful.
Is there any way around having to manually punch in the IPv4 of the host computer?
Thanks, this will probably clear up a lot of confusion.
Use a broadcast to send all clients a message. (this could contain the servers IP but think about that! it could be a security issue)
There are good examples on sending broadcast messages with java
Broadcasting to Multiple Recipients
If you know the name of the hosts, then you can also pass these names in a config file and use getaddrinfo() to get the IP address of the host: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html . Since hostnames do not chnage frequently, this should provide good improvement as compared to manually punching the IP address.
I'm currently working on a small project that manages attendance for a summer program that I'm helping run. The RMI server is run from the office and has a specific port set for it by using the following code:
Registry registry = LocateRegistry.createRegistry(4051);
RemoteManager stub = (RemoteManager) UnicastRemoteObject.exportObject(theServer, 4051);
registry.rebind(SERVER_NAME, stub);
where theServer is a reference to the object that will serve as the system's server and SERVER_NAME is simply a static String used to represent the server. As is shown the registry binds the server to port 4051 so that clients can query for it. Now I'm working on cross-communication between the server and multiple client instances (12 teachers running the same client program) and currently it is set such that the clients send stubs of themselves to the server for client registration.
public void registerClient(INTERFACE_Client teach) throws RemoteException {
.
.
.
}
where INTERFACE_Client extends the Remote interface and the client is sent down by calling:
server.registerClient((INTERFACE_Client) UnicastRemoteObject.exportObject(this, 4052));
where I just chose port 4052 because I didn't know what I was doing. I also didn't bind the stub to a registry. Is a good way to do it? Because I've hardcoded the client port, all 12 teachers will be exporting the object using port 4052 (at least that's how I see it) from their respective client instances. Should the ports be randomized? Should I not include a port (there's a method that doesn't require that as well)? Any helpful hints would be greatly appreciated.
As a disclaimer, I do need a reference to the client in the server so that people in the office can send messages to the teachers. (Server -> Client communication). The client already has the reference to the server because it can look it up on the registry.Any suggestion?
I just chose port 4052 because I didn't know what I was doing.
That's OK, as long as port 4052 is open in both directions in both intermediate firewalls, if there are any firewalls. There's no real reason why you can't use the RMI Registry port 1099 for this, at both ends: it's already reserved by IANA, unless the hosts already contain some other RMI application.
I also didn't bind the stub to a registry. Is a good way to do it?
That's OK. You don't need a Registry at the client. All you need is your existing registration API.
Because I've hardcoded the client port, all 12 teachers will be exporting the object using port 4052 (at least that's how I see it) from their respective client instances.
That's OK as long as the 'client instances' are all separate TCP hosts.
Should the ports be randomized?
Not unless you have > 1 client per TCP host.
Should I not include a port (there's a method that doesn't require that as well)?
No.
Any helpful hints would be greatly appreciated.
Your clients must implement a remote interface and be exported and then registered with the server via your existing API. You're doing well. As long as there are no firewalls, or they are all under your control, you will be OK.
I understand and have coded up some RMI code and it works. I can create a RMIServer object and a RMIClient object and the client can send messages to the server and the server receives it perfectly.
My question is how do I communicate between two different computers in different parts of the world?
When you connect to the RMI server you provide an IP or name of the machine hosting the server. You will simply provide the IP/name of the RMI server in place of the one you're currently using.
To get your ip, if you have windows go to start ->run-> write cmd. now in the console write ipconfig your ip is ADDRESS IP.
Remember, if you have dynamic ip (unless your supplier get you a static ip) this change when restart your pc
This is what I'm planning to do. Suppose there are 2 machines A and B. I need to create an application by which machine A can send data to Machine B, using Java SE.
I know that to make a connection you need to create an object of serversocket class and use the accept() method as
In Machine B:
ServerSocket ss=new ServerSocket(12000);
while(true)
{
Socket s=ss.accept();
.
.
.
.
}
In Machine A:
Socket s=new Socket("<Machine B's IP Address>",12000);
.
.
.
.
Here's the problem.
Suppose if Machine B's IP address is assigned dynamically with DHCP, ie it can change each time the machine reboots.
Is there any way by which the Java Pgm in machine A can recognize the IP address of B without the user typing it manually???
Hoping that you the question is clear.
Waiting for replies!
Most DNS servers have a mechanism that allows the DHCP server to make dynamic updates to the local (internal) zone. If you have this feature at your disposal, then you can just use DNS names, and let the systems guys make sure that the DNS records are up-to-date with the DHCP leases.
A similar DNS-based approach could be accomplished on the wider internet using a DDNS service like dyndns.
If you can't use DNS, then you're stuck with a UDP broadcast-based approach. This is the same mechanism that protocols like DHCP, bonjour, and SMB use to find other computers on the local network without knowing their addresses; and this approach will only work in the same contexts where those technologies work (typically, only within the local network, and definitely not across the greater internet).
In java, you would accomplish UDP broadcast messaging via the DatagramSocket class.
Quoting the api docs:
UDP broadcasts sends are always enabled on a DatagramSocket. In order to receive broadcast packets a DatagramSocket should be bound to the wildcard address. In some implementations, broadcast packets may also be received when a DatagramSocket is bound to a more specific address.
Example:
DatagramSocket s = new DatagramSocket(null);
s.bind(new InetSocketAddress(8888));
Which is equivalent to:
DatagramSocket s = new DatagramSocket(8888);
Both cases will create a DatagramSocket able to receive broadcasts on UDP port 8888.\
If your two machines are located at disparate locations on the internet, and you can't use a DDNS service (like dyndns, mentioned above), then your best bet is to build a central registration server. This would be a simple server (could even be a web service) that runs at a known address on the internet. Each of your client machines would register with the central registration server, thus the central registration server would know the IP addresses of both machines. Then each machine could request the other's address via the central registration server. You'd have to put some thought into to security in order to protect against malicious "poisoning" of your registry, but otherwise, this would be fairly straight forward.
EDIT:
I just discovered JXTA. It's a set of tools for building java applications with peer-to-peer networking features. I don't have any direct experience with it, but it looks like it would accomplish what you're looking for (and probably save you a lot of work over having to build it all from scratch).
In fact, it looks like the subproject p2psockets does exactly what you want.
In Java you can compute the IP address of machine by host name, Here is the code
java.net.InetAddress inetAdd = java.net.InetAddress.getByName("www.ibm.com");
System.out.println("IP Address is : " + inetAdd.getHostAddress());
Use this code to get the changed IP address every time machine reboots