Đồ án lập trình mạng phân tán
Đồ Án Lập Trình Mạng NHẬN XÉT CỦA GIÁO VIÊN HƯỚNG DẪN …………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… ………………..………………………………………………………….. ………………………………………………………………………………………… …… Lớp 11TLT – Nhóm 37 Trang 1 Đồ Án Lập Trình Mạng Mục Lục Phần I : Cơ sở lý thuyết.........................................................................................................................4 Lập Trình Mạng Phân Tán Và RMI......................................................................................................4 1. Mạng máy tính Phân tán............................................................................................................4 2. Các điểm mạnh trong hệ tin học phân tán:................................................................................4 3. Giới thiệu phương thức triệu gọi đối tượng từ xa RMI (Remote Method Invocation).............5 3.1 Triệu gọi phương thức từ xa....................................................................................................5 3.2 Kiến trúc RMI Java.................................................................................................................6 4. Thiết lập môi trường triệu gọi từ xa..........................................................................................8 4.1 Trên máy phục vụ (Server)......................................................................................................9 (a) Thiết lập giao diện từ xa..........................................................................................................9 (b) Xây dựng các lớp cài đặt các giao diện từ xa..........................................................................9 (c) Cài đặt các phương thức từ xa...............................................................................................11 (d) Xác định các đối tượng dịch vụ.............................................................................................12 (e) Bộ đăng ký RMI registry.......................................................................................................14 (f) Chi tiết về RMI registry và các cách tự đăng ký đối tượng....................................................15 4.2 Trên máy khách (Client)........................................................................................................16 5. Nhận xét về phương thức lập trình phân tán RMI...................................................................18 .............................................................................................................................................................19 Phần II: Bài tập....................................................................................................................................20 1. Hướng Giải quyết bài toán:.....................................................................................................20 2. Chương trình và kết quả demo................................................................................................22 Lớp 11TLT – Nhóm 37 Trang 2 Đồ Án Lập Trình Mạng Lời mở đầu Hệ tin học phân tán là hệ thống tin học hiện đại, đa dạng, phức tạp và đang trên đà phát triển, được nhiều trường đại học, nhiều viện nghiên cứu, nhiều chuyên gia công nghệ thông tin, quan tâm nghiên cứu với nhiều công trình khoa học có giá trị về mặt nguyên lý, phương pháp cũng như ứng dụng trong thực tế. Mục đích của lập trình mạng phân tán là tận dụng các khả năng tính toán và khai thác dữ liệu của các hệ thống máy tính ở xa để thực hiện những tính toán nhanh hơn trên cơ sở sử dụng nhiều bộ xử lý, nhiều bộ nhớ đồng thời hoặc nhiều dữ liệu quý giá được phân tán khắp nơi. Trên nền hệ thống mạng máy tính được kết nối như hiện nay, việc xử lý phân tán sẽ giải quyết được những bài toán lớn hơn, phức tạp hơn của thực tế. Trong phạm vi của đồ án này tôi chỉ đề cập đến hai phần: Phần 1 là phần lý thuyết về Lập trình mạng phân tán và RMI Phần 2 là phần bài tập, áp dụng thuật toán tại trạm sản xuất và trạm tiêu thụ để mô phỏng quá trình làm việc của hệ phân tán. Trong qua trình làm đồ án chắc chắn có nhiều sai sót. Kính mong sự chỉ bảo của Thầy giáo hướng dẫn cùng các bạn. Xin trân trọng cám ơn thầy Huỳnh Công Pháp đã cung cấp kiến thức, tài liệu để tôi hoàn thành đồ án này. Xin cảm ơn các bạn trong lớp đã giúp đỡ chúng tôi trong quá trình làm đồ án cũng như chia sẽ các kinh nghiệm học tập nghiên cứu. Đà Nẵng, ngày 4 / 6 / 2012 Lớp 11TLT – Nhóm 37 Trang 3 Đồ Án Lập Trình Mạng Phần I : Cơ sở lý thuyết Lập Trình Mạng Phân Tán Và RMI 1. Mạng máy tính Phân tán Hệ thống tính toán phân tán đã tạo được bước ngoặc vĩ đại so với các hệ tập trung, và hệ khách chủ (Client/Server). Việc tính toán phân tán về cơ bản cũng giống như việc tính toán của hệ khách chủ trên phạm vi rộng lớn. Dữ liệu được chứa trên nhiều máy chủ ở tại nhiều vị trí địa lý khác nhau kết nối nhau thông qua mạng diện rộng WAN hình thành các nơi làm việc, các phòng ban, các chi nhánh của một cơ quan. Tính toán phân tán hình thành từ tính toán tập trung và chient/server. Các mạng được xây dựng dựa trên kỹ thuật Web (ví dụ như: Internet; intranet…) là các mạng phân tán. Hệ thống cơ sở dữ liệu back-end có thể được nối kết với các server Web để lấy được các thông tin động. Kỹ thuật Web nầy đã mở ra hướng mới cho hệ phân tán. Các trình duyệt Web giúp cho khách hàng trên toàn cầu kết nối với hệ thống Web chủ, mà không bị khống chế bởi bất kỳ hệ điều hành nào đang chạy trong máy của khách hàng nầy. Một xu hướng mới khi xây dựng các intranet là dữ liệu phải được tập trung hóa tại một nhóm các máy chủ để có khả năng đáp ứng cùng một lúc cho nhiều người dùng. Giờ đây các hệ thống mainframe đã thật sự trở lại vì tính năng xử lý mạnh mẽ. Xu hướng nầy có lẽ trái ngược với việc tính toán phân tán nhưng trong thực tế chúng cùng tồn tại bên nhau. 2. Các điểm mạnh trong hệ tin học phân tán: Cơ chế tính toán phân tán hỗ trợ truy cập các dữ liệu được lưu ở nhiều nơi. Nhờ cơ chế nhân bản nên người dùng chỉ cần truy cập cục bộ cũng lấy được các thông tin từ các trung tâm chính ở rất xa. Hệ thống nầy khắc phục được các hiểm họa địa phương. Vì nếu chúng ta không truy cập dữ liệu được tại vị trí nầy, chúng ta có thể thử ở nơi khác. Dữ liệu phân tán đòi hỏi phải được nhân bản và đồng bộ hóa cao thông qua các mối liên kết mạng, điều nầy làm cho việc quản trị và giám sát phức tạp hơn. Một số nhà quản trị cho rằng, ở hệ thống như thế nầy sẽ gây khó khăn trong vấn đề bảo mật và điều khiển. Hệ phân tán được xây dựng trên giao thức TCP/IP và các kỹ thuật Web cùng với các ứng dụng trung gian (middleware) thúc đẩy việc tính toán phân tán. Quả thật đây là một đổi thay mang tính cách mạng. Nhiệm vụ trước mắt là làm thế nào để chuyển tiếp sang hệ nầy một cách khoa học. Cơ chế Client/Server cung cấp kiến trúc phù hợp cho việc dàn trải hệ thống phân tán. Mô tả nhiều cách truy cập trong các hệ thống phân tán. Các máy mainframe sẽ dùng để lưu trữ các dữ liệu di sản hoặc đóng vai trò kho dữ liệu (data warehouse). Cơ chế nầy giúp xây dựng các trung tâm dữ liệu staging (công bố), phục vụ tốt cho việc truy cập. Người dùng ở xa có thể truy cập dữ liệu trên hệ staging hay tại các máy chủ cục bộ. Người dùng còn có thể trao đổi thông tin với nhau bằng thư điện tử và hình thành các nhóm công tác Lớp 11TLT – Nhóm 37 Trang 4 Đồ Án Lập Trình Mạng 3. Giới thiệu phương thức triệu gọi đối tượng từ xa RMI (Remote Method Invocation) Ngày nay, cộng đồng những người lập trình bắt đầu nghĩ rằng “đối tượng có ở mọi nơi”. Những đối tượng này, tất nhiên được hỗ trợ để trao đổi được với nhau theo những giao thức chuẩn trên mạng. Ví dụ, bạn có một đối tượng ở máy trạm (máy khách - Client), ở đó người sử dụng cần phải điền dữ liệu vào mẫu báo cáo. Đối tượng này (đối tượng khách) có thể gửi một thông điệp (thỉnh cầu) cho đối tượng trên máy chủ (đối tượng phục vụ - Server) trên mạng để yêu cầu cung cấp các thông tin cần thiết. Đối tượng trên máy chủ truy nhập vào các CSDL để có được những thông tin mà khách yêu cầu và gửi lại cho đối tượng khách. Đó chính là ý tưởng của Java-RMI, phương thức lập trình triệu gọi từ xa. Lập trình phân tán đối tượng bằng cách triệu gọi phương thức từ xa RMI là cách hợp tác giữa các đối tượng Java có những mã lệnh cài đặt (bao gồm các phương thức và thuộc tính) nằm trên các máy khác nhau (chính xác là nằm trên các JVM – máy ảo Java khác nhau) và có thể triệu gọi lẫn nhau để trao đổi tin. Trong mô hình Client/Server truyền thống, các yêu cầu được dịch sang một format (dạng) trung gian (dạng từng cặp tên gọi / giá trị hoặc các dữ liệu trong XML). Máy chủ Server phân tích format yêu cầu, xử lý để có được kết quả và gửi trả lời cho máy khách Client. Máy khách phân tích format trả lời và hiển thị thông tin cho người sử dụng. 3.1 Triệu gọi phương thức từ xa Cơ chế triệu gọi từ xa có vẻ đơn giản hơn mô hình Client/Server. Nếu ta cần truy cập tới một đối tượng ở trên một máy khác thì ta chỉ cần triệu gọi phương thức của đối tượng ở trên máy đó. Tất nhiên, các tham số bằng cách nào đó phải được gửi đến cho máy kia và đối tượng nhận được phải chắc chắn thực hiện phương thức tương ứng để có được những thông tin cần thiết gửi trả lại cho đối tượng khách hàng. :Máy khách :Máy chủ Gửi yêu cầu về dữ liệu Trả lại thông tin yêu cầu Hình 3.1 Sự trao đổi giữa đối tượng khách và phục vụ (chủ) Lớp 11TLT – Nhóm 37 Trang 5 Đồ Án Lập Trình Mạng Tuy nhiên, việc triệu gọi phương thức của các đối tượng từ xa chắc chắn sẽ phức tạp hơn nhiều so với lời gọi hàm ở trong cùng một chương trình ứng dụng. Các đối tượng trên hai máy ảo khác nhau thì hoạt động trên hai tiến trình khác nhau, có hai không gian địa chỉ khác nhau, và vì thế việc tham chiếu tới các biến, địa chỉ đối tượng là hoàn toàn khác nhau. Lời gọi các hàm cục bộ thường luôn trả về kết quả sau khi thực hiện thành công, trong khi lời triệu gọi các phương thức từ xa phải thông qua kết nối mạng, có thể bị tắc nghẽn, bị ngắt do mạng gặp sự cố, … Đối với lời gọi hàm trên máy cục bộ, các tham số truyền cho hàm thường đặt vào ngăn xếp, trong khi tham số truyền cho các phương thức của đối tượng ở xa phải được đóng gói và chuyển qua mạng theo giao thức chuẩn để đến được đích với phương thức thực sự thông qua các đại diện trung gian. 3.2 Kiến trúc RMI Java Mục đích của kiến trúc RMI là tạo ra một mô hình đối tượng phân tán và được tích hợp với ngôn ngữ lập trình Java. Kiến trúc này đã thành công trong việc tạo ra một hệ thống an toàn và kế thừa được sức mạnh của Java trong xử lý phân tán và đa luồng. Về cơ bản, RMI được xây dựng dựa trên kiến trúc ba tầng như hình 3.2.1 Chương trình khách Hệ thống RMI Chương trình chủ Stub & Skeleton Stub & Skeleton Tham chiếu từ xa Tham chiếu từ xa Tầng giao vận Hình 3.2.1 Kiến trúc ba tầng của RMI Đầu tiên là tầng bao gồm hai lớp trung gian Stub và Skeleton, chúng được hệ thống tạo ra theo yêu cầu. Các lớp này chặn các lời gọi phương thức của chương trình khách (Client) tới các biến tham chiếu và gửi tới dịch vụ triệu gọi từ xa. Lớp Skeleton liên lạc với Stub thông qua liên kết RMI. Nó đọc các tham số của lời triệu gọi từ xa từ một liên kết nào đó, thực hiện lời gọi tới đối tượng thực thi dịch vụ từ xa và sau đó gửi các giá trị trả lại cho Stub. Trong Java 2 SDK, các giao diện mới được xây dựng đã làm cho Skeleton lỗi thời. RMI sử dụng phép ánh xạ để thực hiện việc kết nối tới các đối tượng dịch vụ từ xa thay cho Skeleton. Lớp 11TLT – Nhóm 37 Trang 6 Đồ Án Lập Trình Mạng Tầng tham chiếu từ xa là tầng tiếp theo. Tầng này dịch và quản lý các tham chiếu tới các đối tượng dịch vụ từ xa. Ở JDK1.1, tầng này thực hiện két nối theo cơ chế điểm – tới - điểm. Đến Java 2 SDK, tầng này được cải tiến để nâng cao việc hỗ trợ để kích hoạt các đối tượng dịch vu từ xa đang chờ thực hiện thông qua ROA, đó là cách kết nối Client/Server. Tầng giao vận dựa trên kết nối TCP/IP giữa các máy tính trong mạng. Ngay cả khi hai chương trình chạy trên hai JVM trong cùng một máy, chúng cũng thực hiện kết nối thông qua TCP/IP của chính máy đó. Tầng giao vận RMI được thiết kế để thiết lập một kết nối giữa máy Client với máy Server. Giả sử, ta có đối tượng C1 được cài đặt chạy trên máy phục vụ C. RMI của Java giúp ta tạo ra hai lớp trung gian C1_Skel (không cần thiết đối với Java 2 SDK) và C1_Stub. Lớp C1_Stub sẽ được nạp về máy khách B. Khi đối tượng B1 trên máy B triệu gọi C1, máy ảo Java sẽ chuyển lời gọi đến lớp C1_Stub. C1_Stub sẽ chịu trách nhiệm đóng gói các tham số và chuyển chúng qua mạng đến cho máy C. Tại máy C, lớp C1_Skel (C1_Stub được nạp về và thay thế ở Java 2 SDK) sẽ nhận tham số để chuyển vào không gian địa chỉ tương thích với đối tượng C1 sau đó gọi phương thức tương ứng để thực hiện. Kết quả nếu có do phương thức của đối tượng C1 trả về sẽ được lớp C1_Skel (C1_Stub thay thế ở Java 2 SDK) đóng gói trả ngược cho C1_Stub. C1_Stub chuyển giao kết quả cuối cùng cho B1. Theo cơ chế này, có thể hình dung như B1 đang trao đổi trực tiếp với đối tượng C1 ngay trên cùng một máy. Ngoài ra, với sự trợ giúp của lớp trung gian C1_Stub, khi kết nối mạng gặp sự cố, lớp trung gian Stub sẽ luôn biết cách thông báo lỗi đến đối tượng B1. Thực tế có một câu hỏi là: Làm thế nào để B1 tham chiếu được đến C1 khi không có lớp C1 nào được cài đặt ở máy B? C1_Stub trên máy B chỉ làm lớp trung gian chuyển đổi tham số và thực hiện các giao thức mạng, nó không phải là hình ảnh của đối tượng C1. Để làm được điều đó, lớp của đối tượng C1 cần cung cấp một giao diện tương ứng, được gọi là giao diện từ xa với các phương thức cho phép đối tượng B1 gọi nó trên máy B. Stub thường trực trên máy khách, không ở trên máy chủ. Nó có vai trò đóng gói các thông tin bao gồm: Định danh đối tượng từ xa cần sử dụng Mô tả về phương thức cần triệu gọi Mã hoá các tham số và truyền cho Skel. Stub sẽ chuyển những thông tin trên cho máy chủ. Ở phía máy chủ, đối tượng Skel nhận thực hiện những công việc sau để gọi phương thức từ xa: Giải mã các tham số Xác định đối tượng để thực hiện lời gọi hàm tương ứng Thực hiện lời gọi phương thức theo yêu cầu Tập hợp kết quả để trả lời hoặc thông báo các lỗi ngoại lệ Gửi trả lời gói các dữ liệu kết quả cho Stub ở trên máy khách. Lớp 11TLT – Nhóm 37 Trang 7 Đồ Án Lập Trình Mạng c: Client Gọi hàm cục bộ ở Stub Trả lại giá trị hoặc ngoại lệ :Stub :SKel Chuyển các gói các tham số s: Server Gọi hàm cục bộ ở Server Gửi trả lại kết quả hoặc ngoại lệ Hình 3.2.2 Sự trao đổi giữa đối tượng khách và phục vụ thông qua đối tượng trung gian Hình trên mô tả quá trình tổ chức gói các tham số, các dữ liệu trả lời và sự trao đổi giữa các đối tượng trung gian trong kỹ thuật triệu gọi từ xa. 4. Thiết lập môi trường triệu gọi từ xa Để thực hiện được việc triệu gọi từ xa thì ta phải chạy chương trình ở trên cả hai máy, máy khách và máy chủ. Những thông tin cần thiết cũng phải được cài đặt tách biệt ở hai phía, máy khách và máy chủ. Tuy nhiên không nhất thiết phải có hai máy tính riêng biệt. Nhờ có máy ảo Java, khi mở cửa sổ DOS-Prompt (môi trường DOS dưới Window) để chạy chương trình Java, chương trình này được xem như chạy trên một máy (ảo) độc lập. Do đó, nếu hai chương trình Java chạy ở trong hai cửa sổ riêng thì có thể xem như là chúng thực hiện trên hai máy khác nhau. Ví dụ: Chúng ta hãy bắt đầu từ một ví dụ đơn giản, chương trình trên máy chủ tạo ra hai sản phẩm: lò nướng bánh và lò vi sóng thuộc lớp Product. Sau đó chạy một chương trình trên máy khách để xác định thông tin về sản phẩm, giá bán của từng sản phẩm và in ra cho khách hàng. Lưu ý: Ví dụ này có thể chạy ở trên một máy đơn cũng như trên từng cặp máy kết nối mạng. Chúng ta có thể thực hiện theo cả hai cách. Nhưng ngay cả khi chạy trên một máy, thì cũng Lớp 11TLT – Nhóm 37 Trang 8 Đồ Án Lập Trình Mạng cần phải đảm bảo rằng các dịch vụ mạng là sẵn sàng. Đặc biệt phải chắc chắn rằng TCP/IP được hỗ trợ. 4.1 Trên máy phục vụ (Server) (a) Thiết lập giao diện từ xa Trong Java, đối tượng từ xa là thể hiện của một lớp cài đặt giao diện Remote . Tất cả các phương thức của các giao diện từ xa phải được khai báo public để các máy JVM khác có thể gọi được. Các giao diện từ xa phải đảm bảo những tính chất sau: Giao diện từ xa phải khai báo public. Giao diện từ xa kế thừa java.rmi.Remote. Mọi phương thức phải khai báo với mệnh đề throws để kiểm soát các ngoại lệ java.rmi.RemoteException. Kiểu dữ liệu của các đối tượng từ xa được truyền đi và giá trị nhận về phải được khai báo như là kiểu giao diện Remote, không phải là lớp. Chúng ta trở lại ví dụ cần tạo ra một cặp đối tượng sản phẩm tại máy chủ và máy phục vụ. Chương trình trên máy khách cũng phải biết được nó cần cái gì ở những đối tượng đó. Điều này thực hiện được nếu cả hai máy chia sẻ với một giao diện từ xa. interface Product // Chia sẻ bởi Client và Server extends Remote{ public String getDescription() throws RemoteException; public double getPrice() throws RemoteException; } Tất cả các phương thức của giao diện từ xa phải khai báo với throws RemoteException vì khi triệu gọi từ xa rất nhiều nguyên nhân làm cho nó thất bại, ví dụ, máy chủ, kết nối mạng không sẵn sàng, và nhiều vấn đề không bình thường, ngoại lệ khác gặp phải trên mạng. (b) Xây dựng các lớp cài đặt các giao diện từ xa Ở phía máy chủ, chúng ta phải xây dựng lớp cài đặt các phương thức được khai báo trong giao diện từ xa. Nói chung, các lớp các cài đặt đối tượng từ xa cần phải: Khai báo rằng nó cài đặt ít nhất một giao diện từ xa Định nghĩa đối tượng từ xa Cài đặt các phương thức để có thể triệu gọi được từ xa. public class ProductImpl // Server extends UnicastRemoteObject implements Product{ Lớp 11TLT – Nhóm 37 Trang 9 Đồ Án Lập Trình Mạng publicProductImpl(Strings,doublep)throwsRemoteException{ descr = s; price = p; } public String getDescription() throws RemoteException { return descr ; } public double getPrice() throws RemoteException { return price ; } private String descr; private double price; } Lớp ProductImpl cài đặt hai hàm getDescription(), getPrice() cho phép gọi được từ xa trong chương trình khách. Tất cả các lớp ở Server phải kế thừa từ RemoteServer trong gói java.rmi.server, nhưng RemoteServer là lớp trừu tượng, nó định nghĩa các cơ chế cơ sở để trao đổi tin giữa các đối tượng dịch vụ và các đại diện của chúng từ xa. Lớp UnicastRemoteObject là lớp con của RemoteServer. Object Remote RemoteObject RemoteServer RemoteStub UnicastRemoteObject Hình 4.1.1 Sơ đồ kế thừa các đối tượng từ xa Lớp UnicastRemoteObject tạo ra các đối tượng ở trên máy chủ. Đây là lớp cơ sở để xây dựng các lớp ứng dụng trao đổi thông tin từ xa trên máy chủ. Ngoài ra, ta có thể sử dụng lớp cơ sở MulticastRemoteObject để kế thừa, tạo ra những lớp ứng dụng chạy trên nhiều máy chủ đồng thời. Lưu ý: Khi sử dụng RMI, vấn đề đặt tên cho các lớp, giao diện là cần phải cẩn trọng. Để cho phù hợp, ta nên thực hiện theo những qui ước đặt tên như sau: Lớp 11TLT – Nhóm 37 Trang 10 Đồ Án Lập Trình Mạng + Không có hậu tố, ví dụ: Product + Có hậu tố Impl, ví dụ: ProductImpl + Có hậu tố Server, ví dụ: ProductServer + Có hậu tố Client, ví dụ: ProductClient + Có hậu tố _Stub, ví dụ: ProductImpl_Stub + Có hậu tố _Skel, ví dụ: ProductImpl_Skel + Giao diện từ xa + Lớp cài đặt giao diện + Chương trình tạo ra các đối tượng dịch vụ + Chương trình khách triệu gọi phương thức từ xa + Lớp đại diện máy khách được tự động tạo ra bởi chương trình rmic + Lớp đại diện máy chủ được tự động tạo ra bởi chương trình rmic Bởi vì đối tượng xuất ra thường gặp phải ngoại lệ java.rmi.RemoteException, nên ta phải định nghĩa toán tử tạo lập với mệnh đề throws RemoteException, thậm chí cả khi toán tử tạo lập không làm gì. Nếu ta quyên toán tử tạo lập thì chương trình dịch javac sẽ thông báo lỗi. (c) Cài đặt các phương thức từ xa Lớp cài đặt các đối tượng từ xa phải cài đặt tất cả các phương thức đã được khai báo trong giao diện từ xa. Ở ví dụ của chúng ta, phương thức từ xa phải cài đặt là: public String getDescription() throws RemoteException{ return descr; } public double getPrice() throws RemoteException{ return price; } Các tham số, các giá trị trả về của phương thức từ xa có thể là kiểu dữ liệu bất kỳ của Java, kể cả các đối tượng. Lưu ý: Một lớp có thể định nghĩa những phương thức không được khai báo trong giao diện từ xa, được gọi là phương thức cục bộ. Những phương thức cục bộ chỉ được gọi trong cùng một ứng dụng (cùng một JVM), không triệu gọi từ xa được. Sau khi hoàn tất lớp cài đặt, ta cần tạo ra các đại diện của lớp ProductImpl để mã hoá các tham số và nhận lại các kết quả của các lần triệu gọi phương thức từ xa. Người lập trình không sử dụng những lớp này trực tiếp và vì vậy cũng không phải tự viết chúng. Bộ công cụ rmic sẽ sinh ra chúng một cách tự động, ví dụ C:\j2sdk1.4.0\bin>rmic ProductImpl Kết quả là hai tệp lớp: ProductImpl_Stub.class và ProductImpl_Skel.class được sinh ra. Đối với Java 2 SDK thì tệp thứ hai không còn cần thiết nữa. Nếu lớp đặt trong một gói thì gọi rmic với tên của gói đó. Lớp 11TLT – Nhóm 37 Trang 11 Đồ Án Lập Trình Mạng (d) Xác định các đối tượng dịch vụ Để truy cập được đối tượng từ xa trên máy phục vụ, khách hàng cần có được đối tượng đại diện tại nơi đó. Khách yêu cầu đối tượng đó như thế nào? Phương thức chung là gọi phương thức từ xa của một đối tượng phục vụ và tạo ra một đối tượng đại diện để nhận kết quả trả lời. Hệ thống RMI cung cấp một bộ đăng ký (RMI registry) đối tượng từ xa để ta kết hợp với tên được thiết lập theo URL dạng “//host/objectname” giúp ta xác định được đối tượng phục vụ. Tên gọi là dãy các ký tự (xâu) xác định duy nhất. // Server ProductImpl p1 = new ProductImpl(“Lo nuong banh”, p); Naming.bind(“teaster”); Đối tượng p1 được ghi danh với tên gợi nhớ “teaster” bằng hàm Naming.bind(), hoặc hàm Naming.rebind(). thuộc package java.rmi.server.Naming static Remote lookup(String url) Tìm đến đối tượng từ xa theo địa chỉ url. Nếu chưa có đối tượng được đăng ký thì phát sinh ngoại lệ NotBoundException. static void bind(String name, Remote obj) Ghép (đóng gói) name với đối tượng từ xa obj. Nếu đối tượng đó đã có trong gói thì phát sinh ngoại lệ AlreadyBoundException. static void unbind(String name) Mở để lấy name ra khỏi gói. Nếu name không có trong gói thì phát sinh ngoại lệ NotBoundException. static void rebind(String name) Ghép (đóng gói) name với đối tượng từ xa obj. Cho phép thay thế những name đã được đóng gói. static String[] list(String url) Lấy ra một danh sách các tên đối tượng (xâu) đã được đăng ký ở địa chỉ url. Chương trình khách truy cập đến đối tượng phục vụ bằng cách chỉ ra tên của dịch vụ và tên đối tượng, sau đó ép về kiểu của giao diện từ xa như sau: // Client Product p = (Product)Naming.lookup(“rmi://yourserver.com/teaster”); Đối tượng p ở trên máy khách muốn triệu gọi phương thức từ xa của đối tượng có tên được đăng ký là “teaster” ở máy phục vụ thì gọi hàm Naming.lookup() để truy tìm tham chiếu tới đối tượng đó từ xa. RMIURL bắt đầu bằng “rmi:/” sau đó là Server, số hiệu cổng để lắng nghe (tuỳ chọn), dấu ‘/’ và sau đó là tên gọi của đối tượng triệu gọi từ xa. Ví dụ: rmi://localhost:99/teaster Lớp 11TLT – Nhóm 37 Trang 12 Đồ Án Lập Trình Mạng Số hiệu cổng mặc định là 1099. Chương trình ở máy phục vụ Server được viết đầy đủ như sau. // Product.java: giao diện từ xa Product import java.rmi.*; public interface Product extends Remote{ public String getDescription() throws RemoteException; public double getPrice() throws RemoteException; } // ProductImpl.java: cài đặt lớp ProductImpl ở máy Server import java.rmi.*; import java.rmi.server.*; public class ProductImpl extends UnicastRemoteObject implements Product{ public ProductImpl(String s, double p) throws RemoteException{ descr = s; price = p; } public String getDescription() throws RemoteException{ return descr; } public double getPrice() throws RemoteException{ return price; } private String descr; private double price; } // ProductServer.java: Chương trình phục vụ tạo ra 2 sản phẩm: Lò nướng bánh tên là teaster) và lò vi sóng (có tên là microwave). import java.rmi.*; import java.rmi.server.*; import sun.applet.*; public class ProductServer{ public static void main(String args[]){ try{ System.out.println("Cai dat dich vu ..."); Lớp 11TLT – Nhóm 37 Trang 13 // (có Đồ Án Lập Trình Mạng ProductImpl p1 = new ProductImpl("Lo nuong banh", 200.5); ProductImpl p2 = new ProductImpl("Lo vi song", 350.2); System.out.println("Dang ky dich vu ..."); Naming.rebind("teaster", p1); Naming.rebind("microwave", p2); System.out.println("Cho may khach trieu goi ..."); }catch(Exception e){ System.out.println("Error: " + e); } } } Tất cả các giao diện, lớp trên có thể gộp vào thành một gói. Sử dụng javac để dịch chúng để tạo ra các tệp lớp (đuôi .class) tương ứng trên thư mục hiện thời. (e) Bộ đăng ký RMI registry Chương trình dịch vụ của chúng ta hoàn toàn chưa sẵn sàng thực hiện. Vấn đề chính của chúng ta là cài đặt đối tượng của ProductImpl trên một máy và ở một máy khác (chương trình khác) muốn gọi phương thức getDescription() để biết được thông tin mô tả và giá bán của các sản phẩm có trên chương trình phục vụ. Như đã nói trước, ta không thể gọi trực tiếp của ProductImpl trực tiếp mà thông qua các lớp trung gian Stub và Skel (không cần thiết đối với Java 2 SDK). Ta thực hiện điều này nhờ trình biên dịch rmic như đã nêu ở trên. Hơn nữa, máy khách muốn triệu gọi được phương thức ở xa thì trước tiên nó phải liên lạc được với bộ đăng ký RMI registry của máy ở xa đó. Các hàm giao diện của Java thực hiện nhiệm vụ này được gọi là các hàm giao diện API JNDI. Các hàm JNDI ở máy khách sẽ liên lạc với RMI registry của máy chủ để nhận tham chiếu của đối tượng trong khi các hàm JNDI ở máy chủ lại có nhiệm vụ đăng ký tên đối tượng với RMI registry. Để khởi động RMI registry dưới nền Window 95 hoặc NT thì phải thực hiện start rmiregistry [port] ở cửa sổ lệnh của DOS Prompt hoặc ở hộp thoại Run, trong đó port là số hiệu cổng giao diện để chờ phục vụ và trả lời kết quả. Và tất nhiên, khi thiết kế các đối tượng RMI, cụ thể là các đối tượng cài đặt chi tiết trên máy phục vụ, ta phải ghi nhớ lấy số hiệu cổng này cho khớp. Nếu không chỉ định số hiệu cổng thì RMI registry ngầm định lắng nghe ở cổng 1099. Để khởi động registry ở một cổng khác, thì phải chỉ ra số hiệu của cổng đó trên dòng lệnh. Ví dụ, đăng ký ở cổng 2001: start rmiregistry 2001 Một vấn đề khác đáng quan tâm ở đây nữa là RMI registry không cho phép đăng ký hai đối tượng cùng tên. Muốn chỉnh sửa lại hệ thống chương trình triệu gọi phương thức từ xa, ta phải, hoặc là khởi động lại chương trình RMI Registry, hoặc là ngay từ đầu khi thiết kế chương trình Server của đối tượng, ta sử dụng phương thức rebind() thay vì phương thức bind() để đăng ký với RMI registry của máy phục vụ. Lớp 11TLT – Nhóm 37 Trang 14 Đồ Án Lập Trình Mạng (f) Chi tiết về RMI registry và các cách tự đăng ký đối tượng RMI registry đã được đề cập trên đây như một dịch vụ tìm kiếm đối tượng. Các đối tượng phục vụ muốn chương trình khách truy cập được từ xa thì phải đăng ký với RMI registry. Bộ đăng ký này là một chương trình dịch vụ chạy ở hậu trường, lắng nghe ở một cổng có số hiệu đã xác định. Hiện tại Java yêu cầu một máy ảo JVM chạy RMI registry và một máy JVM chạy chương trình Server (trên cùng một máy chủ). Một dịch vụ RMI registry có thể tiếp nhận và quản lý cùng lúc nhiều đối tượng dịch vụ khác nhau. Java cho phép liên lạc với bộ đăng ký RMI registry để lấy về danh sách các đối tượng chủ mà nó đang quản lý thông qua phương thức list() của đối tượng đã đăng ký như ví dụ dưới đây. //ListReg.java import java.rmi.registry.*; public class ListReg { public static void main(String[] args) throws Exception{ // Địa chỉ của máy nơi mà RMI Registry đang chạy String hostName = "localhost"; System.out.println("Connecting registry..."); // Kết nối với bộ đăng ký Registry reg = LocateRegistry.getRegistry(hostName); // Lấy về danh sách các đối tượng do RMI Registry đang qủan lý String objList[] = reg.list(); System.out.println("Resgitry object: "); for (int i = 0; i < objList.length; i++) System.out.prtinln(objList[i]); } } Java cho phép nhà lập trình tự tạo bộ đăng ký cho riêng mình mà không cần dùng đến rmiregistry.exe. Để tạo bộ đăng ký và tự đăng ký đối tượng, ta sử dụng phương thức tĩnh createRegistry() của lớp LocateRegistry. //CalculatorSetup.java import java.rmi.server.*; import java.rmi.*; import java.rmi.registry.*; public class ProductSetup { Lớp 11TLT – Nhóm 37 Trang 15 Đồ Án Lập Trình Mạng public static void main(String[] args) throws Exception { // Tạo bộ đăng ký registry LocateRegistry.createRegistry(2510); // Tạo đối tượng String name = “May in”; double p = 150.0; ProductImpl product = new ProductImpl(name, p); // Yêu cầu JVM nhận dạng product UnicastRemoteObject.exportObject(product); // Đăng ký product với dịch vụ truy cập System.out.println(“registering object …”); Naming.rebind(“rmi://localhost:2510/printer”, product); System.out.println(“waiting for client request …”); } } Biên dịch và cho thực thi chương trình thì khi chương trình hoạt động, nó tương đương với hai chương trình trước kia: rmiregistry.exe và ProductServer. 4.2 Trên máy khách (Client) Bây giờ ta hãy viết chương trình ở trên máy khách (chương trình khách) để yêu cầu chương trình phục vụ cung cấp những thông tin về các sản phẩm từ các đối tượng đã đăng ký. Với Java, tất cả các thao tác kết nối và sao chép các tệp tin từ một máy tính về máy khách đều phải thông qua lớp bảo vệ gọi là RMISecurityManager. Ví dụ, để chương trình khách ProductClient có thể nạp tự động ProductImpl_Stub.class từ Webserver, ta phải thiết lập lại cơ chế bảo vệ an ninh ở máy khách. System.setSecurityManager(new RMISecurityManager()); Hệ thống an ninh RMISecurityManager sẽ sử dụng các quyền được thiết lập trong tệp chính sách jre\lib\security\java.policy để kiểm soát việc kết nối từ xa (jre là thư mục chứa các tài nguyên tạo nên môi trường thực thi của Java). Để chương trình khách kết nối được với RMI registry và đối tượng phục vụ, ta cần sự hỗ trợ của tệp chính sách (tệp thường có đuôi .policy). Ở đây, tệp chính sách cho phép một chương trình ứng dụng tạo ra sự kết nối mạng qua các cổng có số hiệu ít nhất là 1024. Cổng RMI mặc định là 1099 và Server có thể sử dụng các cổng ≥ 1024. Ta có thể soạn tệp client.policy cho phép kết nối các cổng ≥ 1024: Lớp 11TLT – Nhóm 37 Trang 16 Đồ Án Lập Trình Mạng grant { permission java.net.SocketPermission “*:1024-65535”, “connect”; } Khi thực hiện chương trình khách, ta phải sử dụng chính sách (client.policy) (chi tiết xem [Cays]). java ProductClient –Djava.security.policy=client.policy Chương trình ở máy khách được viết như sau. // ProductClient.java: lớp ProductClient trên máy khách import java.rmi.*; import java.rmi.server.*; public class ProductClient{ public static void main(String args[]){ System.setSecurityManager(new RMISecurityManager()); String url = "rmi://localhost/"; String name = “”; double price = 0.0; // Thay bằng "rmi://yourserver.com/" // Khi Server chạy trên máy từ xa yourServer.com try{ Product c1 = (Product)Naming.lookup(url + "teaster"); Product c2 = (Product)Naming.lookup(url + "microwave"); name = c1.getDescription(); price = c1.getPrice(); System.out.println(name + ", gia ban: $ " + price); price = c2.getPrice(); name = c2.getDescription(); price = c2.getPrice(); System.out.println(name + ", gia ban: $ " + price); }catch(Exception e){ System.out.println("Error " + e); } System.exit(0); } } Trong ví dụ trên, giả sử tất cả các tệp Product*.* và client.policy được đặt ở D:\user\product, còn Java 2 SDK cài đặt ở C:\j2sdk1.4.0. Ta thực hiện các bước lần lượt như sau: 1. Dịch tất cả các tệp nguồn Java bắt đầu bằng Product D:\user\product>C:\j2sdk1.4.0\bin\javac Product*.java 2. Tạo ra các lớp trung gian Lớp 11TLT – Nhóm 37 Trang 17 Đồ Án Lập Trình Mạng D:\user\product>C:\j2sdk1.4.0\bin\rmic ProductImpl 3. Khởi động bộ đăng ký RMI registry D:\user\product>start C:\j2sdk1.4.0\bin\rmiregistry 4. Bắt đầu thực hiện chương trình phục vụ D:\user\product>start C:\j2sdk1.4.0\bin\java ProductServer 5. Thực hiện chương trình khách D:\user\product>C:\j2sdk1.4.0\bin\java ProducClient Kết quả sẽ in ra: Lo nuong banh, gia ban: 200.5 $ Lo vi song, gia ban: 350.2 $ Lưu ý: Ta có thể thiết lập biến môi trường bằng cách đặt đường dẫn để khi thực hiện không cần phải chỉ định như trên, ví dụ set classpath = D:\server\product; D:\client\product; c:\j2sdk1.4.0\bin 5. Nhận xét về phương thức lập trình phân tán RMI Xu hướng lập trình phân tán là xu hướng phát triển tự nhiên và là tất yêu của công nghệ phần mềm hiện nay. Đã có rất nhiều giải pháp cho vấn đề này: kiến trúc COM (Microsoft), CORBA (OMG), và hiện nay Web Services đang nổi lên là như lựa chọn tốt nhất. Cơ chế kết nối theo giao thức TCP/IP bằng khái niệm Socket bắt buộc ta phải dùng đến khái niệm cổng – port. Một trình chủ phải hoạt động và trao đổi qua một cổng chỉ định để lắng nghe các yêu cầu đến từ các máy khách. Tuy vậy, việc mở cổng đối với một máy chủ là một vấn đề hết sức thận trọng, và không dễ để thực hiện vì nó liên quan đến sự an toàn của các hệ thống trên mạng. Nếu ta xây dựng các ứng dụng trên mạng nội hạt (Intranet) thì điều này không thành vấn đề. Ta có thể chỉ định số hiệu của cổng bất kỳ cho socket trên máy chủ, miễn là những cổng này không trùng với những cổng phổ dụng mặc định cho các ứng dụng như Web, E-Mail, FTP. Tuy nhiên, đối với mạng diện rộng (Internet), thường nó bị kiểm soát nghiêm ngặt bởi bức tường lửa. Tường lửa là phần mềm (có thể được cài đặt hoặc điều khiển bởi phần cứng tuỳ theo nhà cung cấp) chặn cửa ra / vào của đường kết nối trao đổi dữ liệu của mạng nội hạt (mạng cục bộ) với bên ngoài (Internet). Mục đích là tránh sự đột nhập, sự tấn công hay ăn cắp thông tin của những người không được phép truy cập, của các tay hacker. Nó cũng được sử dụng để kiểm soát sự truy xuất ra bên ngoài mạng Internet. Vấn đề phát sinh chính là việc sử dụng các cổng kết nối. Hầu như tất cả bức tường lửa chỉ cho sử dụng một số hạn chế các cổng. Cổng kết nối giao thức http: 80 là cổng phổ dụng cho việc kết nối với Web Server. Một số cổng khác mà ta có thể được phép sử dụng như: cổng 21 cho ftp, 23 cho telnet và 110 cho POP3 Mail. Như vậy, ta sẽ gặp khó khăn khi sử dụng mô hình khách chủ và gặp phải bức tường lửa. Ứng dụng phân tán triệu gọi đối tượng từ xa có thể giải quyết vấn đề đối với tường lửa như sau: 1. Yêu cầu người quản trị bức tường lửa cung cấp một số cổng để kết nối. Lớp 11TLT – Nhóm 37 Trang 18 Đồ Án Lập Trình Mạng 2. Sử dụng cơ chế trung gian thông qua cổng 80, cổng phổ thông của dịch vụ Web Server. Cơ chế này còn được goi là cơ chế “đường hầm”. Như vậy, COM và RMI, về hiệu quả, cách thức hoạt động có nhiều nét tương đồng nhưng so với COM, RMI linh động hơn do sử dụng công nghệ Java, và do đó có thể được áp dụng cho nhiều hệ nền khác nhau (COM chỉ được áp dụng trên các hệ nền Windows). Cả hai đều có chung nhược điểm là đều phải thực hiện việc kết nối giữa các đối tượng qua các cổng chỉ định đã được mở từ trước. Web Services, là công nghệ mới phát triển gần đây sử dụng SOAP cho phép trình chủ và trình khách giao tiếp với nhau qua giao thức http, hay là qua cổng 80 – đây là cổng luôn được mở để phục vụ trên một http webserver, nên nhà phát triển dịch vụ này sẽ không lo lắng về vấn đề cổng giao tiếp nữa. Điểm thuận tiện khác, Web Services được xây dựng dựa trên nền tảng là XML – độc lập với các hệ nền và nó có thể nói là tựu trung tất cả các ưu điểm của các phương thức lập trình phân tán trước đó. SOAP cho phép dữ liệu chuyển đi bằng HTTP và định dạng theo chuẩn XML. Các công nghệ mới hiện nay, .NET Framework, Java đều đưa khả năng làm việc với Web Services vào như là một thành phần quan trọng. Nó cho phép triệu gọi lẫn nhau, bất chấp các đối tượng đó được viết bằng Java của Sun hay .NET của Microsoft. Lớp 11TLT – Nhóm 37 Trang 19 Đồ Án Lập Trình Mạng Phần II: Bài tập Áp dụng thuật toán tại trạm sản xuất và trạm tiêu thụ để mô phỏng quá trình làm việc của hệ phân tán. Bao gồm: + Xây dựng hệ 2 Server hoạt động theo nguyên lý trao đổi thông điệp + Xây dựng chương trình bằng Java thể hiện chức năng tại 2 trạm nêu trên + Viết chương trình mô phỏng trên màn hình quá trình hoạt động của hệ 1. Hướng Giải quyết bài toán: Ứng dụng lý thuyết lập trình mạng và RMI đã đề cập ở trên để xây dựng chương trình nhằm giải quyết bài toán. Trong bài toán này ta xét hai trạm là trạm sản xuất, ký hiệu là PS và trạm tiêu thụ, ký hiệu là CS. Ta gọi NP số lượng sản phẩm đã được sản xuất ra trên trạm sản xuất PS và NC là số lượng sản phẩm đã được trạm CS tiêu thụ. Tại trạm sản xuất PS ta đặt thêm một công tơ NC’. Trạm PS sẽ tăng giá trị của công tơ sự kiện NC’ thêm 1 đơn vị mỗi khi nhận được thông điệp từ trạm CS thông báo cho biết đã tiêu thụ thêm một sản phẩm. Tương tự, trên trạm CS ta đặt một công tơ NP’. Giá trị của công tơ sự kiện NP’ được tăng lên một đơn vị khi trạm CS nhận được thông điệp từ trạm PS thông báo đã có một sản phẩm vừa được sản xuất. Để giải quyết bài toán đã nêu ra, ta sử dụng một số hàm nguyên thủy sau: tang(E) : tăng giá trị công tơ lên một đơn vị cho(E,i) : treo cho đến khi giá trị của công tơ sự kiện E lớn hơn hoặc bằng i send(S): gửi thông điệp đến trạm S. receive(S): nhận thông điệp từ trạm S. Theo giả thiết của bài toán, trạm sản xuất PS chỉ có thể sản xuất sản phẩm nếu: NP – NC’ < N và trạm tiêu thụ CS chỉ có thể tiêu thụ sản phẩm nếu: NP’ – NC > 0 với: NP: số lượng sản phẩm đã sản xuất bởi trạm PS NC: số lượng sản phẩm đã tiêu thụ bởi trạm CS NC’: công tơ sự kiện tiêu thụ đặt trên trạm sản xuất PS NP’: công tơ sự kiện sản xuất đặt trên trạm tiêu thụ CS Ta gọi Pi là sản xuất thứ i và Ci là tiêu thụ thứ i. Ta thấy rằng: Pi → Pi+1 → Pi+N : tuân theo trật tự cục bộ của trạm sản xuất PS. Pi → Ci : tuân theo mối quan hệ nhân quả. Vấn đề của bài toán đến đây là cần phải chứng minh: Ci → Pi+N Trạm sản xuất PS chỉ sản xuất thêm sản phẩm nếu hiện tại số lượng còn lại (tức là lượng sản phẩm đã sản xuất nhưng chưa tiêu thụ được) nhỏ hơn N, tức là: Lớp 11TLT – Nhóm 37 Trang 20 Đồ Án Lập Trình Mạng NP – NC’ < N Nghĩa là trước khi thực hiện tiến trình sản xuất, trạm PS phải kiểm tra xem điều kiện: NP – NC’ < N có thỏa mãn hay không, nếu thỏa mãn mới sản xuất tiếp, nếu không thì tạm ngừng sản suất. Mỗi lần trạm PS sản xuất ra một sản phẩm thì NP sẽ tăng thêm một đơn vị (NP=NP+1) và trạm PS sẽ gửi thông điệp đến cho trạm CS (send(CS))để báo cho biết có một sản phẩm vừa được sản xuất. Tại trạm CS, khi nhận được thông điệp từ trạm PS thông báo có sản phẩm vừa được sản xuất (receive(PS)), trạm CS sẽ tăng giá trị công tơ sự kiện NP’ thêm một đơn vị (tang(NP’)). Trạm tiêu thụ CS chỉ có thể tiêu thụ sản phẩm nếu vẫn còn sản phẩm, nghĩa là: NP’ – NC > 0 Tức là trước khi tiêu thụ một sản phẩm, trạm CS phải kiểm tra điều kiện: NP’ – NC > 0 có thỏa mãn hay không, nếu thỏa mãn mới thực hiện việc tiêu thụ, còn ngược lại thì tạm ngừng việc tiêu thụ. Sau mỗi lần tiêu thụ sản phẩm, trạm CS sẽ tăng biến NC thêm một đơn vị (NC=NC+1) và gửi thông điệp thông báo cho trạm PS biết có sản phẩm vừa được tiêu thụ (send(PS)). Sau khi nhận được thông báo từ trạm CS (receive(CS)), trạm sản xuất PS sẽ tăng giá trị của công tơ sự kiện NC’ thêm một đơn vị (tang(NC’)). Thuật toán tại trạm sản xuất PS: Vòng lặp Nếu receive(CS) tang(NC’) cho(NC’,NP – N + 1) san_xuat() send(CS) NP = NP + 1 Kết thúc vòng lặp − Thuật toán tại trạm tiêu thụ CS: Vòng lặp Nếu receive(PS) tang(NP’) cho(NP’,NP + 1) tieu_thu() send(PS) NC = NC + 1 Kết thúc vòng lặp Lớp 11TLT – Nhóm 37 Trang 21 Đồ Án Lập Trình Mạng 2. Chương trình và kết quả demo // Server1.java (chua cac lenh sau) // Server1 dong vai tro la Tram San Xuat // khai bao interface cho Server1 import java.rmi.Remote; import java.rmi.RemoteException; public interface Server1 extends java.rmi.Remote { public abstract int sanxuatso() throws java.rmi.RemoteException; // Set thong tin den tram San xuat public abstract void setmessSX(java.lang.String message) throws java.rmi.RemoteException; public abstract java.lang.String getmessSX() throws java.rmi.RemoteException; public abstract void setcongtosukienSX(int ctsk) throws java.rmi.RemoteException; public abstract int getcongtosukienSX() throws java.rmi.RemoteException; public abstract void setnumSX(int number) throws java.rmi.RemoteException; public abstract int getnumSX() throws java.rmi.RemoteException; } // Server2Impl.java (chua cac lenh sau) // Server1 dong vai tro la Tram San Xuat // Thuc hien Implement cho Server1 import java.io.*; import java.util.*; import java.rmi.*; public class Server1Impl extends java.rmi.server.UnicastRemoteObject Runnable, Server1 { public Server1Impl() throws java.rmi.RemoteException { java.lang.System.out.println("Starting Server1..."); } static String nameserver2 = null; // Khai báo bien de giu tên cua Server2 static Server2 tramtt; static Thread thr; static int congtosukienSX=0; static Message mesinSX; // +++++ Lớp 11TLT – Nhóm 37 Trang 22 implements Đồ Án Lập Trình Mạng public synchronized int sanxuatso() { // thu ham random int i=0; try{ Random rd=new Random(); i=rd.nextInt(30); System.out.println("So random cua Tram San Xuat gui la:= "+ i); } catch(java.lang.Exception exception) { java.lang.System.out.println(exception.getMessage()); java.lang.System.exit(0); } return i; } //******************* public synchronized void setmessSX(java.lang.String message) { mesinSX.setmess(message); } public synchronized java.lang.String getmessSX() { return mesinSX.getmess(); } // voi bien congtosukien public synchronized void setcongtosukienSX(int ctsk) { mesinSX.setcongtosukien(ctsk); } public synchronized int getcongtosukienSX() { return mesinSX.getcongtosukien(); } // voi bien num public synchronized void setnumSX(int number) { mesinSX.setnum(number); } public synchronized int getnumSX() { return mesinSX.getnum(); } // ++++++ public void run() { try { //******* Cai dat thuat toan cho tram TT ****** mesinSX.setmess("ok"); mesinSX.setcongtosukien(1); Lớp 11TLT – Nhóm 37 Trang 23 Đồ Án Lập Trình Mạng mesinSX.setkiemtra(false); Util.mySleep(700); while(mesinSX.getkiemtra()==false ){ System.out.println("======================================"); System.out.println(" CUA SO LAM VIEC CUA TRAM SAN XUAT "); System.out.println("======================================"); tramtt=(Server2)java.rmi.Naming.lookup("rmi://localhost:1099/Server2"); String text = tramtt.getmessTT(); if(text.compareToIgnoreCase("sanxuat")==0){ System.out.println(" Dang Xu ly o Tram SX"); congtosukienSX=mesinSX.getcongtosukien(); System.out.println(" CongToSuKien o Tram SX la: "+ congtosukienSX); // lay gia tri congtosukien o tram TT de so sanh int ctskTT= tramtt.getcongtosukienTT(); // get ctsk o tram tieuthu System.out.println(" CongToSuKien o Tram TT la: "+ ctskTT ); if (ctskTT - congtosukienSX >= 0){ System.out.println(" Tram SX Dang san xuat"); mesinSX.setnum(this.sanxuatso()); congtosukienSX=congtosukienSX + 1; // tang ctsk o tram SX len mesinSX.setcongtosukien(congtosukienSX); //set lai gia tri cho ctsk o tr SX tramtt.setcongtosukienTT(congtosukienSX); // set lai cho bien ctsk o tr TT mesinSX.setmess("tieuthu"); //de yeu cau tram tieu thu tieu thu int tong= tramtt.gettongTT(); System.out.println("^^^ Gia tri tong o tram TT tra ve la: "+tong); } else tramtt.setmessTT("sanxuat"); } Util.mySleep(2000); System.out.println("Tram San Xuat dang doi thong diep de xu ly"); System.out.println( mesinSX.getmess()); System.out.println( tramtt.getmessTT()); if (mesinSX.getmess().compareToIgnoreCase("quit")==0) thr.stop(); } thr.stop(); } catch(java.lang.Exception exception){ java.lang.System.out.println(exception.getMessage()); java.lang.System.exit(0); } } Lớp 11TLT – Nhóm 37 Trang 24 Đồ Án Lập Trình Mạng public static void main(java.lang.String args[]) { java.lang.System.out.println("Creating Registry Server1..."); try { // ***** Khoi tao va Start Server o tram SX **** //Server1 tao ra doi tuong server1impl va dang ky no de san sàng cho viec goi tu xa java.rmi.registry.LocateRegistry.createRegistry(1999); Server1Impl server1impl = new Server1Impl(); java.rmi.Naming.rebind("rmi://" + args[0] + ":1999/Server1", server1impl); java.lang.System.out.println("Server1 Ready"); System.out.println("====**************************===="); thr = new Thread(server1impl); mesinSX = new Message();// khoi tao doi tuong message while (true){ String str = mesinSX.getmess(); if (str.compareToIgnoreCase("start")==0) { thr.start(); break; } Util.mySleep(200); } } catch(java.lang.Exception exception) { java.lang.System.out.println("Create registry failed " + exception.getMessage()); java.lang.System.exit(0); } } } // *************************************************** // Server2.java (chua cac lenh sau) // Server2 dong vai tro la Tram Tieu Thu import java.rmi.Remote; import java.rmi.RemoteException; public interface Server2 extends java.rmi.Remote { public abstract void tieuthuso() throws java.rmi.RemoteException; // Set thong tin den tram Tieu Thu public abstract void setmessTT(java.lang.String message) throws java.rmi.RemoteException; public abstract java.lang.String getmessTT() throws java.rmi.RemoteException; Lớp 11TLT – Nhóm 37 Trang 25 Đồ Án Lập Trình Mạng public abstract void setcongtosukienTT(int ctsk) throws java.rmi.RemoteException; public abstract int getcongtosukienTT() throws java.rmi.RemoteException; public abstract void setnumTT(int number) throws java.rmi.RemoteException; public abstract int getnumTT() throws java.rmi.RemoteException; public abstract int gettongTT() throws java.rmi.RemoteException; } // Server2Impl.java (chua cac lenh sau) // Server2 dong vai tro la Tram Tieu Thu import java.io.*; import java.rmi.*; import java.util.*; public class Server2Impl extends java.rmi.server.UnicastRemoteObject Runnable, Server2 { public Server2Impl() throws java.rmi.RemoteException { java.lang.System.out.println("Starting Server2..."); } static String nameserver1 = null; // Khai báo bien de giu tên cua Server1 static Server1 tramsx ; static int congtosukienTT=0; static Thread thrTT; static Message mesinTT;//=new Message(); //+++++++++++++++ public synchronized void setmessTT(java.lang.String message) { mesinTT.setmess(message); } public synchronized java.lang.String getmessTT() { return mesinTT.getmess(); } // voi bien congtosukien public synchronized void setcongtosukienTT(int ctsk) { mesinTT.setcongtosukien(ctsk); } public synchronized int getcongtosukienTT() { return mesinTT.getcongtosukien(); Lớp 11TLT – Nhóm 37 Trang 26 implements Đồ Án Lập Trình Mạng } // voi bien num public synchronized void setnumTT(int number) { mesinTT.setnum(number); } public synchronized int getnumTT() { return mesinTT.getnum(); } public synchronized int gettongTT() { return mesinTT.gettong(); } //************************************* public synchronized void tieuthuso() { try{ tramsx=(Server1)java.rmi.Naming.lookup("rmi://localhost:1999/Server1"); System.out.println("Toi ham tieu thu roi !!!!!!!!!!!!!!!!!!!!!!!!!!!"); int tam = mesinTT.gettong(); int num = tramsx.getnumSX(); tam= tam + num; mesinTT.settong(tam); System.out.println("**Ket qua tinh tong o tram Tieu thu bang = "+mesinTT.gettong()); } catch(java.lang.Exception exception) { java.lang.System.out.println(exception.getMessage()); java.lang.System.exit(0); } } //************ public void run(){ try{ //******* Cai dat thuat toan cho tram SX ****** mesinTT.setcongtosukien(0); mesinTT.setkiemtra(false); mesinTT.setmess("ok"); Util.mySleep(700); while(mesinTT.getkiemtra()==false){ System.out.println("======================================"); System.out.println(" CUA SO LAM VIEC CUA TRAM TIEU THU "); System.out.println("======================================"); tramsx=(Server1)java.rmi.Naming.lookup("rmi://localhost:1999/Server1"); Lớp 11TLT – Nhóm 37 Trang 27 Đồ Án Lập Trình Mạng String text = tramsx.getmessSX(); if(text.compareToIgnoreCase("tieuthu")==0){ System.out.println(" Dang Xu ly o Tram TT"); congtosukienTT=mesinTT.getcongtosukien(); System.out.println(" CongToSuKien o Tram TT la: "+ congtosukienTT); //lay gia tri congtosukien o tram SX de so sanh int ctskSX = tramsx.getcongtosukienSX(); System.out.println(" CongToSuKien o Tram SX la: "+ ctskSX); if ( ctskSX - congtosukienTT >=0 ){ System.out.println(" Tram TT Dang tieu thu"); tieuthuso(); congtosukienTT=congtosukienTT +1; //tang ctsk tram tieu thu len 1 mesinTT.setcongtosukien(congtosukienTT);//set lai value ctsk o TT tramsx.setcongtosukienSX(congtosukienTT); mesinTT.setmess("sanxuat"); } else tramsx.setmessSX("tieuthu"); } if (mesinTT.getmess().compareToIgnoreCase("stop")==0) mesinTT.settong(0); Util.mySleep(2000); System.out.println("Tram Tieu thu dang doi thong diep de xu ly"); System.out.println( mesinTT.getmess()); System.out.println( tramsx.getmessSX()); if (mesinTT.getmess().compareToIgnoreCase("quit")==0) thrTT.stop(); } thrTT.stop(); } catch(java.lang.Exception exception) { java.lang.System.out.println(exception.getMessage()); java.lang.System.exit(0); } } //*******************// public static void main(java.lang.String args[]) { java.lang.System.out.println("Creating Registry Server2..."); try { // ***** Khoi tao va Start Server o tram SX **** //Server2 tao ra doi tuong server2impl và dang ký nó de san sàng cho viec goi tu xa java.rmi.registry.LocateRegistry.createRegistry(1099); Server2Impl server2impl = new Server2Impl(); Lớp 11TLT – Nhóm 37 Trang 28 Đồ Án Lập Trình Mạng java.rmi.Naming.rebind("rmi://" + args[0] + ":1099/Server2", server2impl); java.lang.System.out.println("Server2 Ready"); System.out.println("====**************************===="); thrTT = new Thread(server2impl); mesinTT=new Message();//khoi tao doi tuong message while(true) { String str= mesinTT.getmess(); if (str.compareToIgnoreCase("start")==0) { thrTT.start(); break; } Util.mySleep(200); } } catch(java.lang.Exception exception) { java.lang.System.out.println("Create registry failed " + exception.getMessage()); java.lang.System.exit(0); } } } // Message.java (chua cac lenh sau) import java.io.*; import java.lang.*; public class Message { int idmess; //id cua thong diep (muc dich de de quan ly) private java.lang.String mess; private int tong; private boolean kiemtra; private int num; private int congtosukien; public Message() { mess="ok"; tong = 0; } // voi bien congtosukien public void setcongtosukien(int ctsk) { System.out.println("vua set gia tri cua cong to su kien la: "+ctsk); this.congtosukien=ctsk; } public int getcongtosukien() { Lớp 11TLT – Nhóm 37 Trang 29 Đồ Án Lập Trình Mạng System.out.println("vua get gia tri cua cong to su kien la: "+congtosukien); return this.congtosukien; } // voi bien num public void setnum(int number) { this.num=number; } public int getnum() { return this.num; } // voi bien mess public void setmess(java.lang.String message) { this.mess=message; } public java.lang.String getmess() { return this.mess; } // voi bien tong public int gettong() { return this.tong; } public void settong(int total) { this.tong=total; } // voi bien kiem tra public void setkiemtra(boolean kt) { this.kiemtra=kt; } public boolean getkiemtra() { return this.kiemtra; } } // Client.java (chua cac lenh sau) import java.io.*; import java.rmi.*; public class Client{ static Server1 sanxuat = null; static Server2 tieuthu =null; public static void main (String argv[]){ try{ sanxuat = (Server1)Naming.lookup("rmi://"+ argv[0] +":1999/Server1"); tieuthu= (Server2)Naming.lookup("rmi://"+ argv[0]+":1099/Server2"); Lớp 11TLT – Nhóm 37 Trang 30 Đồ Án Lập Trình Mạng DataInputStream inname=new DataInputStream(System.in) ; java.lang.System.out.println("Nhap chuoi dieu khien Vao: "); java.lang.System.out.println("1/ : bat dau thuc hien chuong trinh, khoi dong cac server hoat dong"); java.lang.System.out.println("2/ : Neu muon goi server San Xuat lam viec truoc "); java.lang.System.out.println("3/ : Neu muon goi server Tieu Thu lam viec truoc "); java.lang.System.out.println("4/ : Neu muon dung viec san xuat va tieu thu cua cac server lai"); java.lang.System.out.println("5/ : Neu muon dung hoat dong cua cac server va thoat"); while(true){ String str=inname.readLine(); if(str.compareToIgnoreCase("sanxuat")==0||str.compareToIgnoreCase("tieuthu")==0) { sanxuat.setmessSX("tieuthu"); tieuthu.setmessTT("sanxuat"); } if(str.compareToIgnoreCase("stop")==0){ sanxuat.setmessSX("Stop san xuat"); sanxuat.setcongtosukienSX(1); sanxuat.setnumSX(0); tieuthu.setmessTT("Stop tieu thu"); tieuthu.setcongtosukienTT(0); tieuthu.setnumTT(0); } if (str.compareToIgnoreCase("start")==0){ sanxuat.setmessSX("start"); tieuthu.setmessTT("start"); } if (str.compareToIgnoreCase("quit")==0) { sanxuat.setmessSX("quit"); tieuthu.setmessTT("quit"); } Util.mySleep(100); } }catch (Exception e){ System.out.println ("Client exception: " + e); } } } Lớp 11TLT – Nhóm 37 Trang 31 Đồ Án Lập Trình Mạng // MonitorTable.java (chua cac lenh sau) dung de display cac gia tri và theo dõi chúng import java.io.*; import java.awt.Component; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import java.rmi.*; public class MonitorTable extends JFrame { static DefaultTableModel dm; static JTable table; static JScrollPane scroll; // khai bao cac doi tuong tu xa static Server1 sanxuat = null; static Server2 tieuthu =null; MonitorTable() { super("Monitoring Server San xuat, Tieu thu"); dm = new DefaultTableModel() { public Class getColumnClass(int columnIndex) { return String.class; } }; table = new JTable(dm); int lines = 2; table.setRowHeight(table.getRowHeight() * lines); scroll = new JScrollPane(table); getContentPane().add(scroll); setSize(800,430); setVisible(true); } public static void viewTable(){ try{ //khoi tao cac doi tuong tu xa sanxuat = (Server1)Naming.lookup("rmi://localhost:1999/Server1"); tieuthu = (Server2)Naming.lookup("rmi://localhost:1099/Server2"); //khai bao cho table Object[] col =new Object[4]; Lớp 11TLT – Nhóm 37 Trang 32 Đồ Án Lập Trình Mạng col[0]="CTSK O Tram San Xuat"; col[1]="Tram San Xuat gui gia tri"; col[2]="CTSK O Tram Tieu Thu"; col[3]="Gia tri sau khi Tram Tieu Thu xu ly"; int i,k; for (k=0;k[...]... 33 Đồ Án Lập Trình Mạng Kết quả Demo Server1 được khởi tạo và đang lắng nghe để thực thi Server2 được khởi tạo và đang lắng nghe để thực thi Chương trình client khi chạy Lớp 11TLT – Nhóm 37 Trang 34 Đồ Án Lập Trình Mạng Màn hình hiển thị các giá trị công tơ sự kiện ở các trạm sản xuất, tiêu thụ và các giá trị của Server sản xuất và Server thụ gửi và nhận Lớp 11TLT – Nhóm 37 Trang 35 Đồ Án Lập Trình. .. 19 Đồ Án Lập Trình Mạng Phần II: Bài tập Áp dụng thuật toán tại trạm sản xuất và trạm tiêu thụ để mô phỏng quá trình làm việc của hệ phân tán Bao gồm: + Xây dựng hệ 2 Server hoạt động theo nguyên lý trao đổi thông điệp + Xây dựng chương trình bằng Java thể hiện chức năng tại 2 trạm nêu trên + Viết chương trình mô phỏng trên màn hình quá trình hoạt động của hệ 1 Hướng Giải quyết bài toán:... banh, gia ban: 200.5 $ Lo vi song, gia ban: 350.2 $ Lưu ý: Ta có thể thiết lập biến môi trường bằng cách đặt đường dẫn để khi thực hiện không cần phải chỉ định như trên, ví dụ set classpath = D:\server\product; D:\client\product; c:\j2sdk1.4.0\bin 5 Nhận xét về phương thức lập trình phân tán RMI Xu hướng lập trình phân tán là xu hướng phát triển tự nhiên và là tất yêu của công nghệ phần mềm hiện... diện máy khách được tự động tạo ra bởi chương trình rmic + Lớp đại diện máy chủ được tự động tạo ra bởi chương trình rmic Bởi vì đối tượng xuất ra thường gặp phải ngoại lệ java.rmi.RemoteException, nên ta phải định nghĩa toán tử tạo lập với mệnh đề throws RemoteException, thậm chí cả khi toán tử tạo lập không làm gì Nếu ta quyên toán tử tạo lập thì chương trình dịch javac sẽ thông báo lỗi (c) Cài... NC’ thêm một đơn vị (tang(NC’)) Thuật toán tại trạm sản xuất PS: Vòng lặp Nếu receive(CS) tang(NC’) cho(NC’,NP – N + 1) san_xuat() send(CS) NP = NP + 1 Kết thúc vòng lặp − Thuật toán tại trạm tiêu thụ CS: Vòng lặp Nếu receive(PS) tang(NP’) cho(NP’,NP + 1) tieu_thu() send(PS) NC = NC + 1 Kết thúc vòng lặp Lớp 11TLT – Nhóm 37 Trang 21 Đồ Án Lập Trình Mạng 2 Chương trình và kết quả demo // Server1.java... Mail Như vậy, ta sẽ gặp khó khăn khi sử dụng mô hình khách chủ và gặp phải bức tường lửa Ứng dụng phân tán triệu gọi đối tượng từ xa có thể giải quyết vấn đề đối với tường lửa như sau: 1 Yêu cầu người quản trị bức tường lửa cung cấp một số cổng để kết nối Lớp 11TLT – Nhóm 37 Trang 18 Đồ Án Lập Trình Mạng 2 Sử dụng cơ chế trung gian thông qua cổng 80, cổng phổ thông của dịch vụ Web Server Cơ chế... Product*.java 2 Tạo ra các lớp trung gian Lớp 11TLT – Nhóm 37 Trang 17 Đồ Án Lập Trình Mạng D:\user\product>C:\j2sdk1.4.0\bin\rmic ProductImpl 3 Khởi động bộ đăng ký RMI registry D:\user\product>start C:\j2sdk1.4.0\bin\rmiregistry 4 Bắt đầu thực hiện chương trình phục vụ D:\user\product>start C:\j2sdk1.4.0\bin\java ProductServer 5 Thực hiện chương trình khách D:\user\product>C:\j2sdk1.4.0\bin\java ProducClient.. .Đồ Án Lập Trình Mạng + Không có hậu tố, ví dụ: Product + Có hậu tố Impl, ví dụ: ProductImpl + Có hậu tố Server, ví dụ: ProductServer + Có hậu tố Client, ví dụ: ProductClient + Có hậu tố _Stub, ví dụ: ProductImpl_Stub + Có hậu tố _Skel, ví dụ: ProductImpl_Skel + Giao diện từ xa + Lớp cài đặt giao diện + Chương trình tạo ra các đối tượng dịch vụ + Chương trình khách triệu... price; } // ProductServer.java: Chương trình phục vụ tạo ra 2 sản phẩm: Lò nướng bánh tên là teaster) và lò vi sóng (có tên là microwave) import java.rmi.*; import java.rmi.server.*; import sun.applet.*; public class ProductServer{ public static void main(String args[]){ try{ System.out.println("Cai dat dich vu "); Lớp 11TLT – Nhóm 37 Trang 13 // (có Đồ Án Lập Trình Mạng ProductImpl p1 = new ProductImpl("Lo... RMI registry của máy phục vụ Lớp 11TLT – Nhóm 37 Trang 14 Đồ Án Lập Trình Mạng (f) Chi tiết về RMI registry và các cách tự đăng ký đối tượng RMI registry đã được đề cập trên đây như một dịch vụ tìm kiếm đối tượng Các đối tượng phục vụ muốn chương trình khách truy cập được từ xa thì phải đăng ký với RMI registry Bộ đăng ký này là một chương trình dịch vụ chạy ở hậu trường, lắng nghe ở một cổng có số .. .Đồ Án Lập Trình Mạng Mục Lục Phần I : Cơ sở lý thuyết .4 Lập Trình Mạng Phân Tán Và RMI Mạng máy tính Phân tán Các điểm mạnh hệ tin học phân tán: ... Lập Trình Mạng Phân Tán Và RMI Mạng máy tính Phân tán Hệ thống tính toán phân tán tạo bước ngoặc vĩ đại so với hệ tập trung, hệ khách chủ (Client/Server) Việc tính toán phân tán giống... phần: Phần phần lý thuyết Lập trình mạng phân tán RMI Phần phần tập, áp dụng thuật toán trạm sản xuất trạm tiêu thụ để mô trình làm việc hệ phân tán Trong qua trình làm đồ án chắn có nhiều sai