Java RMI for remote ip (host) - java

I am newbie. I cannot understand RMI correctly. There are tons of tutorials available on the internet ,but all of them are for the local host as I can understand. Both server and client run on the same machine.
I want to run client on any machine and the host will be on the one computer lets consider IP - 11.11.11.11. On the 1099.
But how can I achieve this, where should I specify my IP on the client side. As I understand naming convertion is used, like DNS but anyway when I need to connect to some machine remotely I need to know at least IP address (+mask) and port.
I guess I missed something really important.
Please give some example how to configure RMI remotly not on the same host.

First you have to setup a server whose method or object can be accessed by any remote client
Below is example code for the server.
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyCalc extends Remote{
int add(int a, int b) throws RemoteException;
}
import java.rmi.RemoteException;
public class MyCalcImpl implements MyCalc {
#Override
public int add(int a, int b) throws RemoteException {
return (a + b);
}
}
Start the rmi registry on server machine so you can register your object to this registry and better you run it where you have placed your classes otherwise you will get ClassNotFound.
rmiregistry 1099
Note: you might need to change the port if port is already in use.
Register you object to rmi registry with name 'calculator'.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class MyRMIServer {
public static void main(String[] args) throws Exception {
System.setProperty("java.security.policy","file:///tmp/test.policy");
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String name = "Calculator";
MyCalc engine = new MyCalcImpl();
MyCalc stub = (MyCalc) UnicastRemoteObject.exportObject(engine, 0);
Registry registry = LocateRegistry.getRegistry(1099);
System.out.println("Registering Calculator Object");
registry.rebind(name, stub);
} catch (Exception e) {
System.err.println("Exception:" + e);
e.printStackTrace();
}
}
}
Note: To run the program you have to setup a security policy file and for that creat a file e.g. test.policy and copy below content.
grant {
permission java.security.AllPermission;
permission java.net.SocketPermission "localhost:1099", "connect, resolve";
permission java.net.SocketPermission "127.0.0.1:1099", "connect, resolve";
permission java.net.SocketPermission "localhost:80", "connect, resolve";
};
You can change IP and port as per your case.
After starting the server, suppose your server's IP address is 11.11.11.11 then you can invoke the MyCalc's add() on the server. So on your client machine your client code would be like:
Copy the MyCalc class from server to client machine so you can set it to the classpath while compiling client's code.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class MyRMIClient {
public static void main(String args[]) {
System.setProperty("java.security.policy","file:///tmp/test.policy");
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
String name = "Calculator";
String serverIP = "11.11.11.11"; // or localhost if client and server on same machine.
int serverPort = 1099;
Registry registry = LocateRegistry.getRegistry(serverIP, serverPort);
MyCalc mycalc = (MyCalc) registry.lookup(name);
int result = mycalc.add(10, 20);
System.out.println("Result:" + result);
} catch (Exception e) {
System.err.println("ComputePi exception:");
e.printStackTrace();
}
}
}
compile and test the client's code.
EDIT: edited to remove dependency on rmi compiler (rmic)

You only have to specify the server's IP address in one place: the lookup string supplied to Naming.lookup().
[Unless you have the Linux problem referred to in the RMI FAQ item A.1.]

Related

How to give certificate to Java Websocket?

Forgive me for the newb question, but I am confused and obviously not understanding the fundamentals or explanations of how to use a Websocket server hosted over HTTPS. Everything I find online leads me to have more questions than answers.
I have a Websocket server hosted on my HTTPS website using Java code.
This is my WebsocketServer.java file:
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class WebsocketServer extends WebSocketServer {
private static final Logger logger = LogManager.getLogger(WebsocketServer.class);
private static int TCP_PORT = 6868;
private static Set<WebSocket> conns;
public WebsocketServer() {
super(new InetSocketAddress(TCP_PORT));
conns = new HashSet<>();
}
#Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
logger.info("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
logger.info("Size of connection list: " + conns.size());
}
#Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
logger.info("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onMessage(WebSocket conn, String message) {
logger.info("Message from client: {}", message);
// for (WebSocket sock : conns) {
// sock.send("SENDING BACK" + message);
// }
}
#Override
public void onError(WebSocket conn, Exception ex) {
// ex.printStackTrace();
try {
if (conn != null) {
conns.remove(conn);
// do some thing if required
}
logger.info("ERROR from {}", conn.getRemoteSocketAddress().getAddress().getHostAddress());
} catch (Exception e) {
logger.info("onError: WebSocketServer may already be running");
}
}
public Set<WebSocket> getConns() {
return conns;
}
}
Then I started the WebsocketServer like this:
WebsocketServer websocketServer;
// Start socket server
websocketServer = new WebsocketServer();
websocketServer.start();
And on the client side, I connect to it like this:
// APP_WEB_SOCKET is the url to my site: api.my_custom_domain.com
var connection = new WebSocket("wss://" + APP_WEB_SOCKET + ":6868");
QUESTIONS:
I keep reading that I need a certificate if I want to use wss over HTTPS, but cannot find any documents that explain what this means in a way that I can understand.
My app is hosted in AWS Elastic Beanstalk environment. Do I need to somehow add a certificate to the setup of the WebsocketServer in my Java code?
Example:
WebsocketServer websocketServer;
// Start socket server
websocketServer = new WebsocketServer();
// example guessing
websocketServer.cert = "SOMETHING";??
websocketServer.start();
Does the client code need to be changed at all?
Who needs the certificate?
If someone could please explain what I am missing or point me in the correct direction, I would really appreciate it.
Keep it easy.
Certs inside your application are complex - they are hard to manage and you will get problems to run your application in a modern cloud environment (start new environments, renew certs, scale your application, ...).
Simple conclusion: Dont implement any certs.
How-to get encrypted connections?
As Mike already pointed out in the comments: WebSockets are just upgraded HTTP(S) connections. A normal webserver (nginx, apache) takes care about the certs. It can be done in kubernetes (as ingress-controller) or with a "bare-metal" webserver.
Both of them should act as a reverse-proxy. This means: Your java-application doesn't know anything about certs. It has just unencrypted connections - like in your code on port 6868.
But the client will not use this port. 6868 is only internally reachable.
The client will call your reverse-proxy at the normal HTTPS port (=443). The reverse-proxy will forward the connection to your java-application.
Here some links for further information:
nginx reverse-proxy
nginx reverse-proxy for websocket
tutorial for java behind reverse-proxy
LetsEncrypt for automatic and free certs

Java unknownhostException with two computers

import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
public class ChatClient{
private final String serverName;
private final int serverPort;
private Socket socket;
private InputStream serverIn;
private OutputStream serverOut;
public ChatClient(String serverName, int serverPort) {
this.serverName = serverName;
this.serverPort = serverPort;
}
public static void main(String[] args){
ChatClient client = new ChatClient("raspberrypi", 6342);
if (!client.connect()){
System.err.println("Connect failed");
}else{
System.out.println("Connected");
}
}
private boolean connect(){
try{
this.socket = new Socket("raspberrypi", 6342);
this.serverOut = socket.getOutputStream();
this.serverIn = socket.getInputStream();
return true;
}catch (IOException e){
e.printStackTrace();
}
return false;
}
}
I have a server which I am running which is waiting for an client to join. However since I am using the client on my computer and the server on my raspberry pi, I keep getting the unknown host exception. I have tried to put the hostname of the raspberry pi in but it doesn't seem to work. P.s I might be getting the host name wrong.
It does not work, because the value you provide to the first argument (raspberrypi) is not a valid host name.
You need to pass there the IP address of your raspberry in your network.
If you are using home router, you can even set static IP for your raspberry (it's common, because without that, every time you restart your raspberry, you may get different address from DHCP server).
After you know the address of your raspberry, simply replace "raspberrypi" with the address (in form of "192.168.0.10" depending on your configuration).
Here's how to set static IP: https://www.raspberrypi.org/learning/networking-lessons/rpi-static-ip-address/
Edit the file /etc/dhcpcd.conf as follows:
Type sudo nano /etc/dhcpcd.conf at the command prompt.
Scroll to the bottom of the script, and add the following lines:
interface eth0
static ip_address=192.168.0.2/24 static routers=192.168.0.1 static
domain_name_servers=192.168.0.1
interface wlan0
static ip_address=192.168.0.2/24 static routers=192.168.0.1 static
domain_name_servers=192.168.0.1
Save the file with ctrl + o and then
exit nano with ctrl + x. Your Raspberry Pi will now boot up with the
IP address 192.168.0.2 every time; we didn't use 192.168.0.1 as this
is reserved for the router. You can of course use any address you
like, but in the configuration above the range must be between
192.168.0.2 and 192.168.0.255.

Connection refused to host exception in java RMI [duplicate]

I have written following code for the client of RMI. But getting
java.rmi.ConnectException: Connection refused to host: localhost; nested
exception is:
java.net.ConnectException: Connection refused: connect
code :
import java.rmi.*;
import java.net.*;
import java.rmi.registry.*;
class client
{
public static void main(String [] ars)
{
Iface serv;
Registry r;
String serveraddr = ars[0];
String serverport = ars[1];
String text = "Hey jude";
System.out.println("Sending" + text);
try{
r = LocateRegistry.getRegistry(
serveraddr,
(new Integer(serverport)).intValue()
);
serv = (Iface) r.lookup("rmi://server");
serv.receive(text);
}
catch(Exception e){
System.out.println(e);
}
}
}
If you're getting that on bind, rebind, or lookup, the Registry isn't running. If you get it doing the remote call, see item A.1 in the RMI FAQ supplied with the Javadoc, and if you're running Linux also check that your /etc/hosts file maps 127.0.0.1 to localhost and your real ip address to your real hostname - this has been a common problem in some Linux distributions.
I met the same problem. It's silly but just that I forgot to start the RMI registry process.
So, you also need to run RMI Registry process
rmiregistry
Before you try to rebind(address, obj) with RMI registry.

RMI programme: Client side giving Error

I am creating RMI program for my class assignment in Netbeans. It is a simple RMI program and The server side is working properly. But as I run my client side file. It ends up giving me error
Exception in thread "main" java.security.AccessControlException: access denied ("java.net.SocketPermission" "127.0.0.1:1099" "connect,resolve")
plus it is saying some error at line 26 at client code.
For clear understanding I am giving full code of all three files.
Interface.java :
package RMI;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface DemoInterface extends Remote {
public String SayDemo() throws RemoteException;
}
Server.java
package RMI;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class Server implements Interface{
public Server()
{
super();
}
private String message;
public Server(String msg) throws RemoteException
{
message = msg;
}
public static void main(String[] args) {
try {
DemoInterface h = new Server("Hello");
DemoInterface stub = (DemoInterface) UnicastRemoteObject.exportObject(h,0);
LocateRegistry.createRegistry(4096);
Registry registry = LocateRegistry.getRegistry("127.0.0.1",4096);
registry.rebind("Hello", stub);
System.out.println("Server is connected and ready to use");
}
catch(Exception e)
{
System.out.println("server not connected\n"+e);
}
}
#Override
public String SayDemo() throws RemoteException {
System.out.println("Server.saydemo override");
return message;
}
}
Client.java
package RMI;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) {
if(System.getSecurityManager() == null)
{
System.setSecurityManager(new SecurityManager());
}
try {
Registry reg = LocateRegistry.getRegistry("127.0.0.1", 4096);
System.out.println("in try after reg locate");
DemoInterface h = (DemoInterface) reg.lookup("Hello");//Error Showed on this line by netbeans
System.out.println(h.SayDemo());
}
catch(RemoteException | NotBoundException e)
{
System.out.println(""+e );
}
}
}
please guide me where I am wrong. Thank You in advance.
You set a SecurityManager in your client main method. Did you also provide a security policy file? The default policy is not very permissive, and denies, among other things, Socket operations.
You can specify a policy that allows all permissions to all code bases like so.
grant {
permission java.security.AllPermission;
};
add it to your command line for invoking java. Substitute mypolicy for your policy file and SomeApp for your main class. Note the two = characters in the second argument
java -Djava.security.manager -Djava.security.policy==mypolicy SomeApp
Note that this is not a safe policy to run for RMI in a production environment (RMI can load remote code bases).
Proper use of the SecurityManager class and policy configuration is a complex topic, for further reading I suggest Java SE 7 Security Documentation and in particular Default Policy Implementation and Policy File Syntax

Java RMI : connection refused

I have written following code for the client of RMI. But getting
java.rmi.ConnectException: Connection refused to host: localhost; nested
exception is:
java.net.ConnectException: Connection refused: connect
code :
import java.rmi.*;
import java.net.*;
import java.rmi.registry.*;
class client
{
public static void main(String [] ars)
{
Iface serv;
Registry r;
String serveraddr = ars[0];
String serverport = ars[1];
String text = "Hey jude";
System.out.println("Sending" + text);
try{
r = LocateRegistry.getRegistry(
serveraddr,
(new Integer(serverport)).intValue()
);
serv = (Iface) r.lookup("rmi://server");
serv.receive(text);
}
catch(Exception e){
System.out.println(e);
}
}
}
If you're getting that on bind, rebind, or lookup, the Registry isn't running. If you get it doing the remote call, see item A.1 in the RMI FAQ supplied with the Javadoc, and if you're running Linux also check that your /etc/hosts file maps 127.0.0.1 to localhost and your real ip address to your real hostname - this has been a common problem in some Linux distributions.
I met the same problem. It's silly but just that I forgot to start the RMI registry process.
So, you also need to run RMI Registry process
rmiregistry
Before you try to rebind(address, obj) with RMI registry.

Categories

Resources