回调时的RMI连接失败检测

时间:2014-03-13 03:47:57

标签: java rmi

我正在编写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;
}

RMI服务器实施

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);

RMI客户端实现

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);

            }
    }
}

2 个答案:

答案 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);
    }
}