Bind address and port to RMI - java

I'm developing a chat, and firstly I was using sockets and streams to communicate between the server and client, which I already tested with my friends and it worked. Now I`m trying to convert to RMI.
So, it is working locally, but when my friend tries to connect he gets a refused connection. Weirder is that it shows the server local ip (192.168.25.28).
My code looks like this:
public void conectar() throws RemoteException, MalformedURLException, NotBoundException{
// COMUNICADOR SERVIDOR (USADO PELO CLIENTE)
comunicadorServidor = new ComunicadorServidor(id); // cria um novo comunicador
LocateRegistry.createRegistry(8081); // inicia o registro RMI na porta 8081
Naming.rebind("//:8081/ComunicadorServidor", comunicadorServidor); // vincula o objeto comunicador ao endereço RMI
// COMUNICADOR CLIENTE (USADO PELO SERVIDOR)
comunicador = (IComunicadorCliente) Naming.lookup("//" + conexao.getInetAddress().getHostAddress() + ":8082/ComunicadorCliente"); // procura o comunicador no cliente
}
So I use RMI in both server and client, and one connect to each another, because in server I have methods like Authentication and Send Message, which the cliente uses, and in the client I have methods like Update Users List and Receive Message, which the server uses.
So first I create an instance of the RMI class (server-side), create a registry on port 8081, then bind the object to port 8081 with the name "ComunicadorServidor".
And after that the server tries to connect to the client RMI.
So I read about the rebind method, and if I don't specify an address, it will bind to the local host address, which I ask: even if it's binding to my local machine, is it still available outside? If not, how can I bind it in the same away as socket, where I just specify some port and it will be available to any address, like localhost, local ip, or external ip.
And about the lookup, what is the best way to get the client IP (right now I'm taking from the socket), how can I be sure that I will get a correct IP? Can I connect to the client RMI without a socket?
And in the client side it's essentialy the same thing, except it binds the RMI class to 8082 and lookup for the RMI class in server-side with the provided IP and port.

Weirder is that it shows the server local ip (192.168.25.28).
That's correct. If you need it to appear on a public IP address you need to look up java.rmi.server.hostname, and see Item A.1 in the RMI FAQ.
So I read about the rebind method, and if I don't specify an address, it will bind to the local host address, which I ask: even if it's binding to my local machine, is it still available outside?
The Registry is available to the outside world if the server-side firewall rules so permit. Note that bind in the RMI sense just means associating a remote object with a name in the Registry: it has nothing to do with Socket.bind().
And about the lookup, what is the best way to get the client IP (right now I'm taking from the socket), how can I be sure that I will get a correct IP? Can I connect to the client RMI without a socket?
You can't 'connect' in RMI at all, but you don't need the client's IP address. The client should register its remote object with the server via a server remote method, e.g. register(Client client) throws RemoteException. Then the server has a stub on which it can call client remote methods directly (client-side firewall permitting).

Related

Should i use the same port numbers when sending data through UDP?

When we send data (in this case) to a client/server, does this really matter to use the same port number?
My guess is no, because it doesn't matter which port you are using when sending data to. (The protocol gives it to you randomly internally - this is the idea?) The only thing has to be kept, the port has to be any availabe one on the receiver machine(above 1000, because those are reserverd by the system), and if that receiver decides to send something back, he or she will have enough information about sender: his IP address, port number ect. As far as i know, a received packed provides with all of that info.
Below is just an illustration of what i've said above.
public class Server {
public static void main(String[] args) {
GameServer server = new GameSever(9822);
server.start();
InetAddress address = null;
int port = 7877;
try {
address = InetAddress.getByName("192.168.0.2");
} catch (UnknownHostException e) {
e.printStackTrace();
}
server.send(new byte[] { 1, 2, 3 }, address, port);
}
}
When a server listens on a computer, it specifies a port it wants it's connections coming in from , so ports are important for setting up servers. This is useful as you can have multiple applications listening on different ports without the different applications accidentally talking to eachother. So you should decide on a port that isn't a standard( 80 is for HTTP for example) to exclusively use for you gameserver so the client knows which port to send the requests to.
If you want to handle multiple connections at once the best thing to do is threading.
When we send data (in this case) to a client/server, does this really
matter to use the same port number? My guess is no, because it doesn't
matter which port you are using when sending data to.
Firstly, use the terms client and server distinguishly(as generally client initiates by sending the message, to which the server responds).
Next, the port which you're using is logically of no significance, the reason being server uses request.getPort() to determine the port while seding the response; (request is a DatagramPacket sent by the client).
Though you can hardcode the port at server(if known beforehand), but, it is a bad idea. What in those applications where you've no idea about who sent the datagram packet?
Java documentation by Oracle also uses an example of client-server where client's port number is left for the constructor to pick. It mentions :
Mostly, the client uses a constructor that does not require a port number. This constructor just binds the DatagramSocket to any available local port.
It doesn't matter what port the client is bound to because the DatagramPackets contain the addressing information. The server gets the port number from the DatagramPackets and send its response to that port.
MORE INFO (taken from Java Network Programming) :
public DatagramSocket() throws SocketException
This constructor creates a socket that is bound to an anonymous port. For example:
DatagramSocket client = new DatagramSocket();
Pick this constructor for a client that initiates a conversation with a server. In this scenario, you don’t care what port the socket is bound to because the server will send its response to the port from which the datagram originated. Letting the system assign a port means that you don’t have to worry about finding an unused port. If, for some reason, you need to know the local port, you can find out with the getLocalPort() method.
NOTE : The same socket can receive the datagrams that a server sends back to it(underlying implementation).
Whereas, the below constructor creates a socket that listens for incoming datagrams on a particular port, specified by the port argument :
public DatagramSocket(int port) throws SocketException
Use this constructor to write a server that listens on a well-known port.
Short answer:
Your guess is correct.
Longer answer:
Client gets a random port number when sending data to a server and each packet has a header which contains the info about client's port, ip address ect. So server can easily retreive this information and send anything back.
Whereas the server needs to be bind to a specific port in order to clients be able to send data to that server because when you use UDP, you need to specify an IP address and a port.

Java Socket: How to bind a specific local address to a Socket without a port number specified

I want to let the user have the freedom to choose a specific local address to connect to the target server since there might be customized routing policies, but want the program to pick up an ephemeral port instead of specifying one since that may need manual-test of local port availability.
I checked the constructors of "Socket" and "InetSocketAddress", it seems none of them have one to do the above task (even though it can pick up a local address and an ephemeral port simultaneously), and there is no method to do so after the initialization.
There is a construtor
public Socket(InetAddress address,
int port,
InetAddress localAddr,
int localPort)
throws IOException
that should be suitable for your requirement. If localPort is 0, the system will pick a free port.
You can create a Socket and call connect on it later.
Socket socket = new Socket(); // no idea where to connect
socket.connect(addressAndPort); // now I know.
What I do is have a TCPRegistry for testing purposes. This component takes care of aliased ports. e.g. host.port1. It gives it an ephemeral port on the server and allows the client to connect to it using the same string.
Note: to allow the client to start before the server I can ask it to pre-build these ServerSocket in the unit test.
Finally, at the end of the test, I can either check all Sockets and ServerSockets were closed, or forcefully clean them up.
It is designed for NIO, but could be adapted for plain IO TCPRegistry

Java rmi over the internet

I am developing a game in Java using RMI for all network communication. RMI allows me to call method on my server, but it is not enough for me. I also want the server to be able to spread message among connected clients.
My clients look up for the server (it's interface extends Remote) and register on it. It allows the server to know who is connected. My clients also implement an interface that extends Remote. Here is some part of my code:
Interfaces declaration:
public interface IServer extends Remote {
void connect(IClient Client) throws RemoteException, ExistingItemException;
//...
}
public interface IClient extends Remote {
public void notify(Notification Notification) throws RemoteException;
//...
}
Server side:
//int RMIPort = 1099, ServerPort = 1100;
IServer Server = new RMIServer();
IServer Proxy = (IServer) UnicastRemoteObject.exportObject(Server, ServerPort);
LocateRegistry.createRegistry(RMIPort).rebind("//" + LocalIP + ":" +
RMIPort + "/xxx", Proxy);
Client side:
//Sets the local reference to IServer and creates the IClient
setInstance(new Client(Login, (IServer) LocateRegistry.getRegistry(RemoteIP).
lookup("//" + RemoteIP + ":" + RMIPort + "/xxx")));
//Gets the IClient and makes it available for the IServer to call notify(...)
Proxy.connect((IClient) (UnicastRemoteObject.exportObject(getInstance(), 0)));
This solution works in local but doesn't when I'm trying to use it through Internet.
I have setup my router to expose my computer to a fix IP address and forward the 1099 and 1100 ports. This solution allow other developers to "lookup" my server and get a valid and usable Proxy, but it doesn't allow them to export their IClient. It seems that the JVM tries to export the object to their local network and the execution stops here.
So, I have tried to pass -Djava.rmi.server.hostname=my-external-IP JVM argument both local for my server and remote for clients. Doing so, exportObject throws a ConnectException to the remote ip instead of local one.
Forget it. Using callbacks over the Internet requires every client to configure his firewall/NAT box/whatever to allow inbound connections and probable port forwarding. Many of them aren't configurable at all, and many of them are run by net admins who just won't do it.
NB you would also have to export on a fixed port.
There is an alternative:
http://dev.root1.de/projects/simon/wiki#Why-SIMON-is-better-than-
The protocol is not compatible to RMI, but the usage is almost the same. Changing from RMI to SIMON is typically not that hard. I heared from users that switching to SIMON took just 30min.
You might think about alternative solution than using RMI, because I believe it was designed for Intranet applications (i.e. Enterprise application within a local network) not Internet.
I would suggest using a long-running TCP connection between the client and the server so at any moment the server wants to communicate back it just pushes a message to this connection.
In this case, initiating the connection will always be the client task. It is very similar to how mail clients connects to imap or pop3 server.

Netty is giving me a wrong port using TCP

I'm using Netty with Java trying to configure a TCP client. Everything is working so far, except that I'm connecting on port 1050 but when I call messageEvent.getRemoteAddress() on messageReceived() method of the handler, I'm getting the port 1500. I changed the port to 1049 but I'm still receiving 1500. This is Netty's problem or can it be the server's problem?
My hardware setup here is: this netty client running on a Java server, and several access control equipments spread through the area here. The equipments act as tcp servers and the netty as the client, that process everything the server sends and just reply to them.
The tcp server initialization is this:
private ChannelFactory fabrica;
private ServerBootstrap bootstrap;
public void iniciarServidorTCP() {
fabrica = new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
bootstrap = new ServerBootstrap(fabrica);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoderDeMensagem", new MensagemDecoderTCP());
pipeline.addLast("handlerGerente", new GerenteTCP());
pipeline.addLast("encoder de mensagem", new MensagemEncoderTCP());
return pipeline;
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.reuseAddress", true);
bootstrap.bind(new InetSocketAddress(1050));
}
Any idea why I'm getting 1500 instead of 1050? Could it be a problem with the equipment?
Every TCP connection has a source port and a destination port. When you connect to a server, the server sees the destination port as its well-known address. The client picks the source port. On either end, getting the "remote address" gets the other side's address. So when you call get remote address on the server, you get the client's address, not the server's.
Imagine you have a server with one IP address and one well-known port. Now, say you have a client machine with one IP address. If it make's four connections to the server, how can either end tell those connections apart? The answer is that the client port is different.

How a threaded server continues to listen on the post for more incoming connections?

I am going through Sun's Java tutorial. I am in the lesson about sockets. There is the following code for a simple threaded server:
import java.net.*;
import java.io.*;
public class KKMultiServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new KKMultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
The server is said to "keep listening for more incoming connections". I just don't understand how it's possible; the line serverSocket.accept() constructs a new (client) Socket object which is, according to the tutorial "bound to the same local port and has its...". Well, how is it possible that the server is communicating with the client and listening to more incoming connections on the same port? As far as I know, if a port is used for some connection it is blocked and cannot be used for more things.
So what am I getting wrong here?
Well, a socket is not one-to-one based on a port, it is unique on a tuple of (address, port). A connection - the pair of the local and remote sockets involved in the communication - is used to demux incoming data from a port to the correct socket, allowing multiple sockets on one port. See Wikipedia. In other words, the relationship of sockets to ports are N-to-1
getting multiple connections on the same port is entirely possible as each TCP connection is a (local host, local port, remote host, remote port) tuple as long as at least 1 is different the connections are distinct and won't interfere (besides bandwidth drops)
clients attempting to connect to a server generally get a port assigned from the OS that is not used currently
Listening sockets work like a receptionist in on a business's phone switch. Everyone calls the switch number, and the receptionist responds to each incoming call on the switch line by having someone else handle the call on another line. Even though the receptionist can only take one call at a time, the switch line is tied up only very briefly because it is used only to establish a connection.
[...]TCP demultiplexes incoming segments using all four values that comprise the local and foreign addresses: destination IP address, destination port number, source IP address, and source port number. TCP cannot determine which process gets an incoming segment by looking at the destination port only. Also, the only one of the [various] endpoints at [a given port number] that will receive incoming connection requests is the one in the listen state. (p255, TCP-IP Illustrated Volume 1, W. Richard Stevens)
The last sentence in the above quote is the key to understanding.
Interestingly, a socket isn't really identified by the combination of IP address and port. This is unique only in context, where the context is either a particular connection or the listening state. Only one listener socket can bind to a particular IP/port combination.
The short and sweet answer is that the port is blocked for OTHER programs and processes. Only the program that opened the port can now listen on it. BUT it can listen to many different clients on the same port.
When a client connects, it creates a unique socket. A socket is comprised of the listening IP address and port (the one you opened) AND the calling IP address and port. Because the caller's IP address and port are always unique, each socket is unique and identifiable to your listener.
Even if I connected to your program twice from the same machine, my machine would select a new and random source port for each connection -- thus ensuring that we have a unique socket each time.
Based on this link
The accept method waits until a client starts up and requests a connection on the host and port of this server (in this example, the server is running on the hypothetical machine taranis on port 4444). When a connection is requested and successfully established, the accept method returns a new Socket object which is bound to the same local port and has its remote address and remote port set to that of the client.The server can communicate with the client over this new Socket and continue to listen for client connection requests on the original ServerSocket This particular version of the program doesn't listen for more client connection requests.
Here is SO discussion which may clear confusion about how single port handles multiple client calls Port and Socket SO discussion .
To put it in simple terms, most of the webservers listen on port 8080 and multiple clients will access same port to access your website.

Categories

Resources