GIỚI THIỆU VỀ RMI
Khái niệm chung
1.1.1 Java RMI (Remote Method Invocation)
RMI (Remote Method Invocation) là cơ chế cho phép một đối tượng đang chạy trên một Java Virtual Machine (JVM) gọi phương thức của một đối tượng khác trên một JVM khác Sun đã phát triển cơ chế này thông qua hệ thống Java Remote Method Invocation, cung cấp nhiều phương pháp truyền thông cho các chương trình viết bằng Java Các chương trình sử dụng hệ thống này được gọi là chương trình RMI.
RMI, hay Remote Method Invocation, là một cơ chế gọi hàm từ xa được tích hợp trong ngôn ngữ lập trình Java Nó đối mặt với các vấn đề tương tự như RPC và áp dụng những giải pháp tương tự Tuy nhiên, RMI mang lại nhiều lợi ích hơn nhờ vào tính chất hướng đối tượng của Java, cho phép lập trình viên thực hiện các thao tác và gọi hàm liên quan đến các đối tượng Đặc biệt, RMI cho phép Client gửi một Object đến Server để xử lý, với Object này có thể được xem như một tham số cho lời gọi hàm từ xa, đồng thời chứa dữ liệu và hành vi như một Object thực sự.
1.1.2 Remote Interface, Remote Object, Remote Method
Chương trình RMI trong Java được xây dựng từ các Interface và Class, trong đó Interface định nghĩa các Method và Class hiện thực hóa chúng Chỉ những Method được khai báo trong Remote Interface mới có thể được Client gọi từ một Java Virtual Machine khác, nghĩa là chỉ những Method này mới được Client nhận diện.
Vì vậy, Remote Interface là một Interface khai báo các Method cho phép gọi từ xa Trong Java, Remote Interface có các đặc điểm :
- Thừa kế Interface có sẵn : Interface java.rmi.Remote
- Mỗi Method trong Remote Interface muốn là Remote Method phải được khai báo là throws java.rmi.RemoteException và có thể có các Exception khác
Remote Object là một đối tượng được thiết kế để cho phép các đối tượng khác trên một JVM khác thực hiện các cuộc gọi tới nó Nó chứa một số phương thức, được gọi là Remote Method, cho phép thực hiện gọi từ xa và các phương thức này sẽ được thực thi bởi JVM được gọi là Server.
Hình 1 Remote Object, Remote Method
In the context of RPC, the Name Server acts as an intermediary process that facilitates the search for a reference to a specific Remote Object, assisting the Client in locating the necessary reference Within a Java RMI system, the Name Server can be any machine in the network, and it must maintain a memory space known as the Name Space, which stores the names and corresponding addresses of the Remote Objects in the system.
Trong Remote Procedure Call (RPC), Client Stub và Server Stub (gọi là Stub và Skeleton trong Java RMI) là những thành phần thiết yếu giúp một Process trên máy khách thực hiện các phương thức từ xa của các đối tượng trên máy chủ Bài viết này sẽ trình bày chi tiết về vai trò của Stub và Skeleton trong quá trình gọi thực thi các Remote Method.
Những công việc được thực hiện bởi Stub trong Java RMI:
- Tạo một cầu nối với JVM có chứa Remote Object mà Client cần
- Marshals các tham số cần cho việc gọi hàm và thực hiện việc gửi chúng đi
- Chờ kết quả trả về từ lời gọi hàm
- Unmarshals gói dữ liệu nhận được để đọc các giá trị trả về hay các Exception trả về từ lời gọi hàm
- Trả kết quả về cho chương trình Client thực sự
Ngoài việc cung cấp thông tin, Stub còn giữ vai trò quan trọng trong việc duy trì tham chiếu tới Remote Object, giúp ngăn chặn việc Remote Object bị giải phóng bởi trình Garbage Collection tự động của Java.
Khi có một lời gọi hàm gửi tới Skeleton, Skeleton sẽ thực hiện các công việc như sau :
- Unmarshals gói dữ liệu nhận được để có những thông tin cần thiết cho việc gọi hàm
- Thực hiện lời gọi hàm đối với hệ thống thực thụ
- Marshals kết quả trả về và gửi trả về cho Client
Với những nhiệm vụ của từng phần như trên, ta cũng có thể thấy vài sự khác nhau về Client Stub,Server Stub giữa RMI và RPC như sau :
Stub (RMI) so với Client Stub (RPC) :
Stub khác với Client Stub ở chỗ Stub giữ một tham khảo tới một Remote Object, ngăn chặn việc Garbage Collection xóa bỏ Remote Object Ngược lại, Client Stub không thực hiện chức năng này.
- Stub còn đóng vai trò quan trọng trong việc Sẽrialize một Object, và việc truyền khai báo Class cho Skeleton khi có yêu cầu
Skeleton (RMI) so với Server Stub(RPC) :
Server Stub không yêu cầu phải thực hiện việc Serialize một Object và không cần phải tìm kiếm hay quan tâm đến việc khai báo một Class nào đó, trong khi Skeleton lại phải chú ý đến những yếu tố này.
Nguyên tắc hoạt động của Java RMI
Một chương trình RMI thông thường được chia làm 2 phần, đó là chương trình trên Client và chương trình trên Server
Chương trình Server có nhiệm vụ tạo ra các Remote Object và cho phép các tham chiếu tới chúng được truy cập từ xa Sau khi hoàn tất, Server sẽ chờ đợi các yêu cầu từ Client để thực thi các phương thức tương ứng và trả về kết quả cho Client.
Chương trình Client có nhiệm vụ tìm kiếm và lấy tham khảo đến các Remote Object từ một máy Name Server, sau đó gọi các phương thức của Remote Object đó Hệ thống Java RMI cung cấp các kỹ thuật cần thiết để Server và Client có thể giao tiếp, cho phép truyền nhận thông tin qua lại giữa hai bên.
Hoạt động cụ thể của một chương trình RMI chúng ta có thể biểu diễn như sau :
Hình 4 Cơ chế hoạt động của chương trình RMI
Như hình trên ta có thể thấy cơ chế hoạt động của một chương trình RMI như sau :
To enable remote calls to Remote Objects and their Remote Methods on a server, developers must arrange Stubs, Skeletons, and Remote Interfaces on the web server This setup ensures that different JVMs, specifically Clients and RMI Registries, can access these components effectively.
(2) Server đó phải đăng ký với Registry để báo cho các JVM đóng vai trò Client biết là Server đã sẵn sàng phục vụ
Khi Registry nhận yêu cầu đăng ký, nó tự động tải Stub Class trên Web Server dựa vào codebase mà Remote Object cung cấp Quá trình này diễn ra tự động nhờ cơ chế Load Class động trong Java, giúp lập trình viên không cần phải lo lắng, chỉ cần cung cấp một codebase chính xác để Registry có thể tìm kiếm.
Chú ý : Registry sẽ truy cập Stub Class File bằng URL Protocol Nghĩa là
The Registry sends a request for the Stub Class File via a URL Protocol to the WEB Server, which then returns the Stub Class File to the Registry In other words, the Registry does not directly access the Stub Class File on a different JVM.
When a client needs to execute a remote method, it must send a message to the registry to obtain a reference to the required remote object.
After referencing the necessary Remote Object, the Client will automatically load the Stub Class using Java's dynamic class loading mechanism.
(3) (6) Client gửi yêu cầu thực thi một Method nào đó mà nó cần với đầy đú các tham số cần thiết
Các đường không liên tục là biểu diễn cho các bước mà người lập trình không nhìn thấy được do Java đã tự động làm
Để đảm bảo một JVM từ xa có thể truy cập bytecode của Stub và Skeleton, chúng ta cần bố trí chúng một cách hợp lý Nguyên tắc là chương trình trên một JVM không thể tự động truy cập vào hệ thống file của một JVM từ xa, vì Local JVM không biết cách tổ chức hệ thống file của JVM từ xa Do đó, khi một chương trình trên JVM cần truy cập thông tin từ file trên JVM từ xa, nó phải có quyền truy cập file đó, sau đó gửi yêu cầu tới chương trình trên JVM từ xa để thực hiện truy cập và nhận kết quả.
1.2.2 Các công việc đã giải quyết đƣợc
Chương trình sử dụng RMI thường được gọi là ứng dụng đối tượng phân tán Với cơ chế hoạt động này, RMI đã giải quyết hiệu quả các nhiệm vụ cần thiết trong một ứng dụng đối tượng phân tán.
Trong một chương trình chạy trên nhiều máy, các đối tượng (Object) cần gửi và nhận thông tin qua lại để hợp tác làm việc, do đó, một ứng dụng Distributed Object cần giải quyết vấn đề định vị các Remote Object để phục vụ cho việc truyền nhận thông tin Có hai kỹ thuật để thực hiện điều này: một là hỏi trực tiếp máy chứa Remote Object cho đến khi có được tham khảo cần thiết, và hai là sử dụng cơ chế Naming Thông thường, trong RMI, cơ chế Naming được sử dụng.
Khách hàng chỉ có thể gọi các phương thức trên Remote Object khi có tham chiếu đến đối tượng đó RMI cung cấp một Name Server đơn giản, cho phép các Remote Object đăng ký thông qua lớp java.rmi.NamingRegistry Lớp này áp dụng cơ chế Naming dựa trên URL.
Hình 5 Remote Object đăng ký với Naming Registry
Khách hàng sử dụng lớp java.rmi.Naming để tìm kiếm và nhận tham chiếu đến các đối tượng từ xa Địa chỉ của đối tượng từ xa được xác định qua một URL chỉ đến máy chủ từ xa và tên của đối tượng trên máy đó Khi một đối tượng đăng ký với registry, nó sẽ có một tên dễ nhớ, giúp cho các khách hàng từ xa tham khảo đến các đối tượng này qua tên đã đăng ký.
1.2.2.2 Vấn đề truyền tham số trong lời gọi hàm
Trong Java RMI, các tham số cho lời gọi hàm và giá trị trả về phải là các Object có khả năng “Serialize”.
Client Remote reference đến việc truyền nhận cụ thể trong Java là thực chất là truyền cái gì, khi một Object nào đó được gọi là truyền đi
Hình 7 Truyền Non-Remote Object
Khi một Non-Remote Object được truyền, nó sẽ được sao chép thành một Object mới, sau đó được tuần tự hóa (Serialize) và gửi đến người nhận Do đó, Non-Remote Object là tham số được sao chép từ Object có sẵn, và bên nhận sẽ khôi phục lại Object từ chuỗi Byte Nếu Non-Remote Object là giá trị trả về, nó sẽ được tạo mới và truyền đi.
Khi một Remote Object được truyền đi, thực tế chỉ có Stub được gửi đi Không có Remote Object nào được truyền đi vì mỗi Remote Object đã đăng ký với Name Server, do đó việc truyền đi làm mất đi ý nghĩa của việc đăng ký.
1.2.2.2.3 Sự tích hợp các tham khảo :
Một số đặc điểm nổi bật của Java RMI
Java RMI (Remote Method Invocation) là một cơ chế gọi hàm từ xa, cho phép các đối tượng Java giao tiếp và tương tác với nhau qua mạng Những vấn đề quan trọng trong Java RMI bao gồm cách truyền tham số trong lời gọi hàm và định vị Remote Object Một số đặc điểm nổi bật của Java RMI bao gồm khả năng hỗ trợ truyền tham số phức tạp, tự động xử lý việc serial hóa và deserial hóa đối tượng, cũng như khả năng làm việc với các đối tượng từ xa một cách hiệu quả.
- Dynamic Class Loading(Cho phép Load Class động)
- Thread usage in RMI(Cho phép sử dụng Thread trong RMI)
- Gabage Collection of Remote Object (Tự động giải phóng các Remote Object mà hệ thống không còn tham khảo tới)
Các đặc điểm này sẽ được trình bày một cách rõ ràng hơn trong các phần sau
C H Ƣ Ơ N G II LÂP TRÌNH PHÂN TÁN VỚI JAVA RMI
Lập trình phân tán với RMI đang trở thành một chủ đề quan trọng trong ngành công nghiệp phần mềm hiện nay Bài viết này sẽ cung cấp kiến thức cơ bản về lập trình phân tán và công nghệ RMI, đồng thời thảo luận các khía cạnh liên quan đến lĩnh vực này.
Sau khi hoàn thành chương này, người học sẽ nắm vững khái niệm về lập trình phân tán và ứng dụng công nghiệp của RMI Họ cũng sẽ biết cách xây dựng các ứng dụng phân tán, cũng như cách chuyển tham số cho các phương thức gọi từ xa và nhận kết quả trả về từ những phương thức này.
RMI và lập trình phân tán đối tượng
Trong thời đại công nghệ hiện nay, các chương trình truyền thống thường tập trung thực thi trên một máy đã không còn đáp ứng được nhu cầu, do sự phát triển mạnh mẽ của mạng máy tính và Internet Thay vào đó, các ứng dụng hiện đại yêu cầu sự hợp tác xử lý, với mã lệnh được phân tán trên nhiều máy, tạo thành các chương trình phân tán Lập trình để phát triển những chương trình này được gọi là lập trình phân tán, với nhiều công nghệ nổi bật như DCOM, CORBA, RMI và EJB, trong đó RMI nổi bật với tính đơn giản và tính thuần Java.
Trong lập trình phân tán, để triệu gọi các phương thức của một đối tượng nằm trên máy khác, chúng ta sử dụng RMI (Remote Method Invocation) RMI cho phép các đối tượng Java giao tiếp và gọi lẫn nhau, mặc dù mã lệnh của chúng (bao gồm các phương thức và thuộc tính) được cài đặt trên các máy khác nhau.
Mô hình triệu gọi đối tượng phân tán cho phép các đối tượng A1, A2 trên máy A gọi các phương thức của nhau thông qua triệu gọi phương thức cục bộ Đây là phương pháp lập trình hướng đối tượng truyền thống, tương tự như cách mà các đối tượng B1, B2, B3 hoạt động như các đối tượng cục bộ.
Các đối tượng Java có khả năng gọi phương thức của một đối tượng trên máy khác thông qua giao thức gọi từ xa RMI Ví dụ, trong mô hình sau, đối tượng A1 (trên máy A) có thể thực hiện lời gọi phương thức đến đối tượng B2 (trên máy B).
A) là lời gọi phương thức từ xa
Hình 1: Mô hình triệu gọi các phương thức từ xa
Gọi phương thức từ xa và các vấn đề phát sinh
Triệu gọi phương thức từ xa có vẻ đơn giản nhưng thực tế lại phức tạp hơn so với triệu gọi phương thức cục bộ Các đối tượng trên hai máy khác nhau hoạt động trong hai tiến trình riêng biệt, dẫn đến sự khác biệt trong cách tham chiếu biến địa chỉ đối tượng Khi truyền một đối tượng cho phương thức triệu gọi từ xa, bạn thực sự chỉ truyền một tham chiếu đến đối tượng, trong khi vùng nhớ của nó lại nằm trên máy khác Kết quả của lời gọi phương thức cục bộ được trả về qua ngăn xếp, trong khi kết quả từ lời gọi phương thức từ xa phải qua kết nối mạng, điều này có thể dẫn đến sự cố truyền thông Do đó, việc bắt và kiểm soát lỗi trong các ứng dụng phân tán trở nên tốn kém.
Lớp trung gian đóng vai trò quan trọng trong việc gọi phương thức từ xa trong lập trình Java, giúp đơn giản hóa quá trình giao tiếp giữa hai máy khác nhau Khi thực hiện lời gọi phương thức cục bộ, các tham số và kết quả được xử lý qua ngăn xếp, trong khi đó, với lời gọi phương thức từ xa, dữ liệu cần được đóng gói và truyền qua mạng Để người lập trình không phải tương tác trực tiếp giữa các đối tượng trên hai máy, lớp trung gian được sử dụng để kết nối máy khách và máy chủ, đảm bảo tính minh bạch và hiệu quả trong việc thực hiện các phương thức từ xa.
B1 đặt) Phía máy khác lớp trung gian này được gọi là stub (lớp móc), phía máy chú lớp trung gian được gọi là skeletion (lớp nối)
Ta có thể hình dung lớp trung gian stub và skel là hai người trung gian giúp các đối tượng ở xa có thể giao dịch được với nhau
Trong quá trình gọi phương thức của đối tượng C1 trên máy C, trình biên dịch Java tạo ra hai lớp trung gian là C1_stub và C1_skel Lớp C1_stub được truyền về máy A, và khi A1 trên máy A gọi phương thức của đối tượng C1, nó sẽ chuyển lời gọi đến lớp C1_stub Lớp này có nhiệm vụ đóng gói các tham số và gửi chúng qua mạng đến phương thức tương ứng của đối tượng C1 Trên máy C, lớp C1_skel nhận các tham số và chuyển vào địa chỉ thích hợp để gọi phương thức Kết quả trả về từ phương thức C1 sẽ được lớp C1_skel đóng gói và gửi lại cho A1 qua lớp C1_stub Nhờ cơ chế này, A1 luôn cảm nhận rằng đối tượng C1 như đang tồn tại trên cùng máy với nó, tương tự như các đối tượng cục bộ khác Hơn nữa, lớp trung gian C1_stub còn có khả năng thông báo lỗi cho A1 khi có sự cố kết nối mạng xảy ra.
A1 có thể tham chiếu đến C1 mà không cần đối tượng C1 được cài đặt trên máy A C1_Stub trên máy A chỉ thực hiện việc chuyển tham số và nhận kết quả trả về, đồng thời thực hiện các giao thức mạng mà không phải là hình ảnh của C1 Để thực hiện điều này, đối tượng C1 cần cung cấp một giao diện tượng.
Cài đặt đối tượng phân tán
2.4 Cài đặt đối tƣợng phân tán
Khi bạn muốn tạo ra một đối tượng từ xa, bạn cần sử dụng một giao diện để thiết lập nền Khi khách hàng nhận được tham chiếu đến đối tượng từ xa, điều đó thực sự là một giao diện.
Khi tao ra một giao diện từ xa, thì bạn phải tuân theo các hướng dẫn sau:
Giao diện từ xa cần được định nghĩa là một giao diện public, tức là phải thêm từ khóa public trước định nghĩa của nó Nếu không, việc tham chiếu đến đối tượng từ xa sẽ gây ra một ngoại lệ.
Giao diện từ xa phải là giao diện được kế thừa từ giao diện Remote
Tất cả các phương thức trong giao diện từ xa đều phải khai báo ngoại lệ Remote Exception trong mệnh đề throws, nhằm xử lý các cú ngoại lệ khác Điều này có nghĩa là Remote Exception là một yêu cầu bắt buộc cho mọi phương thức trong giao diện từ xa.
Nếu tham số được truyền cho phương thức hoặc giá trị nhận về từ cuộc gọi từ xa là một đối tượng, thì đối tượng đó cần phải triển khai giao diện Remote hoặc giao diện tương ứng.
Serializable Thông thường bạn thường thấy một giao diện từ xa có cầu trúc như sau: import java.rmi.*; public interface RemoteInterface extends Remote{
[public] ReturnDatatype method1([Datatype arg1,][ Dataype arg2,…] ) throws RemoteException;
[public] ReturnDataype method2() throws RemoteException;
Ví dụ 1-1: Sau đây là một giao diện từ xa đơn giản của ứng dụng HelloRMI
Giao diện HelloRMI mở rộng từ giao diện Remote và yêu cầu tất cả các phương thức phải ném ra ngoại lệ RemoteException Lưu ý rằng, các phương thức trong giao diện tự động được coi là public, vì vậy có thể bỏ từ khóa public khi khai báo phương thức sayHello.
Bạn tiến hành biên dịch javac HelloRMI.java bạn sẽ thu được tập tin HelloRMI.class
2.4.2 Triển khai giao diện từ xa
Sau khi tạo giao diện từ xa, bước tiếp theo là triển khai tất cả các phương thức trong giao diện đó.
Ví dụ 1-2: Sau đây là cài đặt của giao diện từ xa HelloRMI
Để cài đặt đối tượng HelloRMI trên máy 2 và gọi phương thức sayHello() từ máy 1, cần sử dụng hai lớp trung gian là HelloRMIImpl_Stub và HelloRMIImpl_Skel Phương thức sayHello không thể được gọi trực tiếp, mà phải thông qua các lớp này Sử dụng lớp HelloRMIImpl.class, trình biên dịch rmic.exe của Java sẽ tạo ra hai lớp Stub và Skel Bạn cần mở cửa sổ DOS – Prompt và nhập lệnh tương ứng.
Kết quả bạn sẽ thu được hai tập HelloRMIImpl_Stub.class và
2.4.3 Cài đặt, đăng kí đối tƣợng từ xa
Bước tiếp theo sau khi bạn cài đặt giao diện từ xa là công việc đăng ký nó với trình rmiregistry theo mẫu sau:
Ví dụ 1-4: Ví dụ sau là chương trình đăng ký và cài đặt đối tượng HelloRMIImpl với trình chú rmiregistry
Setup.java import java.rmi.*; public class HelloRMIImpl implements HelloRMI { public String sayHello() throws RemoteException
Công việc đầu tiên bạn phải làm khi cài đặt đối tượng từ xa là tao ra một thể hiện của đối tượng từ xa
HelloRMI h=new HelloRMIImpl(); bạn có thể thấy bằng dòng lệnh
Tiếp theo bạn gọi phương thức tĩnh exportObject của lớp UnicastRemoteObject đề máy áo java biết đối tượng h (HelloRMI) là đối tượng có khả năng truy xuất từ xa
Lưu ý đề sử dụng được lớp UnicastRemoteObject bạn phải khai báo import java.rmi.server.*; ở đâu chương trình
Cuối cùng, bạn cần đặt một cái tên dễ nhớ cho đối tượng h và đăng ký tên này với bộ đăng ký rmiregistry Lớp Nameming sẽ thực hiện phương thức tĩnh để hoàn tất quy trình này.
Naming.bind("[rmi:]//hostname[:port]/name”, h);
Phương thức bind có hai tham số: tham số thứ nhất là một chuỗi định vị URL, đối số thứ hai là bản thân đối tượng cần đăng ký
Chuỗi định vị URL có định đang như sau:
Trong đó: import java.rmi.server.*; import java.rmi.*; import java.net.*; public class Setup { public static void main(String[] args) {
// tao ra một thể hiện cúa đôí tương từ xa
// Khai báo đôí tương có khá năng triệu gọi từ xa
// đăng ký nó vơi trình rmiregistry
// có thể thấy phương thức bind bơi rebind nhu sau:
RMI là tên giao thức,đây là phần tuy chọn, mặc định giao thức là rmi nên bạn có thể bỏ qua
Hostname là tên của máy chú hoặc địa chỉ IP của máy chú nối đối tượng phân tán đăng tồn tại
Port là số hiệu cổng của chương trình rmiregistry, đây là tham số tuy chon, nếu bỏ qua tham số này thì cổng mặc định là 1009
Name là tên gọi nhớ của đối tượng phân tán
Phương thức bind sẽ đi vào vòng lặp vô han chờ kết nối từ máy kách
Các chương trình phía máy khách sẽ dựa vào chuỗi định vị URL mà ta đăng ký với trình rmiregistry đề truy tìm tham chiếu đến đối cần dùng
Bạn có thể khởi động bộ đăng ký rmiregistry này ó dâu? Bạn mở của số DOS- Prompt và cho chay chương trình rmiregistry này từ dòng lệnh như sau:
Nếu trong WintựT thì bạn có thể chay nó như một dịch vụ bằng dòng lệnh start C:\JDK1.4\bin\rmiregistry.exe
Sau khi khởi động chương trình rmiregistry, bạn sẽ không thấy phản hồi ngay lập tức vì nó hoạt động dưới dạng dịch vụ Mặc định, rmiregistry lắng nghe các kết nối trên cổng 1009, nhưng bạn có thể chỉ định cổng khác Ví dụ, để khởi động rmiregistry trên cổng 2004, bạn có thể sử dụng lệnh: C:\Jdk1.4\bin\rmiregistry.exe 2004.
Trong Java, hostname không thể là "localhost", vì vậy nếu bạn muốn thử nghiệm trên máy cục bộ, bạn cần sử dụng địa chỉ IP như 127.0.0.1 hoặc tên máy của bạn Để tìm tên máy, bạn có thể vào Control Panel, chọn Network, sau đó vào thẻ Identification để xem tên máy trong phần Computer Name.
RMI sẽ không làm việc chừng nào bạn chưa cài cho giao thức TCP/IP
Nếu bạn đăng kiểm thử trên máy cục bộ thì bạn có thể đăng ký với trình rmiregistry đơn giản như sau:
Khi bạn đăng ký một đối tượng mới với tên đã được sử dụng cho một đối tượng khác, bạn sẽ gặp phải ngoại lệ AlreadyBoundException Để tránh tình trạng này, hãy sử dụng phương thức Naming.rebind() thay vì Naming.bind() Phương thức Naming.rebind() cho phép bạn thêm một tên mới nếu chưa có và thay thế một tên đã tồn tại bằng một đối tượng mới.
Dù phương thức main() kết thúc, đối tượng từ xa mà bạn tạo ra và đăng ký tên vẫn tồn tại miễn là rmiregistry còn chạy và bạn không gọi phương thức Naming.unbind() Vì vậy, khi phát triển ứng dụng, bạn cần phải luôn khởi động lại rmiregistry mỗi khi biên dịch lại đối tượng từ xa.
Bạn không nhất thiết phải khởi động rmiregistry như một tiến trình ngoài
Nếu ứng dụng của bạn là ứng dụng duy nhất sử dụng số đăng ký, bạn có thể khởi động nó từ bên trong chương trình của mình bằng cách sử dụng dòng lệnh.
LocateRegistry.createRegistry(Port); Ở đây Port là số hiệu cổng Ðiều này là tương ứng với việc chay rmiregistry Port từ đầu của DOS-Prompt
2.4.4 Viết trình khách triệu gọi phương thức của đối tượng cài đặt từ xa
Trình khách triệu gọi đối tượng phân tán RMI có thể được phát triển dưới nhiều hình thức như ứng dụng console, ứng dụng có giao diện đồ họa, ứng dụng Servlet hoặc trang JSP Trong chương trình khách, bạn chỉ cần tra cứu và lấy giao diện từ xa từ trình chú, sau đó thực hiện việc triệu gọi phương thức từ xa một cách tương tự như triệu gọi phương thức của bất kỳ đối tượng cục bộ nào khác.
Sau đây là mẫu chương trình phía trình khách triệu gọi đối tượng phân tán RMI
Ví dụ 1-5: Sau đây là trình khách triệu gọi đối tượng HelloRMI import java.rmi.*; import java.rmi.registry*; public Client
{ public static void main(String args[]) throws RemoteException
// lấy về tham chiếu đối tượng phân tán bằng phương thức Naming.lookup()
RemoteInterface r=(RemoteInterface)Naming.lookup(“[rmi:]//hostname[:port]/name”);
// triệu gọi các phương thửc cúa đối tượng từ xa }
} Để truy tìm đối tượng ở xa, chương trình máy khách gọi phương thức
Naming.lookup(); Phương thức này chỉ yêu cầu đối số là chuỗi cho biết địa chỉ của máy chú và tên đăng ký của đối tượng
RemoteInterfacer=(RemoteInterface)Naming.lookup(“[rmi:]//hostựame[:port]/name
Mặc định phương thức Naming.lookup() trả về một tham chiếu Object nên bạn cần phải é p kiểu sang giao diện từ xa
Phương thức Naming.lookup() hoạt động như một dịch vụ tìm kiếm đối tượng trên máy chủ, liên lạc với trình rmiregistry để yêu cầu tham chiếu đối tượng Trong khi đó, Naming.bind() thực hiện chức năng đăng ký Sau khi biên dịch và chạy chương trình khách bằng lệnh Javac Client.java, bạn có thể khởi động chương trình khách với lệnh: Java Client.
Kết quả thu được là lời chào “Hello RMI”
CÀI ĐẶT CHƯƠNG TRÌNH
Cài đặt công cụ lập trình và một số thú tục cần thiết
3.1.1 Cài đặt công cụ lập trình
Dowload tại địa chỉ http://www.oracle.com/technetwork/java/javase/downloads/index.html
Các bước cài đặt để mặc định
3.1.1.2 Cài đặt Neatbeans 8.0.1 dowload tại địa chỉ https://netbeans.org/downloads/
Các bước cài đặt để mặc định
Download tại địa chỉ http://www.microsoft.com/en- us/download/details.aspx?id95
Các bước cài đặt Xem hướng dẫn tại http://kenhsinhvien.net/topic/huong-dan- cai-dat-ms-sql-server-2008-co-hinh-anh-minh-hoa.9786/
3.1.1.4.1 Xem port kết nối với SQL Server
3.1.1.4.2 Tạo tài khoản quản trị ATMDatabase
3.1.2 Xây dựng chương trình ATM_Server
3.1.2.2 Thêm thƣ viện kết nối đến SQL Server
3.1.2.3 Tạo lớp kết nối từ chương trình và SQL Server
Với hàm kết nối đế SQL Server sau
3.1.2.4 Tạo lớp truy xuất CSL
3.1.2.5 Xây dựng thêm các Form khác
3.1.3 Xây dựng chương trình ATM Client
Xây dựng các Java Class và Jframe Form…
Nội dung chính của chương trình
Admin tiến hành đăng nhập bằng cách nhập User và Password được cấp Chương trình sẽ tham chiếu đối tượng được nhập đến CSDL
Nếu đúng thì thông báo đăng nhập thành công
3.2.1.2 Tìm kiếm giao dịch, tìm kiếm tài khoản
3.2.1.3 Gửi tiền vào tài khoản
Người quản lý sau khi đăng nhập vào hệ thống
Nhập các dữ liệu tìm kiếm cần thiết ( Mã PIN,
Số tài khoản, Số CMND… ) Chương trình sẽ truy vấn đến CSDL và lấy ra thông tin cần tìm
Sau khi đăng nhập vào hệ thống, người quản lý sẽ tìm kiếm thông tin của khách hàng cần nạp tiền bằng cách sử dụng số tài khoản, tên hoặc chứng minh thư Sau khi xác minh thông tin tài khoản, người quản lý tiến hành nạp tiền vào tài khoản cho khách hàng.
Tại máy client - khác hàng đăng nhập vào hệ thống, hệ thống sẽ truy vấn đến CSDL để kiểm tra thông tin về tài khoản đăng nhập
Người dùng có thể thực hiện chức năng rút tiền bằng cách nhập số tiền mong muốn Nếu số tiền rút hợp lệ, hệ thống sẽ thông báo giao dịch rút tiền thành công.
Sau khi đăng nhập, hệ thống sẽ xác minh thông tin tài khoản Khi chọn chức năng chuyển khoản, người dùng cần nhập số tài khoản nhận tiền Nếu thông tin mã thẻ hợp lệ, hệ thống sẽ thông báo chuyển khoản thành công.
Sơ đồ cơ chế vận hành
Cấu trúc CSDL
Fields Type Constraint Null Description
Username nvarchar(50) Primary Key Admin to login
Password nvarchar(50) Admin to login
Fields Type Constraint Null Description
ID Int Primary Key Statistic number
Bảng lưu trữ thông tin quản trị là một phần quan trọng trong hệ thống ngân hàng, thuộc quyền quản lý của các thành viên cao nhất Bảng này cho phép họ kiểm soát và quản trị hầu hết các hoạt động cần thiết trong hệ thống.
Bảng này là nơi mà thông tin cúa khách hàng sẽ được lưu trữ và được quản lý bởi các Admin và Manager
Fields Type Constraint Null Description
Một số mã nguồn quan trọng
3.5.1 Class ATM Server Đây được xem như một lớp đặc trưng của chương trình Nó khởi tạo môi trường để chương trình trên máy Server và Client có thể liên lạc được với nhau Gán cho Server một địa chỉ IP mặc định là 192.168.1.100 các máy Client sẽ phải đặt Ip cùng dải với máy Server thì mới có thể liên lạc được public class ATMServer { public static void main(String[] args) {
System.setProperty("java.rmi.server.hostname", "192.168.1.100");
//Khởi tạo bộ đăng ký và đăng ký trên cổng 2014
//Khởi tạo đối tượng transaction
//Ràng buộc đối tượng transaction vào bộ đăng ký
Naming.bind("rmi://192.168.1.100:2014/ATMServer", trans);
JOptionPane.showMessageDialog(null, "ATM Server khởi động thành công"); } catch (Exception e) {
//Thông báo nếu bị lỗi
JOptionPane.showMessageDialog(null, e.toString(), "Loi",
} Đây là bảng lưu trữ các thông tin về giao dịch cúa khách hàng
3.5.2 Class DBAccess Đây là lớp cho phép chương trình kết nối với CSDL, sử dụng những hàm đã được viết sẵn để tạo ra sự thống nhất với CSDL, mỗi thao tác có sử dụng đến
CSDL trong chương trình thì đều được tham chiếu đến đây public class DBAccess { private Connection con; //biến kết nối private Statement stmt; // biến phát biểu public void DBAcess()
//hàm update thực hiện việc insert, update, delete CDSL public int Update(String str)
//tạo đối tượng của lớp MyConnection mới
//biến kết nối lấy kết quả từ thưc hiện hàm GetConnection trong class
//tạo giá trị cho biến phát biểu stmt = con.createStatement();
//thực hiện phát biểu với câu truy vấn là chuỗi str Giá trị phát biểu trả về là số nguyên i int i = stmt.executeUpdate(str);
//Giá trị trả về cho hàm update của lớp DBAccess return i;
//Thông báo lỗi và trả về giá trị -1 cho hàm update của lớp DBAccess
JOptionPane.showMessageDialog(null,e.toString(),"Loi",JOptionPane.ERROR_M
//Hàm Query thực hiện việc lấy dữ liệu từ CSDL thông qua câu lệnh select public ResultSet Query(String srt)
//tạo đối tượng của lớp MyConnection mới
//biến kết nối lấy kết quả từ thưc hiện hàm GetConnection trong class
//tạo giá trị cho biến phát biểu stmt = con.createStatement();
//thực hiện phát biểu với chuỗi truy vấn srt Giá trị trả về nằm trong tập kết quả rs
ResultSet rs = stmt.executeQuery(srt);
//trả về giá trị tập kết quả cho hàm Query của lớp DBAccess return rs;
JOptionPane.showMessageDialog(null,e.toString(),"Loi",JOptionPane.ERROR_M ESSAGE); return null;
Lớp MyConnection cung cấp hàm kết nối giữa chương trình và cơ sở dữ liệu, cho phép chương trình sử dụng các kết nối đã có hoặc tạo mới kết nối.
//sử dụng driver jdbc4 của Microsoft
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
//định nghĩa chuỗi kết nối với port, user, password và tên database
String URL "jdbc:sqlserver://Hongha\\SQLEXPRESS1:1433;user=sa;password3@123a;Da tabase=ATMDatabase";
//khai báo biến kết nối, nhận giá trị là 1 kết nối với chuỗi kết nối URL
Connection con = DriverManager.getConnection(URL); return con;
JOptionPane.showMessageDialog(null, e.toString(), "Loi",
JOptionPane.ERROR_MESSAGE); return null;
Hệ thống chứa tất cả các thuật toán giao dịch như chuyển khoản, nạp tiền và rút tiền, giúp khách hàng tham khảo để thực hiện các giao dịch Tất cả thuật toán giao dịch được lưu trữ trên Server, đảm bảo tính bảo mật cao hơn Điều này không chỉ mang lại sự an toàn mà còn dễ dàng cho việc bảo trì, sửa đổi và nâng cấp hệ thống.
String to=""; if(trans_type.compareTo("Chuyen Khoan")==0){
String[] lstCardds.split("-"); card=lstCard[0]; to=lstCard[1];
//chuỗi truy vấn lấy ra số tiền hiện có của tài khoản
String str = "select Tien from TaiKhoanATM WHERE [MaThe] = '" + card + "'";
String to_str = "select Tien from TaiKhoanATM WHERE [MaThe] = '" + to + "'";
ResultSet rs = acc.Query(str); // truy vấn, lấy dữ liệu về rs
ResultSet to_rs=null; if(trans_type.compareTo("Chuyen Khoan")==0){ to_rs = acc.Query(to_str); // truy vấn, lấy dữ liệu về rs
} int total_money = 0; //tổng số tiền hiện tại int new_money = 0; // tổng số tiền sau khi giao dịch int to_total=0; int to_new=0;
//lấy giá trị số tiền hiện có của tài khoản if (!rs.isBeforeFirst() || (trans_type.compareTo("Chuyen Khoan")==0 &&
}else { while (rs.next()) { total_money = rs.getInt(1);
} if(trans_type.compareTo("Chuyen Khoan")==0){ while (to_rs.next()) { to_total = to_rs.getInt(1);
//Rut tien thì số tiền mới của tài khoản = tiền hiện tại - tiền rút if (trans_type.compareTo("Rut tien") == 0 && (total_money -
50000) >= money_value) { new_money = total_money - money_value;
// System.out.println(total_money - money_value); if(trans_type.compareTo("Rut tien") == 0 && total_money - money_value= money_value) { new_money = total_money - money_value; to_new=to_total+money_value;
} if (trans_type.compareTo("Chuyen Khoan") == 0 && (total_money
//cập nhật số tiền mới vào tài khoản str = "update TaiKhoanATM set [Tien] ='" + new_money + "'
WHERE [MaThe] = '" + card + "'"; to_str = "update TaiKhoanATM set [Tien] ='" + to_new + "'
WHERE [MaThe] = '" + to + "'"; kq = acc.Update(str); if (trans_type.compareTo("Chuyen Khoan") == 0){ kq = acc.Update(to_str);
Giao diện đồ họa người dùng của ứng dụng ATM bao gồm những phần cơ bản không thể thiếu Hầu hết các khung hình trong ứng dụng được thiết kế đơn giản và mang phong cách cổ điển, sử dụng Window Frame của Java.
Khi chương trình khởi động thành công, một thông báo sẽ xuất hiện Sau khi đóng thông báo này, người quản trị sẽ thấy một Form cho phép đăng nhập tài khoản và mật khẩu vào hệ thống.
Tại đây sẽ có các chức năng chính của phần quản lý như
- Quản lý tài khoản Server
- Quản lý tài khoản, thẻ ATM
Giao diện quản lý Đăng nhập
+ Nạp tiền vào tài khoản
- Quản lý giao dịch + Tìm kiêm giao dịch
Tên tài khoản Field Chấp nhận tên tài khoản
Mật khẩu Password Field Chấp nhận mật khẩu
Xác nhận mật khẩu Password Field Chấp nhận xác nhận mật khẩu Button Thêm Click để thêm tài khoản
Button Cancel Click để thoát khỏi
Tên tài khoản trong bảng chứa các tài khoản Admin được truy xuất từ cơ sở dữ liệu Để xóa một tài khoản, người dùng chỉ cần chọn tài khoản cần xóa trên bảng và nhấn nút Xóa để xác nhận quyết định xóa.
Sau khi nhập đầy đú thông tin đăng ký tài khoản mới Chọn vào “ Thêm” để thêm mới tài khoản
Nếu nhập mã thẻ sai
Nếu thông tin nhập chính xác Click “ Đóng” để thoát khỏi Form
Trong Form này, danh sách và thông tin các tài khoản được trình bày trong một bảng Khi người dùng chọn một tài khoản để chỉnh sửa, thông tin của tài khoản đó sẽ hiển thị ở ô phía trên, cho phép người quản lý sửa đổi thông tin (ngoại trừ mã thẻ và số tiền) Sau khi hoàn tất chỉnh sửa, người quản lý cần nhấn nút "Sửa" để tiến hành cập nhật tài khoản.
Tại đây công cụ tìm kiếm thông minh sẽ cho phép người quản trị tìm kiếm tài khoản cúa khách hàng thông qua nhiều thông tin khác nhau
Nạp tiền vào tài khoản
Client Đăng nhập Tìm kiếm giao dịch
Giao diện chính tại Client
Xác nhận để tiến hành giao dịch
Nếu số tiền rút + 50.000đ lớn hơn số tiền trong tài khoản
Nếu bạn chưa nhập số tài khoản vào
Nếu chưa nhập số tiền
Nếu sai số tài khoản hoặc số tiền chuyển khoản + 50.000đ lớn hơn số tiền trong tài khoản chuyển
Chuyển khoản thành công Số tiền trong tài khoản chính bị trừ đi và được cộng vào tài khoản được chuyển
Nếu bạn nhập mã PIN cũ không chính xác
Thông báo đổi mã PIN thành công Mã PIN đã được đổi thành mã PIN mới Đổi mã PIN