我正在编写Java RMI的分布式应用程序。 RMI客户端向RMI服务器注册事件处理程序/回调,服务器在需要时调用客户端的回调函数。现在的问题是,当网络连接失败时(例如,以太网电缆插入......),RMI服务器和客户端将不会被通知,并且当尝试调用客户端的注册回调函数时RMI服务器会失败.RMI服务器也无法通知RMI客户端此问题。更糟糕的是,当网络连接恢复时,RMI客户端服务仍将失去与RMI服务器的联系,因为没有人通知她重新连接。
我目前的想法是在单独的线程中在RMI客户端中实现ping()方法。 此线程可以定期唤醒并检查服务器。 如果失败,那么闹剧重新连接。
还有其他优雅的解决方案吗?希望你们能帮忙!
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyInterface extends Remote {
public int RegisterEventHandler(RemoteMyEventHandler eventHandler) throws RemoteException;
public void unRegisterEventHandler(int eventHandlerId) throws RemoteException;
}
import java.rmi.RemoteException;
import com.me.MyInterface;
public class MyInterfaceImpl implements MyInterface {
{
public void init() {
try {
//... initialize RMI server....
//....
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public int RegisterEventHandler(RemoteMyEventHandler eventHandler)
throws RemoteException {
return MyEventHandlerImp.getInstance().addHandler(eventHandler);
}
@Override
public void unRegisterEventHandler(int eventHandlerId)
throws RemoteException {
MyEventHandlerImp.getInstance().removeHandler(eventHandlerId);
}
}
//handler.notifyEventSnap(events);
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Properties;
import org.apache.log4j.Logger;
import com.me.MyInterface;
public class MyService implements NotifyHandler{
{
private MyInterface client;
private MyEventHandler myEventHandler;
private void connectToServer() {
try {
//...
Registry registry = LocateRegistry.getRegistry(rmiHost, rmiPort);
client = (MyInterface) registry.lookup(MyCInterface.class.getName());
} catch (RemoteException er) {
} catch (NotBoundException en) {
} catch (Exception en) {
}
}
private void startService(){
//Attach my event handler
if(client != null)
{
myEventHandler = new MyEventHandler();
myEventHandlerId = client.RegisterEventHandler(myEventHandler);
}
}
}
答案 0 :(得分:0)
当网络连接失败时(例如,以太网电缆拔出......),RMI服务器和客户端将不会收到通知,并且在尝试调用客户端注册的回调函数时RMI服务器会失败。
错误,是通知服务器。服务器只需要注意这一点,稍后再试。
RMI服务器也无法通知RMI客户端此问题。
客户不需要知道。
更糟糕的是,当网络连接恢复时,RMI客户端服务仍将失去与RMI服务器的联系,因为没有人通知她重新连接。
客户端不必“重新连接”。 RMI中没有连接或重新连接步骤。只要客户端的JVM和远程对象分别保持启动和导出,服务器上的存根仍然有效,并且可以继续由服务器使用。
你正在解决一个无问题。
答案 1 :(得分:-1)
您似乎部分实现了客户端/服务器会话。这是服务器可以跟踪的标记,以确保客户端有效。如果服务器与客户端通信时出错,则应终止会话并删除对客户端的所有引用。
您的服务器已在使用用于unRegisterEventHandler的整数实现会话。你应该像Map一样跟踪那些整数。如果服务器无法连接到客户端,则只需取消注册该客户端,并通过将其从映射中删除来使会话无效。服务器应删除对客户端的所有引用,并且在创建新会话之前不尝试与客户端通信。
如果客户端尝试与服务器通信,则应从服务器获取InvalidException异常。这样,客户端可以通过在catch块中调用RegisterEventHandler来尝试创建一个新会话。
我使用像你在https://code.google.com/p/umuc-team-factor/
建议的ping处理这个问题的项目与服务器的所有客户端通信都在循环的try catch块中,如
private void getSession() {
while(isRun()) {
try {
if(server == null) {
Logger.getLogger(JobClient.class.getName()).info("Server is null.");
setupServer();
}
UUID sid = server.getSession(this);
synchronized (this) {
id = sid;
}
Logger.getLogger(JobClient.class.getName()).info("Session id is " + id);
return;
} catch (RemoteException ex) {
Logger.getLogger(JobClient.class.getName()).info("Could not get session from server: " + ex + ". setting up server.");
setupServer();
}
}
}
尝试设置与服务器的会话,直到程序停止。
如果抛出RemoteException,则与客户端的所有服务器通信都应该结束客户端的会话。 c.status()类似于ping。
List<UUID> endSessions = new ArrayList<UUID>();
for (UUID id : copy.keySet()) {
ClientCallback c = copy.get(id).client;
try {
ClientStatus status = c.status();
Logger.getLogger(ProcessManager.class.getName()).info("got client status for " + id + ": " + status.getSessionID() + " -" + status.getJobStatus());
if (status.getSessionID() == null || !status.getSessionID().equals(id)) {
endSessions.add(id);
}
} catch (Exception ex) {
endSessions.add(id);
Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
for (UUID id : endSessions) {
try {
endSession(id);
} catch (SessionExpiredException ex) {
Logger.getLogger(ProcessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}