CORBA中的異步傳輸機制
(本文轉(zhuǎn)載自軟件工程專家網(wǎng) www.21cmm.com )
于國良
本文主要討論了的CORBA的異步傳輸機制ONEWAY以及事件服務(wù)。同時給出用DELPHIL利用ONEWAY以及事件服務(wù)異步傳輸機制實現(xiàn)的簡單模型。
我們通常討論的CORBA模型往往從客戶機激發(fā)遠程方法的角度來討論C O R B A系統(tǒng)。象通常的客戶機和服務(wù)器模型:客戶機和服務(wù)器組件分別運行在不同的機器上,客戶機發(fā)出一個請求,然后客戶機阻塞。服務(wù)器主動監(jiān)聽從客戶機來的請求。當收到一個請求后,服務(wù)器處理這個請求,并把結(jié)果返回給發(fā)出請求的客戶機。客戶機在等待回應(yīng)時是阻塞的,只有在它接收到回答后才能繼續(xù)處理。
在很多場合中,這種模型正好是用戶所希望的。而且這種模型也符合傳統(tǒng)的C/S模型,有問有答。但是在很多場合中并不需要這種模型,象股票系統(tǒng)中,普通股民眼中的價格更新,SCADA電力系統(tǒng)中的現(xiàn)場數(shù)據(jù)的顯示等,都是不需要客戶機發(fā)出請求,服務(wù)器就把結(jié)果返回給客戶。還有在很多場合中,客戶機發(fā)出一個請求后,并不希望得到服務(wù)器的回答,它需要的只是給服務(wù)器一個通知,象SCADA電力系統(tǒng)中的前置機往服務(wù)器上發(fā)數(shù)據(jù),前置機并不需要等待這個服務(wù)器上的回答返回。為解決上述問題,CORBA提出了ONEWAY以及事件服務(wù)異步傳輸機制。
ONEWAY異步傳輸,顧名思義,ONEWAY就是"單向",即客戶機發(fā)出它們的激發(fā),然后繼續(xù)處理,而用不著在發(fā)出一請求后阻塞,直到結(jié)果返回,當服務(wù)器完成對該請求的處理后,它可以通過向客戶機發(fā)回一相應(yīng)的單向激發(fā)把結(jié)?quot;返回",也可以不返回結(jié)果。
利用ONEWAY異步傳輸比較簡單,它的一般步驟與普通CORBA應(yīng)用一樣:
1. 首先定義接口的IDL文件。
2. 編譯IDL文件。
3. 編寫服務(wù)器端程序。
4. 編寫客戶端程序。
這里我以DELPHI6(在DELPHI6中CORBA規(guī)范是由VisiBroker產(chǎn)品來實現(xiàn)的)為開發(fā)工具,來實現(xiàn)ONEWAY異步傳輸:
1. 首先定義接口的IDL文件:為了簡單,我這里只定義了一個ONEWAY的方法。
module Pro
{
interface IOnewDemo;
interface IOnewDemo
{
oneway void onewaya(in long aa);
};
interface OnewDemoFactory
{
IOnewDemo CreateInstance(in string InstanceName);
};
};
2.和3在DELPHI6中,第二步和第三步是和在一起的。
選FILE-NEW-OTHER-CORBA-CORBA Server Application 在出現(xiàn)的IDL2Pas Create Server Dialog中按Add按鈕加入剛才定義的IDL文件,按OK按鈕以后,由IDL2Pas編譯器來對它進行編譯,生成Pro_c.pas,Pro-i.Pas,Pro_Impl.pas,Pro_s.pas四個文件,在Pro_Impl.pas文件中定義
procedure TIOnewDemo.onewaya ( const aa : Integer);
begin
form1.ListBox1.Items.Clear;
form1.ListBox1.Items.Add(inttostr(aa));
end;
在程序啟動時進行初始化
procedure TForm1.FormCreate(Sender: TObject);
var
Acct: IOnewDemo;
begin
CorbaInitialize;
// Add CORBA server code here like this
Acct := TIOnewDemoSkeleton.Create('ygl', TIOnewDemo.Create);
BOA.ObjIsReady(Acct as _Object);
end;
編譯生成服務(wù)器端程序。
4. 編寫客戶端程序:
在程序啟動時進行初始化
procedure TForm1.FormCreate(Sender: TObject);
var
Acct: IOnewDemo;
begin
CorbaInitialize;
// Bind to the Corba server like this
Acct := TIOnewDemoHelper.bind;
end;
調(diào)用接口定義方法
procedure TForm1.Timer1Timer(Sender: TObject);//utilize the mothod of interface
var
i:integer;
begin
randomize;
i:=random(20);
acct.onewaya(i);
end;
編譯生成客戶器端程序。
CORBA中的事件服務(wù)是基于以下的原因定義的:
事件發(fā)送者和事件接收者的關(guān)系是松偶合的:事件發(fā)送者發(fā)送消息時,并不關(guān)心誰會收到消息。事件接收者接收消息時,也并不關(guān)心誰發(fā)送的消息。這里事件發(fā)送者稱為事件供應(yīng)者,事件接收者稱為事件消費者。
在VisiBroker的事件實現(xiàn)中,它定義了兩種事件模型:PUSH模型和PULL模型:如果一個事件是由供應(yīng)者主動發(fā)出,消費者被動接收,就稱為PUSH模型,如果一個事件是由消費者主動索取,供應(yīng)者被動提供,就稱為PULL模型。
PUSH模型可以簡單表示為:
DELPHI6中在COSEVENT單元中定義了通用的接口:
PushConsumer , PushSupplier, PullSupplier , PullConsumer, ProxyPushConsumer
ProxyPullSupplier , ProxyPullConsumer , ProxyPushSupplier , ConsumerAdmin , SupplierAdmin , EventChannel…..
這里我用PUSH模型簡單說一下通訊建立的過程:
供應(yīng)者端:
1. 供應(yīng)者獲得一個SupplierAdmin對象。供應(yīng)者通過調(diào)用Event_Channel的for_suppliers得到一個SupplierAdmin對象。
2. 供應(yīng)者獲得一個ProxyPushConsumer對象。供應(yīng)者通過調(diào)用SupplierAdmin的obtain_push_consumer得到一個ProxyPushConsumer對象。
3. 供應(yīng)者利用ProxyPushConsumer對象的connect_push_supplier連接遠方的ProxyPushSupplier對象。
消費者端:
1. 消費者獲得一個ConsumerAdmin對象。消費者通過調(diào)用Event_Channel的for_consumers得到一個ConsumerAdmin對象。
2. 消費者獲得一個ProxyPushSupplier對象。消費者通過調(diào)用ConsumerAdmin的obtain_push_supplier得到一個ProxyPushSupplier對象。
3. 消費者利用ProxyPushSupplier對象的connect_push_consumer連接遠方的ProxyPushConsumer對象。
在DELPHI6中對事件服務(wù)的PUSH模型實現(xiàn)的例子如下:
供應(yīng)者端:
實現(xiàn)TpushSupplier類
TPushSupplier = class(TInterfacedObject, PushSupplier)
public
constructor Create;
procedure disconnect_push_supplier;
end;
主程序:
procedure TForm1.FormCreate(Sender: TObject);
var
PushSupplier_Skeleton,PushSupplier_Skeletonaaa : PushSupplier;
Event_Channel,Event_Channelaaa : EventChannel;
Supplier_Admin,Supplier_Adminaaa : SupplierAdmin;
Push_Consumer,Push_Consumeraaa : ProxyPushConsumer;
myAny:any;
begin
CorbaInitialize;
// Create the skeleton and register it with the boa
PushSupplier_Skeleton:=TPushSupplierSkeleton.Create('ygl', TPushSupplier.Create);
BOA.SetScope( RegistrationScope(1) );
BOA.ObjIsReady(PushSupplier_Skeleton as _Object);
//bind to the event channel and get a Supplier Admin object
獲得事件信道接口,bind的參數(shù)是下面命令行中的參數(shù)ygl:
Event_Channel := TEventChannelHelper.bind('ygl');
//可以連接另一個事件信道bind的參數(shù)是另一個實例中的參數(shù)yglaaa:
// Event_Channelaaa := TEventChannelHelper.bind('yglaaa');
獲得SupplierAdmin接口:
Supplier_Admin := Event_Channel.for_suppliers;
//get a push consumer and register the supplier object
獲得ProxyPushConsumer接口:
Push_Consumer := Supplier_Admin.obtain_push_consumer;
連接ProxyPushSupplier接口
Push_Consumer.connect_push_supplier(PushSupplier_Skeleton);
往信道中推數(shù)據(jù)
randomize;
myany:= random(1000);
try
Push_Consumer.Push(myAny);
except
on EDisconnected do ShowMessage('Client Disconnected');
end;
end;
消費者端:
實現(xiàn)TPushConsumer類
TPushConsumer = class(TInterfacedObject, PushConsumer)
public
constructor Create;
procedure push(const data : Any);
procedure disconnect_push_consumer;
end;
這里,重要的方法是:
procedure TPushConsumer.push(const data : Any);
var
num :integer
begin
num := data;
Form1.ListBox1.Items.Add(IntToStr(num));
end;
它表示消費者收到數(shù)據(jù)后的處理。
主程序:
procedure TForm1.FormCreate(Sender: TObject);
var
PushConsumer_Skeleton : PushConsumer;
Event_Channel : EventChannel;
Consumer_Admin : ConsumerAdmin;
Push_Supplier : ProxyPushSupplier;
begin
CorbaInitialize;
// Create the skeleton and register it with the boa
PushConsumer_Skeleton:=TPushConsumerSkeleton.Create('ygl', TPushConsumer.Create);
BOA.SetScope( RegistrationScope(1) );
BOA.ObjIsReady(PushConsumer_Skeleton as _Object);
獲得事件信道接口:
//bind to the event channel and get a Supplier Admin object
Event_Channel := TEventChannelHelper.bind('ygl');
獲得ConsumerAdmin接口:
Consumer_Admin := Event_Channel.for_consumers;
//get a push consumer and register the supplier object
獲得ProxyPushSupplier;接口:
Push_Supplier := Consumer_Admin.obtain_push_supplier;
連接ProxyPushConsumer接口
Push_Supplier.connect_push_consumer(PushConsumer_Skeleton);
end;
程序運行:
首先運行SmartAgent,再在…\VisiBroker\bin下以命令行方式運行channel ygl 然后分別運行供應(yīng)者端,消費者端程序。
在這里要注意兩個方面的問題:
1.由于大多數(shù)O R B使用T C P作為它們底層的傳輸,而T C P是一可靠的協(xié)議,所以即使用戶認為是非阻塞的調(diào)用,實際上在T C P層還是阻塞的調(diào)用。用戶的客戶機應(yīng)用程序可能不等待服務(wù)器應(yīng)用程序接收并開始處理請求,但是客戶機的T C P / I P棧卻要等待,直到請求緩沖區(qū)被服務(wù)器的T C P / I P棧成功接收(和確認)。
2. 在Visibroker中并沒有提供事件粒度的控制-過濾功能。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2319
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
