- Tạo ứng dụng Spring Boot bằng Spring Launchizr
- Cấu hình Cassandra trong Spring Boot
- Định cấu hình nhóm kết nối Tomcat trên Spring Boot
- Định tuyến tin nhắn Camel đến Artemis được nhúng bằng WildFly
RMI: Gọi phương thức từ xa, chỉ áp dụng cho ngôn ngữ Java. Nói cách khác, ngôn ngữ được sử dụng trên mỗi máy tính phải là Java.
Cơ chế thực hiện: Về phía cục bộ (máy khách), thứ được vận hành trực tiếp là bản sao cục bộ của giao diện máy chủ (được gọi là sơ khai) và sơ khai đóng vai trò là giao diện máy chủ. Ví dụ: nếu đối tượng L của máy khách gọi phương thức() trong giao diện máy chủ R, thì nó không thể được viết trực tiếp dưới dạng L.method() ở phía máy khách. Do đó, trước tiên bạn phải tạo một bản sao cục bộ của giao diện R (nghĩa là sơ khai) của máy chủ trước khi ghi nó vào L.method(). Có thể thấy rằng trong quá trình giao tiếp RMI, giao diện máy khách sử dụng sơ khai và máy chủ cũng thiết lập khung đối tượng phụ trợ để tạo điều kiện thuận lợi cho việc tổ chức và quản lý các giao diện khác nhau của máy chủ và tạo điều kiện giao tiếp với máy khách. Nghĩa là, quá trình giao tiếp RMI thực sự liên quan đến sự tương tác trực tiếp giữa sơ khai máy khách và khung máy chủ, như thể hiện trong hình bên dưới.
1 Máy khách và máy chủ trao đổi thông tin qua Socket.
a Trước tiên, máy khách xác định tên giao diện được yêu cầu dưới dạng một chuỗi ("remote.procedure.call.server.RMIService"), sau đó phân tích chuỗi này thông qua phản chiếu để lấy tên giao diện, tên phương thức và phương thức được yêu cầu . Các tham số và thông tin khác, đồng thời gửi thông tin này đến máy chủ thông qua luồng đối tượng ObjectOutputStream.
b Máy chủ phân tích từng thông tin này và gọi phương thức được yêu cầu trên máy chủ thông qua phương thứcgọi() trong phản ánh.
2 Vì máy chủ có thể có nhiều giao diện cung cấp phương thức nên máy chủ cần có một "trung tâm đăng ký dịch vụ" để quản lý thống nhất các giao diện này; khi máy khách yêu cầu một giao diện nhất định, "trung tâm đăng ký dịch vụ" có thể lấy và cung cấp ngay giao diện đó. . Trong số đó, "trung tâm đăng ký dịch vụ" có thể là Bản đồ, trong đó Key lưu tên giao diện và value là đối tượng giao diện của phương thức phản hồi.
3. Theo yêu cầu của khách hàng, "Trung tâm đăng ký dịch vụ" tìm giao diện tương ứng (thông qua map.get (tên giao diện)) và cung cấp các phương thức thông qua lớp triển khai của giao diện (nghĩa là thực thi các phương thức trong lớp triển khai ).
4 Sau khi dịch vụ hoàn thành, máy chủ chuyển giá trị trả về cho máy khách thông qua đối tượng.
5 Vì các dịch vụ khác nhau trả về các loại dữ liệu khác nhau cho máy khách nên máy khách cần nhận giá trị trả về từ máy chủ thông qua proxy động.
package rmi.server; // Trên máy chủ, giao diện cung cấp các dịch vụ giao diện công cộng RMIService { String sayHi(String name });
package rmi.server; // Trên máy chủ, lớp triển khai cung cấp giao diện dịch vụ public class RMIServiceImpl triển khai RMIService { @Override public String sayHi(String name) { return "hi," + name;
gói rmi.server; /** * @className: ServerCenter * @description: Giao diện trung tâm đăng ký dịch vụ * @date: 14/5/2022 * @author: cakin */ giao diện công cộng ServerCenter { // Bắt đầu dịch vụ void start() ; // Đóng dịch vụ void stop(); // Đăng ký thanh ghi dịch vụ void(Class service, Class serviceImpl);
gói rmi.server; nhập java.io.IOException; nhập java.io.ObjectInputStream; nhập java.io.ObjectOutputStream; nhập java.lang.reflect.Method; nhập java.net.Socket; nhập java.util.HashMap; nhập java.util.concurrent.ExecutorService; java.util.concurrent.Executors; // Lớp triển khai trung tâm đăng ký dịch vụ public class ServerCenterImpl triển khai ServerCenter { // map: Tất cả các giao diện trên máy chủ mà máy khách có thể truy cập được đã đăng ký trong bản đồ // key: tên của giao diện ( Chẳng hạn as "RMIService"), value: lớp dịch vụ thực (chẳng hạn như lớp RMIServiceImpl) Private static HashMap serviceRegiser = new HashMap<>(); Số cổng của máy chủ Private static int port; // Nhóm luồng: Có nhiều đối tượng luồng trong nhóm luồng, mỗi đối tượng luồng có thể xử lý một yêu cầu của khách hàng riêng tư ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors ( )); // Có nên mở dịch vụ boolean tĩnh dễ bay hơi riêng tư isRunning = false; public ServerCenterImpl(int port) { this.port = port; } // Khởi động dịch vụ máy chủ @Override public void start() { ServerSocket server = null; try { server = new ServerSocket(); (); } isRunning = true; // Mỗi khi máy khách yêu cầu một yêu cầu, máy chủ sẽ khởi động một đối tượng luồng từ nhóm luồng để xử lý while (true) { // Nội dung dịch vụ cụ thể: nhận yêu cầu của khách hàng, xử lý yêu cầu và trả về kết quả System.out.println("Dịch vụ đã bắt đầu..."); Socket socket = null; } Catch (IOException e) { e.printStackTrace(); } // Bắt đầu một luồng để xử lý các yêu cầu của khách hàng executor.execute(new ServiceTask(socket)); } } // Đóng dịch vụ @Override public void stop() { isRunning = false; executor.shutdown(); } // Tương ứng giữa tên giao diện và lớp triển khai giao diện, để khi nhận được yêu cầu, có thể lấy lớp triển khai dịch vụ tương ứng trong time @Override public void register(Class service, Class serviceImpl) { serviceRegiser.put(service.getName(), serviceImpl); } // Thread xử lý các yêu cầu lớp tĩnh riêng tư ServiceTask triển khai Runnable { socket public; ServiceTask() { } public ServiceTask(Socket socket) { this.socket = socket; } // Logic xử lý cụ thể @Override public void run() { ObjectOutputStream input = null; tham số của phần cuối (tên giao diện, tên phương thức, loại tham số, giá trị tham số) input = new ObjectInputStream(socket.getInputStream()); // Bởi vì ObjectInputStream()); Có những yêu cầu nghiêm ngặt về thứ tự gửi dữ liệu, vì vậy nó phải được nhận từng cái một theo thứ tự gửi // Tên giao diện được yêu cầu String serviceName = input.readUTF(); // Tên phương thức được yêu cầu String MethodName = input.readUTF(; ); // Loại tham số Phương thức yêu cầu Class[] tham sốTypes = (Class[]) input.readObject(); // Tên tham số phương thức yêu cầu Object[] đối số = (Object[]) input.readObject(); yêu cầu của khách hàng, tới bản đồ trung tâm đăng ký dịch vụ Tìm giao diện cụ thể tương ứng (nghĩa là RMIService) Class ServiceClass = serviceRegiser.get(serviceName); // Xây dựng phương thức được yêu cầu Method Method = ServiceClass.getMethod(methodName, tham sốTypes); // Thực thi phương thức Object result = Method. (ServiceClass.newInstance(), đối số); // Trả về giá trị trả về sau khi thực thi cho máy khách out = new ObjectOutputStream(socket.getOutputStream()); đầu ra.writeObject(kết quả); } bắt (Ngoại lệ e) { e.printStackTrace(); } cuối cùng { thử { if (output != null) out.close(); ; } bắt (Ngoại lệ e) { e.printStackTrace();
gói rmi.client; nhập java.io.ObjectInputStream; nhập java.io.ObjectOutputStream; nhập java.lang.reflect.InvocationHandler; nhập java.lang.reflect.Method; .InetSocketAddress; nhập java.net.Socket; lớp công khai RMIClient { /** * Mô tả chức năng: Lấy đối tượng proxy động (RMIService) đại diện cho giao diện máy chủ * * @param serviceInterface: tên giao diện được yêu cầu * @param addr: ip: cổng của máy chủ được yêu cầu * @author cakin * @date 2022/5/14 * / @SuppressWarnings("unchecked") public static T getRemoteProxyObj(Class serviceInterface, InetSocketAddress addr) { /* Trong newProxyInstance(a,b,c), ý nghĩa của hai tham số đầu tiên như sau: a: Trình nạp lớp: Trình nạp lớp của đối tượng cần được ủy quyền b: Được sử dụng để chỉ ra những phương thức nào được đối tượng cung cấp cần phải được ủy quyền. Java có tính kế thừa đơn và triển khai nhiều giao diện. Do đó, nếu một đối tượng triển khai nhiều giao diện thì đối tượng đó có tất cả các phương thức của tất cả các giao diện của nó, vì vậy nó là một mảng giao diện. Ví dụ: nếu có A thực hiện giao diện B, giao diện C và có 3 phương thức trong giao diện B và 2 phương thức trong giao diện C thì đối tượng của A có 5 phương thức (không tính đến các phương thức do chính A cung cấp) */ return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class>[]{serviceInterface}, new InvocationHandler() { /** * Mô tả chức năng: * * @author cakin * @date 14/5/2022 * @param proxy: đối tượng proxy * Phương thức @param: phương thức nào (sayHi (danh sách tham số)) * @param args: danh sách tham số * @return T */ @Override public Object gọi (Proxy đối tượng, Phương thức phương thức , Object[] args) { // Máy khách gửi yêu cầu đến máy chủ: yêu cầu một giao diện cụ thể Ổ cắm socket = new Socket(); ObjectOutputStream đầu ra = null; = null; try { // addr chứa IP và cổng của máy chủ được truy cập socket.connect(addr); // Gửi yêu cầu đến máy chủ thông qua luồng tuần tự hóa (luồng đối tượng) out = new ObjectOutputStream(socket.getOutputStream () ); // Tên giao diện để gửi yêu cầu out.writeUTF(serviceInterface.getName()); // Tên phương thức gửi yêu cầu out.writeUTF(method.getName()); Loại tham số của phương thức gửi yêu cầu out.writeObject(method.getParameterTypes()); // Giá trị tham số của phương thức gửi yêu cầu out.writeObject(args); // Đang chờ xử lý phía máy chủ. .. // Nhận xử lý phía máy chủ Giá trị trả về sau input = new ObjectInputStream(socket.getInputStream()); return input.readObject(); } Catch (Ngoại lệ e) { e.printStackTrace() cuối cùng; { thử { if (output != null) out.close(); if (input != null) input.close(); } Catch (Ngoại lệ e) { e.printStackTrace();
gói rmi.test; nhập rmi.server.RMIService; nhập rmi.server.RMIServiceImpl; nhập rmi.server.ServerCenter; nhập rmi.server.ServerCenterImpl; lớp công khai TestRMIServer { public static void main(String[] args) { Bắt đầu dịch vụ dưới dạng một luồng new Thread(() -> { // Trung tâm dịch vụ ServerCenter server = new ServerCenterImpl(9999); // Đăng ký giao diện RMIService và lớp triển khai tới trung tâm dịch vụ server.register(RMIService.class, RMIServiceImpl.class);
gói rmi.test; import rmi.client.RMIClient; import rmi.server.RMIService; import java.net.InetSocketAddress; // Khởi động máy chủ trước, sau đó là máy khách và bạn sẽ thấy máy khách đã gọi thành công máy chủ sayHi( ) phương pháp trên. public class TestRMIClient { public static void main(String[] args) ném ClassNotFoundException { // Gọi giao diện rmi.server.RMIService từ xa và thực thi phương thức sayHi() trong giao diện RMIService service = RMIClient.getRemoteProxyObj( Class.forName(" rmi.server.RMIService" ), mới InetSocketAddress("127.0.0.1", 9999)) ; System.out.println( service.sayHi("zs") ) ;
xin chào, zs
Tôi đang viết một ứng dụng RMI. Tôi có thể thực hiện RMI. Dữ liệu được truyền giữa máy khách và máy chủ thông qua RMI. Máy khách phải luôn nhận/cập nhật dữ liệu phía máy chủ. Có thể có một người nghe có thể chuyển hoặc thông báo cập nhật/sửa đổi dữ liệu từ máy chủ không
Tôi đang sử dụng nhà môi giới JMX-RMI để nhắn tin. Tôi có một chương trình java gửi tin nhắn có tên/ID tới một nhóm người nghe/người nghe. Dựa trên các tin nhắn mà người nghe nhận được, chương trình máy khách sẽ chạy tương ứng. Bài đăng này hoạt động tốt nhưng tôi muốn biết
Tôi có một máy chủ RMI, khi chạy trên localhost, sẽ liên kết chính xác với sổ đăng ký RMI (để chứng minh rằng nó được thiết lập chính xác). Mã thực hiện điều này là: void void phơi bàyTickHistoryRe
Tôi muốn lấy địa chỉ IP của từng máy khách ở phía máy chủ và máy chủ trả về một sơ khai cho địa chỉ đó. Có thể được không? Câu trả lời hay nhất hãy xem RemoteServer.getClientHost(). Bạn có thể gọi nó trong việc thực hiện phương thức từ xa. Nhưng khi
Tôi có hai chương trình Java - RMIServer và RMIClient. Nếu tôi khởi chạy chúng dưới dạng hai lệnh gọi Java riêng biệt thì mọi thứ sẽ hoạt động như mong đợi. Đó là $java -cp someclasspath
Hiện đang đọc về RPC và RMI và tôi hơi bối rối về sự khác biệt giữa chúng. Khi triển khai RMI và gRPC, cú pháp về cơ bản giống nhau. Tất cả chúng đều có giao diện xác định các tham số và phản hồi của phương thức. Tất cả chúng đều có thể được tìm thấy trong các thông số
Câu hỏi này đã có câu trả lời ở đây: đã đóng cửa 12 năm trước. Có thể trùng lặp: Sự khác biệt của RMI và CORBA Sự khác biệt giữa RMI và Corba là gì? Câu trả lời hay nhất là RMI
Tôi mới làm quen với java RMI và tôi đang cố gắng tạo một ứng dụng torrent ngang hàng giống như bit 2 trong đó nhiều phiên bản của cùng một máy ngang hàng có thể nằm trên cùng một máy. Điều này có nghĩa là tôi cần có khả năng đăng ký trên cùng một máy
Tôi nhận được một ngoại lệ từ xa khi cố chạy mẫu RMI của mình. Tôi không hiểu tại sao. Tôi chạy chương trình mà không lấy bất kỳ đối số nào cho chính chương trình hoặc JVM. Xin hãy giúp tôi thoát khỏi ngoại lệ. Cảm ơn rất nhiều Đây là ngoại lệ tôi nhận được: Máy chủ ngoại trừ
Về trang Câu hỏi thường gặp của Oracle về Java RMI, trang này cho biết: Trong khi máy chủ Lệnh gọi phương thức từ xa Java (Java RMI) có thể th
Tôi có máy chủ java rmi và máy khách java rmi trên hai máy riêng biệt và khác nhau. Máy chủ về cơ bản là một máy tính Fibonacci. Nó lấy một loạt số và tính toán dãy Fibonacci dựa trên chúng. Máy khách chỉ cần gửi một loạt số đến máy chủ
đóng cửa. Câu hỏi này yêu cầu chi tiết hoặc rõ ràng. Câu trả lời không được chấp nhận vào thời điểm này. Bạn muốn cải thiện câu hỏi này? Thêm chi tiết và làm rõ câu hỏi bằng cách chỉnh sửa bài đăng này Đã đóng 8 năm trước. Cải thiện điều đó
Tôi muốn biết liệu RMI có thể khởi động RMIregistry trên một máy chủ khác với máy chủ cung cấp dịch vụ hay không. Câu trả lời hay nhất Có, có thể, nhưng bất tiện vì bind(), rebind() và unbind() chỉ chấp nhận từ localhost
Tôi đang gặp một số vấn đề khi kết nối với một đối tượng từ xa trong lớp khách hàng của mình. Khi tôi chạy lớp máy khách sau, tôi nhận được ngoại lệ java.rmi.ConnectException. nhập java.rmi.registry.LocateRegis
Tôi đang cố gắng để máy khách trên một máy tính giao tiếp với máy chủ trên máy tính khác thông qua Java RMI. Tôi đã triển khai máy chủ trên máy chủ IP X trên cổng Y. Sau đó tôi cố gắng để máy khách tìm thấy đối tượng từ xa trên máy chủ, nhưng tôi gặp ngoại lệ sau: E
Tôi có RMIClientSocketFactory tùy chỉnh ghi đè "createSocket" để tạo một ổ cắm đặc biệt. Làm cách nào để có được ổ cắm này khi triển khai giao diện từ xa rmi của tôi? (
Tôi gặp sự cố với luồng RMI Reaper, nó không cho phép tất cả các chương trình của tôi chấm dứt vì luồng này không phải là daemon. Tôi tìm thấy thông tin rằng luồng chỉ dừng khi tất cả các đối tượng không được xuất. Vì vậy, tôi có đoạn mã sau để tạo rmi serer. sổ đăng ký
Khi tôi cố chạy máy khách RMI sau khi chạy máy chủ RMI, tôi gặp ngoại lệ sau: Ngoại lệ EncodeInterface: java.lang.ClassCastException: $Proxy3
Tôi muốn viết một bộ thử nghiệm tích hợp hệ thống cho ứng dụng khách RMI. Tôi muốn khởi động máy chủ RMI trong JUnit 3.8.2 và chạy các thử nghiệm này. Có ai đã làm điều này trước đây chưa? Tôi sử dụng một cái gì đó như thế này trong pojo với main
Câu hỏi này đã có câu trả lời: java.rmi.ServerException: RemoteException xảy ra trong chuỗi máy chủ (ClassNotFoundExcept
Tôi là một lập trình viên xuất sắc, rất giỏi!