Mô hình Client - Server
Lời nói đầu Ngày với việc phát triển mạng máy tính việc viết ứng dụng máy đơn cục không đợc a chuộng thích hợp Các chơng trình ứng dụng đại phải tích hợp triệu gọi lẫn mạng Intranet (mạng cục bộ), mạng Internet (mạng toàn cầu) Tuy nhiên vấn đề nảy sinh , điểm bất đồng ngôn ngữ lập trình Các đối tợng thiết kế ngôn ngữ sau biên dịch dạng nhị phân (binary) có mà lệnh tơng ứng với ngôn ngữ có khả truy xuất đợc đối tợng Đối tợng C++ không dễ truy xuất đợc từ mà lệnh Delphi hay Visual Basic cách tự nhiên (MỈc dï cã mét sè kÜ tht nh sư dụng th viện liên kết động DLL nhng giải pháp toàn diện ) Các nhà lập trình mong muốn tìm đợc tiếng nói chung cho tất ngôn ngữ lập trình có Và CORBA đời CORBA ( Common Object Request Broker Achitecture) - tạm dịch Kiến trúc môi giới gọi đối tợng thông dụng CORBA đợc hình thành từ tổ chức nghiên cøu quèc tÕ OMG (Object Management Group ) víi sù hợp tác 800 công ty Tham vọng OMG đa cách để đối tợng viết ngôn ngữ khác triệu gọi lẫn theo mô hình đối tợng phân tán CORBA ngôn ngữ lập trình nh C++ hay Java CORBA ngôn ngữ đặc tả (description language) Sau trình bày trình ánh xạ (mapping) từ ngôn ngữ đặc tả sang ngôn ngữ cài đặt -1- I ánh xạ từ IDL sang C++ Giới thiệu: ánh xạ IDL sang C++ phải thoà mÃn yêu cầu sau : - ánh xạ phải có tính trực quan dễ sử dụng - phải bảo tồn ngôn ngữ chung C++ phải gần giống với C++ thờng - phải an toàn vỊ kiĨu - sư dơng cã hiƯu qu¶ chu kú CPU nhớ - thực cấu trúc nhớ đoạn nhớ vật lý - phải đợc hớng nội cho dùng môi trờng phân luồng - ánh xạ phải bảo toàn tính che giấu cục (tính suốt) Việc ánh xạ sang C++ phức tạp rộng lớn nhng khó Thứ nhất, ánh xạ thuận tiện ví dụ bạn hiểu rõ cách tổ chức quản lý nhớ kiểu String, luật quản lý kiểu liệu Variablelength, thứ hai, việc ánh xạ an toàn, không yêu cầu sắc thái bắt lỗi dễ dàng lúc biên dịch Thứ 3, ánh xạ dễ nhớ lớp có nhiều hàm thành viên, nhng bạn cần gọi số hàm chính, số hàm khác tồn mặc định để cung cấp chuyển đổi tham số truyền không cần phải gọi rõ ràng ánh xạ cho tên: Cỏc tên IDL bảo toàn ánh xạ sang C++ Để minh hoạ cho điều ta xét ví dụ sau: - Trong IDL: enum color {red, green, blue}; - Khi ánh xạ sang C++: enum color {red, green, blue}; Các ánh xạ sang C++ bảo toàn tốn tử phạm vi Ví dụ IDL toán tử phạm vi Outer :: Inner hợp lệ ánh xạ sang C+ + Outer :: Inner Một vấn đề phát sinh IDL ta dùng tên trùng với từ khoá trùng với từ khố C++: Ví dụ định nghĩa sau hoàn toàn hợp lệ IDL: Enum class {if, this, while, case }; ánh xạ sang C++ tự động thêm vào tiền tố: _cxx_ Vì có dạng sau: enum _cxx_class { _cxx_if, _cxx_this, _cxx_while, _cxx_case }; -2- tiền tố làm cho câu lệnh trở nên khó đọc, tốt ta nên tránh dùng chúng Bây xét chi tiết vào kiểu liệu Ánh xạ kiểu liệu Các kiểu liệu ánh xạ sang C++ mô tả bảng sau: OMG IDL C++ C++ Out Type short CORBA::Short CORBA::Short_out long CORBA::Long CORBA::Long_out unsigned short CORBA::UShort CORBA::UShort_out unsigned long CORBA::ULong CORBA::ULong_out float CORBA::Float CORBA::Float_out double CORBA::Double CORBA::Double_out char CORBA::Char CORBA::Char_out boolean CORBA::Boolean CORBA::Boolean_out octet CORBA::Octet CORBA::Octet_out Các kiểu liệu phức: Các kiểu liệu phức IDL ánh xạ sang C++ sau: OMG IDL C++ Object CORBA::Object_ptr struct C++ struct union C++ class enum C++ enum string char * Sequence C++ class array C++ array a> String Một chuỗi IDL ánh xạ sang C++ char * Cả chuỗi giới hạn chuỗi khơng giới hạn độ dài ánh xạ sang C++ char * Các chuỗi CORBA C++ kết thúc trỏ NULL Nếu chuỗi mà có chứa kiểu tự định nghĩa khác, ví dụ kiểu struct, ánh xạ sang kiểu C ORBA::String_v ar Điều đảm bảo -3- thành phần struct quản lý nhớ Các chuỗi phải cấp phát ngừng cấp phát việc sử dụng hàm thành phần sau lớp CORBA: • string_alloc // hàm cấp phát • string_dup • string_free // hàm huỷ Chú ý: hàm string_alloc cấp phát vùng nhớ có độ dài len+1 cịn chứa ký tự null b>.Enum Các kiểu enum IDL ánh xạ sang kiểu enum C++ // IDL module INVENT { enum Reply {ACCEPT, REFUSE}; } // C++ class INVENT { enum Reply {ACCEPT, REFUSE}; }; Tham chiếu đến thành phần sau hợp lệ: INVENT::Reply accept_reply; accept_reply = INVENT::ACCEPT; c> Struct Các kiểu struct IDL ánh xạ sang kiểu struct C++ Chúng ta xem xét cấu trúc có chiều dài cố định với cấu trúc có chiều dài thay đổi: // IDL module INVENT { // Chiều dài cố định struct Date { long year; -4- long month; long day; }; // Chiều dài thay đổi struct Address { string aptNum; string streetName; string city; string state; string zipCode; }; }; // C++ class INVENT { struct Date { CORBA::Long year; CORBA::Long month; CORBA::Long day; }; struct Address { CORBA::String_var aptNum; CORBA::String_var streetName; CORBA::String_var city; CORBA::String_var state; CORBA::String_var zipCode; Address &operator=(const Address &_obj); }; }; Đối với kiểu liệu thành phần struct ánh xạ sang kiểu tương ứng C++ Còn kiểu liệu như: tham chiếu đối tượng, tham chiếu giả đối tượng, chuối ánh xạ lớp _var tương ứng: • CORBA::string_var • CORBA::object_var d> Union -5- Một kiểu Union IDL ánh xạ sang lớp C++ Lớp chứa: • Các hàm tạo lập (Constructors) • Các hàm huỷ (Destructors) • Các tốn tử gán • Các thay đổi cho giá trị union • Các truy nhập cho giá trị union Ví dụ: // IDL union OrderItem switch (long) { case 1: itemStruct itemInfo; case 2: orderStruct orderInfo; default: ID idInfo; }; // C++ class OrderItem { public: OrderItem(); OrderItem(const OrderItem &); ~OrderItem(); OrderItem &operator=(const OrderItem&); void _d (CORBA::Long); CORBA::Long _d () const; void itemInfo (const itemStruct &); const itemStruct & itemInfo () const; itemStruct & itemInfo (); void orderInfo (const orderStruct &); const orderStruct & orderInfo () const; orderStruct & orderInfo (); void idInfo (ID); ID idInfo () const; }; -6- e> Các định nghĩa kiểu Các định nghĩa kiểu IDL ánh xạ trực tiếp sang định nghĩa kiểu C++ Nếu định nghĩa kiểu IDL gốc ánh xạ sang vài kiểu C++ trình biên dịch IDL sinh bí danh tương ứng cho kiểu C++ // IDL typedef octet example_octet; typedef enum enum_values { first, second, third } enum_example; // Kết C++ typedef octet example_octet; enum enum_values { first, second, third }; typedef enum_values enum_example; // bí danh tạo f> Modules Một module IDL nên ánh xạ sang namespace C++ với tên tương tự // IDL module ABC { // Definitions }; // Kết C++ class ABC { // Definitions }; g> Sequences -7- Các sequences IDL giưói hạn hay khơng giới hạn ánh xạ sang class C++ Chú ý: Khi chiều dài sequence không giới hạn vượt chiều dài cực đại C++ cấp phát suốt buffer lớn hơn, copy buffer cũ vào buffer giải phong nhớ khỏi buffer cũ Tuy nhiên, khơng thực giải phóng nhớ chưa dùng đến chiều dài cực đại giảm Xét ví dụ sau: ánh xạ sequence không giới hạn (unbounded)của IDL sang C++ // IDL typedef sequence LongSeq; // Results in the generation of this C++ code class LongSeq { public: LongSeq(CORBA::ULong max=0); LongSeq(CORBA::ULong max=0, CORBA::ULong length, CORBA::Long *data, CORBA::Boolean release = 0); LongSeq(const LongSeq&); ~LongSeq(); LongSeq& operator=(const LongSeq&); CORBA::ULong maximum() const; void length(CORBA::ULong len); CORBA::ULong length() const; const CORBA::ULong& operator[] (CORBA::ULong index) const; static LongSeq *_duplicate(LongSeq* ptr); static void _release(LongSeq *ptr); static CORBA::Long *allocbuf(CORBA::ULong nelems); static void freebuf(CORBA::Long *data); private: CORBA::Long *_contents; CORBA::ULong _count; CORBA::ULong _num_allocated: CORBA::Boolean _release_flag; CORBA::Long _ref_count; }; Ý nghĩa hàm môt tả bảng sau: Phương thức Mô tả -8- LongSeq(CORBA::ULong tạo lập cho sequence không giới hạn chiếm chiều dài max=0) cực đại tham số Các sequence giới hạn có chiều dài cực đại xác định LongSeq(CORBA::ULong Constructor cho phép bạn đặt chiều dài cực đại, chiều dài max=0, tại, trỏ tới đệm liệu kết hợp cờ giải CORBA::ULong length, phóng.Nếu cờ giải phóng khác 0, ISB C++ giải nhớ kết CORBA::Long *data, hợp với đẹm liệu tăng kích thước sequence Nếu cờ CORBA::Boolean giải phóng nhớ dệm liệu cũ khơng release=0) giải phóng Sequence giới hạn có tất thông số trừ max LongSeq(const LongSeq&) Bộ tạo lập chép thực chép sâu đối tượng nguồn ~LongSeq(); Destructor giải phóng tất nhớ sequence cờ giải phóng (release flag) có giá trị khác khơng tạo lập Operator=(const Tốn tử gán thực ao chép sâu, giải phóng việc lưu trữ LongSeq&j) cũ cần thiết Maximum() Trả lại kích thước sequence length() Hai phương thức định nghĩa cho việc đặt trả lại chiều dài sequence Operator[]() Hai toán tử mục cung cấp cho việc truy nhập phần tử sequence Một toán tử cho phép phần tử thay đổi cịn tốn tử cho phép truy nhập đọc phần tử _release() Giải phóng sequence Nếu cờ giải phóng tạo lập khác đối tượng khởi tạo kiểu phần tử sequence chuỗi tham chiếu đối tượng phần tử giải phóng trước buffer giải phóng allocbuf() Bạn nên dùng hai phương thức tĩnh để cấp phát hay huỷ freebuf() nhớ sử dụng sequence Quản lý nhớ sequence Bạn nên cân nhắc cẩn thận vấn đề quản lý nhớ đây: • Nếu cờ giải phống đặt giá trị khác sequence khởi tạo, sequence giả định quản lý nhớ người dùng Khi phần tử gán, nhớ cũ giải phóng trước quyền sở hữu nhớ biểu thức bên tay phải thừa nhận • Nếu cờ giải phóng đặt giá trị khác sequence khởi tạo phần tử sequence chuỗi hay tham chiếu đối tượng, phần tử giải phóng trước buffer chứa nội dung sequence giải phóng đối tượng bị huỷ • Tránh việc gán phần tử sequence sử dụng toán tử [] trừ cờ giải phóng đặt 1, lỗi quản lý nhớ xuất • Các sequence khởi tạo với cờ huỷ đặt không nên sử dụng tham biến đầu vào/ đầu lỗi quản lý nhớ dịch vụ đối tượng đưa đến kết -9- • Luôn sử dụng allocbuf freebuf để khởi tạo giải phóng kho lưu trữ sử dụng với sequence h> Array Các array IDL ánh xạ sang array C++, mà khởi tạo tĩnh Nếu phần tử array chuỗi tham chiếu đối tượng, phần tử mảng C++ có kiểu _var Ví dụ đoạn chương trình sau ba mảng với kiểu phần tử khác // IDL interface Intf { // definitions }; typedef long L[10]; typedef string S[10]; typedef Intf A[10]; // kiểu tham chiếu đối tượng // Kết C++ typedef CORBA::Long L[10]; typedef CORBA::String_var S[10]; typedef Intf_var A[10]; Cách sử dụng kiểu quản lý kiểu _var cho chuỗi tham chiếu đối tượng cho phép nhớ quản lý suốt phần tử mảng gán Các slice mảng Kiểu _slice mảng sử dụng truyền tham số cho mảng nhiều chiều Một slice mảng với tất chiều mảng gốc trừ chiều Kiểu mảng _slice cung cấp cách thuận lợi cho việc truyền trả lại tham số Một định ngh ĩa ki ểu cho m ỗi slice phát sinh // IDL typedef long L[10]; typedef string str[1][2][3]; // Results in the generation of these slices typedef CORBA::Long L_slice[10]; typedef CORBA::String_var str_slice[2][3]; typedef str_slice *str_slice_ptr; Nếu bạn có mảng chiều, mảng slice kiểu Như bạn thấy ví dụ trên, ta có mảng long L[10] mảng slice trả lại kết kiểu liệu CORBA::Long - 10 - MyObject_impl servant(42); // tạo đối tợng CORBA sử dụng servant tạo MyObject_var object= servant_this(); Dòng đầu đoạn code tạo thể servant thiết lập giá trị 42 điểm tất chơng trình cần có đối tợng C++ không kết nối servant đối tợng CORBA đà đợc tạo Dòng hai đoạn m· lµ lêi gäi hµm _this cđa servant,nã thøc hiƯn bớc sau: - Tạo đối tợng CORBA dới root POA - Đăng kí servant với root POA thực thi cho đối tợng - Tạo tham chiếu đối tợng cho đối tợng - Trả tham chiếu đối tợng Hàm _this đợc cung cấp lớp skeleton đoạn mà dới cho biết lớp POA_MyObject đợc sinh Cho lớp skeleton POA_A miêu tả giao tiếp IDL Và giá trị trả hàm POA_A::_this A_ptr, kiểu tham chiếu đối tợng C++ cho giao tiÕp A theo vÝ dơ tríc kiĨu tr¶ hàm this MyObject_ptr Bởi lời gọi hàm _this chịu trách nhiệm đảm bảo CORBA::release cuối đợc gọi kiểu tham chiếu đối tợng đợc trả đà gán giá trị trả cho biến MyObject_var Trong ví dụ đối tợng CORBA đợc tạo hàm _this đối tợng tồn ngắn ngủi Đối tợng CORBA tồn ngắn ngủi ràng buộc với thời gian tồn POA mà đợc tạo Tuy nhiên hàm _this cung cấp cách thức tạo khuôn dạng việc dịch vụ đăng kí POA servant đợc tạo với cách thức hợp lý Tập chuẩn cách thức đợc hỗ trợ root POA đợc thiết kế rõ ràng phép hàm _this đợc sử dụng theo kiểu Server main Để hoàn tất ứng dụng server đơn giản chơng trình, chơng trình phải cung cấp hàm main nh sau: #include “my_objects.hh” #include “iostream.h” int main(int argc, char *args[]) { // khëi t¹o ORB CORBA::ORB_var orb=CORBA::ORB_init(argc, argv); // LÊy tham chiÕu ®Õn Root POA CORBA::Object_var obj = orb->resolve_inittial_references(“Root POA”); Portable Server::POA_var poa=PortableServer::POA::_narrow(obj); // KÝch ho¹t manager cđa POA Portable Server::Manager_var mgr=poa->the_POAmanager(); - 19 - Mrg=activeti(); // Tạo servant MyObject sau tạo ngầm đối tợng CORBA khởi // t¹o nã víi servant MyObject_impl servant(42); MyObject_var object = servant_this(); // Chuyển đổi tham chiếu đối tợng sang dạng xâu đa thiết bị chuẩn CORBA::String_var str = orb->object_tc_string(object); Cout Trun tham sè kiĨu phøc tạp có độ dài thay đổi kiểu any Những kiểu liệu phức tạp có độ dài biến đổi bao gồm :sequence,struct,union mà có chứa thành phần có ®é dµi biÕn ®ỉi vÝ dơ: struct vls { long l_mem; string s_mem; }; interface foo { vls vls_op ( in vls vls_in, out vls vls_inout, inout vls vls _out, ) }; ph¬ng thøc t¬ng øng líp skeleton class poa::public virtual portable server :: servantbase{ public : virtual vls* vls_op( const vls & vls_in, vls & vls_inout, vls_out vls_out ) throw (CORBA::systemexception)=0; //… }; - 27 - + tham sè trun vµo lvs_in vµ tham sè vµo lvs_inout có quy tắc nh kiểu phức có độ dài cố định + quy tắc tham số có độ dài thay khác biệt với kiểu có độ dài cố định Đặc biệt ta phải cấp phát ®éng cho tham sè cã ®é dµi thay ®ỉi trả giá trị ,sử dụng toán tử new trả chúng trỏ client mà trách nhiệm giải phóng chúng toán tử delete vls_out =new vls; //… vls *reusult =new vls; return result ; phơng thức chơng trình khởi tạo vls_out việc gọi toán tử new 6.6> truyền tham số mảng với thành phần có độ dài thay đổi Việc quản lý nhớ cho mảng với phần tử có độ dài thay đổi tơng tự với kiểu liệu có độ dài thay đổi Vd : Struct vls { Long nunber ; String name; }; typedef vls varr[3]; inteface Foo { Varr varr_op ( in Varr varr_in, inout Varr varr_inout , out Varr varr_out, ); }; líp skeleton class POA_Foo ::virtual PortableServer :: ServantBase { - 28 - public : virtual Varr_slice * varr_op( const varr varr_in, vass slice * varr_inout, ) thow (CORBA::SystemException)=0; } cài đặt varr_slice * Foo::varr_op( ) { const int array_length =sizeof(varr_in)/sizeof(*varr_in); int i; // thay doi varr_inout vass_inout[0]=varr_out[0]; //t¹o khëi t¹o varr_out varr_out=varr_alloc(); const char * brothes[]={“john”,”jin”,”rich”}; for (i=0;i< array_length;i++)] varr_out[i].number=i-1; varr_out[i].name=brothes[i] } //tạo khởi tạo giá trị trả varr_slice * result =varr_alloc(); const char * sisters[]={“aa”,”jbbb”,”ccc”}; for (i=0;i< array_length;i++)] result[i].number=i-1; - 29 - result[i].name=brothes[i] } return result; ] + viƯc qu¶n lý bé nhí nh sau : Tham sè vào varr_in đựoc sử lý nh mảng hần tử có độ dài cố định , client cấp phát khởi tạo phơng thức ta đọc phần tử , ta không cần có trách nhiệm quản lý nhớ Tơng tự tham số vào varr_inout định cấp phát khởi tạo client Nhng trờng hợp đợc phép thay đổi giá trị chúng, tham số đợc truyền kiểu varr_slide* cho phép đánh số mảng nh trờng hợp tự nhiên Phơng thức trách nhiệm phải quản lý nhớ ã Tham số varr_out đợc truyền kiểu varr_out tơng với varr_slide* tham chiếu tới trỏ varr_slide* sử dụng hàm varr_alloc để cấp phát động lời gọi phơng thức servant nh máy client (trên máy) ORB cục có trách nhiệm gọi varr_free để giải phóng vùng nhớ mảng Không nên sử dụng toán tử new không khả chuyển sinh lỗi thời gian chạy mảng đợc giải phóng ã Chúng ta cấp phát khởi tao giá trị trả nh tham số lời gọi có trách nhiệm đảm bảo trỏ trả cuối đợc truyền tới varr_free 6.7 Truyền tham số tham chiếu đối tợng Tham chiếu đối tợng kiểu có độ dài thay đổi tơng tự trỏ Quy tắc truyền tham số chúng tơng tù ®èi víi kiĨu string VD: Interface Foo{ Foo ref_op( In Foo ref_in; Inout Foo ref_inout; Out Foo ref_out; ); - 30 - void say_hello(); }; Líp Skeleton: Class POA_Foo: public virtual Portable Server:: Servant Base { Public: Virtual Foo_ptr ref_op( Foo_ptr ref_in; Foo_ptr & ref_inout; Foo_out ref_out; )throw (CORBA::SystemException)=0; // }; Cài đặt ref_op Foo_impl:: Say_hello() throw (CORBA: System Exeption) { cout