0

異なるマシンにクライアントとサーバーがあります。

クライアントでオブジェクトを逆シリアル化しようとすると、この例外が発生します。

java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: task.MyTask

ここに私のサーバーコードがあります:

System.setProperty("java.security.policy", "all_policy.policy");
System.setSecurityManager(new RMISecurityManager());
        try
        {
            mngr = new Manager();
            registry = LocateRegistry.createRegistry(15120);

            TaskDistributor stub = (TaskDistributor) UnicastRemoteObject.exportObject(mngr, 0);
            registry.rebind("Manager", stub);
        }
catch (Exception e)
        {
            System.out.println ("Ошибка при инициалиазации RMI: " + e.getMessage() + "\n");
            e.printStackTrace();
        }
...

try
    {
        //when creating a new task
        mngr.setTask(task);
    }
    catch (Exception e)
    {
        System.out.println ("Ошибка при передаче задания: " + e.getMessage() + "\n");
        e.printStackTrace();
    }

そして、ここにクライアントがあります:

try
{
    //msg.getMessage() = MyTask.class.getClassLoader().getResource("").getPath() called on server machine
    System.setProperty("java.rmi.server.codebase", "file://" + server + msg.getMessage());
    Registry registry = LocateRegistry.getRegistry(server, 15120);
    TaskDistributor mngr = (TaskDistributor) registry.lookup("Manager");
    cg.append("Задание получено\n");

    MatrixMultiplier task = mngr.getTask(); //<------------Exception here
    task.multiply();

    mngr.setTask(task);

    client.sendMessage(new ChatMessage(ChatMessage.TASK_COMPLETED, ""));
}
catch (Exception e)
{
    System.out.println ("Ошибка: " + e.getMessage());
    e.printStackTrace();
}

同じローカルマシンで使用すると機能するため、リモートクライアントJVMがサーバークラスファイルにアクセスできないか、間違ったパスを使用していると思います。

msg.getMessage() はこれを返します: /C:/Projects/IDEA/KachNetworkLab/out/production/server/

どんな提案でも大歓迎です。

解決:

この HttpServer は私にとってはうまくいきました。多分他の誰かがこれが便利だと思うでしょう...

HttpServer httpServer = HttpServer.create(address, 10);
httpServer.createContext("/", new HttpHandler() {
            @Override
            public void handle(HttpExchange t) throws IOException {
                try {
                File f = new File(t.getRequestURI().toString().substring(1).replace("\\", "/"));
                    System.out.println(t.getRequestURI().toString().substring(1).replace("\\", "/"));
                    if (!f.exists())
                    {
                        StringBuilder response = new StringBuilder().append("No luck :(");
                        t.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.toString().getBytes().length);
                        t.getResponseBody().write(response.toString().getBytes());
                        t.getResponseBody().close();
                        t.close();
                        return;
                    }

                    t.sendResponseHeaders(HttpURLConnection.HTTP_OK, f.length());
                    InputStream file = new FileInputStream(f);
                    sendFile(file, t.getResponseBody());
                    t.getResponseBody().close();
                    t.close();
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
        });

        httpServer.setExecutor(null);
        httpServer.start();

クライアントで呼び出すSystem.setProperty("java.rmi.server.codebase", "http://" + IP + ":8000" + project root path on server);と、RMI にリモート コードベース パスが提供されます。

MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()たとえば、を呼び出すことで、サーバー上のルートパスを取得できます 。

ただし、注意が必要です。このようにして、誰でもサーバー マシン上の任意のファイルにアクセスできます。ハンドルにいくつかのセキュリティ条件を書き込むか、ポリシー ファイルを変更することをお勧めします。

4

1 に答える 1

2

問題は、クライアントでfile:、JVM にローカル ファイル システムでクラスを探すように指示する URI を指定していることです。これは、サーバーと同じ実際のマシンでクライアント JVM を実行している場合に機能しますが、クライアントが別のマシンからクラスをダウンロードできるようにする場合は、クライアントがアクセスできる何らかの URI を指定する必要があります。ネットワーク。マウントされたネットワーク共有を使用してこれを行うこともできますが、標準的な方法は、jar (またはベア クラス ファイル) を HTTP 経由で利用できるようにすることです。動的コードのダウンロードに関する Oracle テクニカル ノートには、詳細な説明といくつかの例があります。

RMI サーバーを他のサービスと通信せずに「スタンドアロン」で実行できるようにする場合は、ランダムなポートにバインドする Web サーバーをそのサーバーに組み込み、クライアントが RMI メソッドを取得して、ダウンロード用のサーバーからの URI。

于 2013-11-10T06:12:29.997 に答える