I am trying to implement a simple chat application that connects clients through a central server, with other client so they can exchange messages and files. I also need to implement a notification framework. for example, if a user signs successfully, or if a buddy of him signs in he get a notification.
Now in the RMI world how is this implemented?
I was thinking of having a remote object "connection class" that the clients call methods from it like "login in", "disconnect" etc...
And as for the notification framework classes do they have to be remote too? or can they lie in the server?
thanks
Event messaging between remote systems is a bit tricky. Here's what has to happen:
The client must register interest in the events fired on the server side. To register, the client must be remotely available to the event source object.
In order to be able the register, the client must find the server to begin with, so the server object must be remotely available to the client.
Ick, right? And that's the simple pattern for implementing remote event handling.
A few weeks ago I started a tutorial that was heade down this path -- it's right here, and I'm hoping to add something to it before the end of the week. Alas, the need to make the rent has interfered and I'm not able to add to it as quickly as I'd like.
If you can't wait, however, that's the key: both sides have to be remotely available for the messaging system to work.
that server as well as the client must be remote objects.
Let all clients implement a Remote interface.
RemoteClientIfc extends Remote {
void inform();
}
//have a remote method register() on the *Server* object which accepts RemoteClientIfc.
//c'd be something like this...
register(RemoteClientIfc client){
arrayListofClients.add(client);
}
//So client will do a look up on the remote server object and register itself.
remoteObj.register(clientInstance);
//In the remote server you
//can probably have another method to send notifications to the client.
//Run through the ArrayList and call
//inform() on each of them.
//Thus the client will receive notification.
tellClients(){
Iterator i = ....
while (i.hasNext()){
((RemoteClientIfc).i.next()).inform();
}
}
Related
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 2 years ago.
So I'm in the making of a very simple server/client complex using java. So far I have managed to figure out what happens if the client quits, because then the server receives null while listening from any input from the client.
BUT - what happens if the client is connected and the server quits for any reason... the server is supposed to wait for input from the client, but how can the client know that the server is not listening anymore? For me the clients call to the server just goes into the void... nothing happens...
Can I do something to find out when the server goes down? Time-out, ping/pong or something?
As You surely can see I'm quite new at this, I'm just curious. This was a puzzle for me ever since I attended computer science at the university.
Thanks in advance. dr_xemacs.
(I am assuming you are working with blocking server socket and socket and not with non blocking ones)
Similarly to the server, reading from streams of a closed connection will return null.
However if you instead do not want to rely on this or a scared that the connection to the server could somehow persist, you can also use time outs (check this out! ) which will throw SocketTimeoutException when the time is up and, to keep track of whether the server is up or not, create a ping/packet to assure server is still up and running.
Edit: I did a quick search and this could be useful to you! Take a look!
How can the client know that the server is not listening anymore?
If the client doesn't attempt to interact at some level with the service, it won't know.
Assuming that the client has sent a request, a few different scenarios.
If the service is no longer listening on the designated port, the client will typically get a "Connection Refused" exception.
If the service is still running (in a sense) but it is not working properly, then connection attempts from the client are likely to time out.
If the service's host is down, the client liable get a timeout.
If there are network connectivity or firewall issues, the client could get a timeout or some other exception.
Can I do something to find out when the server goes down? Time-out, ping/pong or something?
You attempt to connect and send a request. If it fails or times out, that means the service is down. If you are designing and implementing the service yourself, you could include a special "healthcheck" request for clients to "ping" on. But the flip-side is that network and server resources will be consumed in receiving and responding to these requests. It can affect your ability to scale up the number of clients, for example, if each client pings the service every N seconds.
But a client typically doesn't need to know whether the service is up or down. It typically only cares that service responds when it it sends a real request. And the simplest way to handle that is to just send the request and deal with the outcome. (The client code has to deal with all possible outcomes anyway when doing a real request. The service can go down, etc between the last healthcheck ping and when the client sends a real request.)
Bottom line: Don't bother with checking availability in the client unless the application (i.e. the end user) really needs to know.
Your Server probably may be running on a certain port and so you can add a health check at the client side and update a global flag with status to let client know about its availibity :-
Socket socket = null;
try
{
socket = new Socket(host, port);
return true;
}
catch (Exception e)
{
return false;
}
finally
{
if(socket != null)
try
{
socket.close();
}
catch(Exception e){}
}
I have a problem, and I don't know exactly what to search for.
I have a spring boot app which broadcast the message via web socket with a stomp javascript client. The question is if I can put a lock on the message when it is sent because I want no one to send another message at the same time. The system that I want to make is like a traffic light.
If you can give me an example or what to look for.
You should use synchronized keyword and wait for the client response. synchronized keyword ensures that only one thread can execute the method at the same time. And you need client response because you can sequentially send two messages, say in two seconds interval, but your client will get them at the same time. Response can be some dummy ok-message.
public class Traffic {
synchronized void Send() {
// write message to websocket
// read response from websocket
}
}
So I've tried to send players to the lobby server when they type "/lobby" by using this code:
Bukkit.getServer().dispatchCommand((Player) player, "server lobby");
But in game, it returns "Unknown Command. Type "/help" for help."
I've also read to try this code, but I don't know what to put in place of "a", "b", and "c"
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("a");
out.writeUTF("b");
//applies to the player you send it to. aka Kick To Server.
Player player = Bukkit.getPlayerExact("c");
player.sendPluginMessage(this, "BungeeCord", out.toByteArray());
So my question is why does the first method not work? Also, how do you make the second solution work? Is there code I need to put in the bungee server?
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF("ServerName");
player.sendPluginMessage(PluginObject, "BungeeCord", out.toByteArray());
This is what you are looking for. To answer your question, "a" is always "Connect". "b" is the name of the server that you want to connect to (In your case this is "lobby"), and "c" will the name of the player (This is because in the example that you've supplied your getting the player by their name, however if you've already got the player object, this isn't needed).
And just so that you understand why dispatchCommand doesn't work, it's because when you do /server on your client it sends a packet to the Bungeecord as that's what your client is connected to, and it will intercept that command packet read it and see that it's a server command. It will then proceed to connect you to the right server. If you use dispatchCommand on the Bukkit server it will execute the command as though it just received an command packet, which means it never sends out any sort of message to the bungeecord or to the client to get it to execute a command. The dispatchCommand method will only be run on the bukkit server.
The reason that the second solution works is because in the Minecraft protocol there's this thing called the plugin messaging channel, for custom messages between the client and the server. And yet again as the Bungeecord sits in the middle of the client and the server, it listens on certain messages, and any of them tagged with Connect will connect a player to the specified server. I hope this makes sense.
I have a couple different very complex Netty 4 based processes that have lots of incoming and outgoing connections. In a certain case, I have about a dozen running on one machine.
I have my own handler and pipeline, and in the handler, I query the ChannelHandlerContext to log the remote end of a set of requests.
Normally I do something like this:
public void handle(ChannelHandlerContext ctx, HttpRequest request){
System.out.println(ctx.getChannel().getRemoteAddress());
}
In this case, the remote address is of type EmbeddedSocketAddress, and returns just "embedded".
In normal cases, I can get the IP/Port from the InetSocketAddress and use lsof to find out who's making the call. In this case, I can't.
How can I find out what/who is calling into my handler?
Ok, so I found out where these are coming from. The framework that creates my pipeline runs a "warm up" routine that injects these requests right into the pipeline without a remote end. I apologize for my idiocy.
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.