Scenario:
Client C connects to Server S via RMI
C asks S to create a handler H, S returns H to C
C then talks to H
Now I could do this in two ways:
Make the handler a Remote and let S return the stub to it, so C can directly talk to that (h.say(String msg);)
Give the handler an ID and return that to C. C will talk to H via S (s.sayToHandler(int id, String msg);)
The first is nicer OO, but what about the performance? Will an extra TCP connection be opened, or is the existing connection between S and H used?
I don't know about the implementation. I don't think a new connection is made. But what I know is the more objects you share remotely the more objects that depends on remote dereference to get garbage collected (so there will be more objects living longer, not good).
Alternative approach
I'll recommend a mixed approach. Use the nice approach for the client but implement it the not-so-nice-way internally:
interface Server {
public Handler getHandler(...);
}
interface Handler extends Serializable {
// it gets copied!
public X doThis(...);
public Y doThat(...);
}
class HandlerImpl implements Handler {
public X doThis(...) {
backDoor.doThis(this, ...);
}
public Y doThat(...) {
backDoor.doThat(this, ...);
}
private BackDoor backDoor;
}
interface BackDoor {
public X doThis(Handler h, ...);
public Y doThat(Handler h, ...);
}
class ServerImpl imlpements Server, BackDoor {
public Handler getHandler(...) {
return /*a handler with a self reference as backdoor, only ONE remote obj shared via TWO interfaces */
}
...
// it does everything
// it receives the handler
}
BackDoor and Handler are sync'ed interfaces. The first has the methods with Handler as argument, the later has the pure methods. I don't think it's a big deal. And the two different interfaces let you work cleanly without the client know nothing and allowing the thin serializable Handler's do the dirty work.
Hope you like it!
The RMI specification does not really say whether there should be a new connection or the existing one reused. The wire protocol allows both, using either multiplexing or one TCP connection per call (which might be reused for following calls to the same sever object, I'm not sure). If you need tunneling through HTTP, than only one message per connection is allowed.
I did not find anything on how to configure which type of protocol to use (other than disabling HTTP tunneling).
If you want to make sure that only one TCP connection is used, use custom client and server socket factories doing the tunneling of multiple connections though one themselves. This will probably be less efficient than what the RMI runtime system would be doing there.
Related
I have a small application containing a number of classes. The application is designed to connect to a server and send / recv binary protocol msgs.
I have this part working using a connection manager class and a message processor class. The connection manager gets instantiated and creates 2 threads one to send and one to recv msgs. On receipt of a message a new message processor object is instantiated to handle the parsing of the message.
I have now created a GUI that has connect, logon etc... buttons.
The gui creates an instance of connection manager and when the connect button is presses it calls connection manager.connect.
When the logon button is pressed it calls connection manager.logon.
the connection manager object has a Boolean called connected.
so the gui can read connection manager.connected and see true/false. now what I need to be able to do is access connection manager.connected from my message processor object which gets created inside connection manager each time a message is received. So if message processor sees a logon ack message it can set connection manager.connected = true and the GUI which created the connection manager object can read the value.
However I cant see how I can access connection manager.connected from the message processor object. I think this is possibly a flaw in my design?
code examples.
GUI creates connection manager object reading in GUI text fields
cm = new ConnectionManager(jTextField1.getText(), jTextField2.getText())
Connection Manager has a Boolean connected. It also creates a read and write from network thread
public boolean connected;
executor.execute(new MessageProcessor(header, message, msgType));
Inside MessageProcessor I want to update cm.connected - is this possible?
Thanks
Did you create the MessageProcessor yourself? If so you could add a parameter in constructor and send a reference to the ConnectionManager:
executor.execute(new MessageProcessor(header, message, msgType, this));
Then the MessageProcessor will be able to access connected through ConnectionManager.
MessageProcessor should hold a reference to its calling ConnectionManager. You can pass the reference in the constructor of MessageProcessor and store it in an instance variable:
public class MessageProcessor {
private ConnectionManager cm;
public MessageProcessor(ConnectionManager cm) {
this.cm = cm;
}
public void process() {
cm.setConnected(false);
}
}
instantiating a MessageProcessor:
public class ConnectionManager {
public void connect() {
MessageProcessor pm = new MessageProcessor(this);
}
public void setConnected(boolean connected) {
this.connected = connected;
}
}
of course you have coupled MessageProcessor and ConnectionManager. There are (rather) complex solutions that allow you to "decide" at run time between implementations of MessageProcessor and ConnectionManager. These include the factory patter and dependency injection.
how are you planning to access cm from your MessageProcessor object? it's also about the communication between objects. If you have only one ConnectionManager for your send/receive threads and if you always have one pair of threads (send/receive), you can simply use public static boolean connected and upon establishing a connection you can set it to true. This is not a good solution of you have multiple thead-couples (for send/receive activities). I almost forgot until someone pointed it out, you can pass on a parameter this - reference to who is calling MessageProcessor constructor. However, this is still not very good as any change in class definition will hurt the implementation in MessageProcessor.
In simple word, yes it is possible to access/mutate connected from your MessageProcessor - you should also consider using synchronized methods to access/mutate connected. But if you need to make the solution better, you need to consider using individual connectionManager objects. #sharonbn has already shown you some examples of how to go about doing this.
I have a certain problem: I'm using RMI to communicate between server and client.
public class RemoteMap
extends java.rmi.server.UnicastRemoteObject
implements RemoteMapInterface {
private TreeMap<String, GeneralSprite> sprites;
...
This is my remote object. But I want the client to be able to change this object's content. And after the change the server can execute some operation based on this.
Example at the client side:
map = (RemoteMapInterface) (registry.lookup("map"));
map.getSprites.get("object1").setDx(-1);
I'm using serialiable on the GeneralSprite, but I guess it passed by value. So when I did some changes at the GeneralSprite, it wasn't transported to the server . Do I have to make GeneralSprite to an Remote object too? Or is it even possibly?
Thanks in advance, and sorry for my bad english, I hope you can understand.
Everything which does not implement the Remote interface, whether directly or indirectly, will get serialized for the remote method invocation. So it’s a “call-by-copy” behavior. You can implement a new Map which implements Remote, but you can also add a method like setDx(String spriteName, int value) to your RemoteMapInterface and implement it as sprites.get(spriteName) .setDx(value); on the server side.
I am creating a instant chat application using RMI. The server sends through certain objects which I need the client to handle.
For example the server will send a JoinedGroupOperation class. In my client application I need to recognise the class and let my handler take over (HandleJoinedGroupOperation). This class will do a bunch of stuff on the client side.
My question is how can I handle classes that come from the server so I don't need to do any if statements? ie
if(server.getResponse() instanceof JoinedGroupOperation){
HandleJoinedGroupOperation handle = new HandleJoinedGroupOperation();
handle.foo();
}
One of the possible option in your case is to use chain of responsibility design patern.
You should create some abstraction of your possible handlers(like HandleJoinedGroupOperation), then link those handlers(preferebly at start time). As a example, create an interface
interface OperationHandler {
void handle(Operation op);
}
where Operation is also a basic type for all possible operations. This type(Operation) can contain a field of enum type OperationType:
enum OperationType {
...
}
Then in the concrete handlers you can simply check this field(although it will contain if statement, but those statements will be encapsulated in each specific handler)
As a simple example, here is a default implementation of a handler
class SimpleHandler implements OperationHandler {
private OperationHandler next;
public void handle(Operation op) {
if (op.getType() == OperationType.SOMEYOURTYPE) {
//do some stuff
} else {
next.handle(op);
}
}
}
In this case your server.getResponse() method simply will return basic type of Operation hierarchy
Also read the article to get more information
I am in the process of moving the business logic of my Swing program onto the server.
What would be the most efficient way to communicate client-server and server-client?
The server will be responsible for authentication, fetching and storing data, so the program will have to communication frequently.
it depends on a lot of things. if you want a real answer, you should clarify exactly what your program will be doing and exactly what falls under your definition of "efficient"
if rapid productivity falls under your definition of efficient, a method that I have used in the past involves serialization to send plain old java objects down a socket. recently I have found that, in combination with the netty api, i am able to rapidly prototype fairly robust client/server communication.
the guts are fairly simple; the client and server both run Netty with an ObjectDecoder and ObjectEncoder in the pipeline. A class is made for each object designed to handle data. for example, a HandshakeRequest class and HandshakeResponse class.
a handshake request could look like:
public class HandshakeRequest extends Message {
private static final long serialVersionUID = 1L;
}
and a handshake response may look like:
public class HandshakeResponse extends Message {
private static final long serialVersionUID = 1L;
private final HandshakeResult handshakeResult;
public HandshakeResponse(HandshakeResult handshakeResult) {
this.handshakeResult = handshakeResult;
}
public HandshakeResult getHandshakeResult() {
return handshakeResult;
}
}
in netty, the server would send a handshake request when a client connects as such:
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
Channel ch = e.getChannel();
ch.write(new HandshakeRequest();
}
the client receives the HandshakeRequest Object, but it needs a way to tell what kind of message the server just sent. for this, a Map<Class<?>, Method> can be used. when your program is run, it should iterate through the Methods of a class with reflection and place them in the map. here is an example:
public HashMap<Class<?>, Method> populateMessageHandler() {
HashMap<Class<?>, Method> temp = new HashMap<Class<?>, Method>();
for (Method method : getClass().getMethods()) {
if (method.getAnnotation(MessageHandler.class) != null) {
Class<?>[] methodParameters = method.getParameterTypes();
temp.put(methodParameters[1], method);
}
}
return temp;
}
this code would iterate through the current class and look for methods marked with an #MessageHandler annotation, then look at the first parameter of the method (the parameter being an object such as public void handleHandshakeRequest(HandshakeRequest request)) and place the class into the map as a key with the actual method as it's value.
with this map in place, it is very easy to receive a message and send the message directly to the method that should handle the message:
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
try {
Message message = (Message) e.getMessage();
Method method = messageHandlers.get(message.getClass());
if (method == null) {
System.out.println("No handler for message!");
} else {
method.invoke(this, ctx, message);
}
} catch(Exception exception) {
exception.printStackTrace();
}
}
there's not really anything left to it. netty handles all of the messy stuff allowing us to send serialized objects back and forth with ease. if you decide that you do not want to use netty, you can wrap your own protocol around java's Object Output Stream. you will have to do a little bit more work overall, but the simplicity of communication remains intact.
It's a bit hard to say which method is "most efficient" in terms of what, and I don't know your use cases, but here's a couple of options:
The most basic way is to simply use "raw" TCP-sockets. The upside is that there's nothing extra moving across the network and you create your protocol yourself, the latter being also a downside; you have to design and implement your own protocol for the communication, plus the basic framework for handling multiple connections in the server end (if there is a need for such).
Using UDP-sockets, you'll probably save a little latency and bandwidth (not much, unless you're using something like mobile data, you probably won't notice any difference with TCP in terms of latency), but the networking code is a bit harder task; UDP-sockets are "connectionless", meaning all the clients messages will end up in the same handler and must be distinguished from one another. If the server needs to keep up with client state, this can be somewhat troublesome to implement right.
MadProgrammer brought up RMI (remote method invocation), I've personally never used it, and it seems a bit cumbersome to set up, but might be pretty good in the long run in terms of implementation.
Probably one of the most common ways is to use http for the communication, for example via REST-interface for Web services. There are multiple frameworks (I personally prefer Spring MVC) to help with the implementation, but learning a new framework might be out of your scope for now. Also, complex http-queries or long urls could eat your bandwidth a bit more, but unless we're talking about very large amounts of simultaneous clients, this usually isn't a problem (assuming you run your server(s) in a datacenter with something like 100/100MBit connections). This is probably the easiest solution to scale, if it ever comes to that, as there're lots of load-balancing solutions available for web servers.
I've created a generic 'SocketServer' class in java which takes the following arguments:
String address, int port, Class socketProtocol, String encryptionType, int backlogSize
Basically, I want other developers to be able to instance this class in their projects and set some simple options for encryption, backlog, address, port.. at which point they have to design the protocol. SocketProtocol is an interface which enables sendMessage and receiveMessage (along with a few others).
At this point, the user of the class should just implement SocketProtocol and pass the class (i.e. MySocketProto.class) to the SocketServer instance, which will in turn instance a copy of the protocol for each incoming connection via .newInstance();
Does this make sense? Is there an easier way to establish this type functionality? I don't like the idea of passing the class type to the server, it just seems odd.
Thanks all,
Chris
I would use the Factory pattern in this situation. The linked Wikipedia example is a bit verbose, but it can be really simple:
public interface ISocketProtocolFactory {
ISocketProtocol buildProtocol();
}
Your SocketServer constructor would then take an instance of something implementing ISocketProtocolFactory, and ask it for new ISocketProtocols as it goes.
This will give your users a lot more flexibility in constructing the ISocketProtocol instances, take care of the 'nastiness' of having a class parameter.
I would assume that each port would have it's own protocol. With that in mind you would specify it for the port.
The way I had done it in the past is to have the implementors pass in a class that inherits from:
public Interface ProtocolInterface
{
public void serve(InputStream in, OutputStream out) throws IOException
...
where the InputStream and OutputStream are the input and outputs to the Socket