?軟件接口概念
計(jì)算機(jī)世界里的接口這兩個(gè)字具有兩種眾所周知的含義:其一是指軟件本身的狹義“接口”,比如各種軟件開(kāi)發(fā)API等。其二則指的是人與軟件之間的交互界面。
我們把這種人-軟件之間的接口稱(chēng)作“用戶界面”,也就是“UI”。這里要討論的前一種定義: 軟件不同部分之間的交互接口。通常就是所謂的API――應(yīng)用程序編程接口,其表現(xiàn)的形式是源代碼。API的發(fā)明和發(fā)展大大促進(jìn)了計(jì)算機(jī)產(chǎn)業(yè)的進(jìn)步,同時(shí)API幾乎決定著日常運(yùn)算的各個(gè)方面。
大多數(shù)程序員秉承為軟件用戶設(shè)計(jì)優(yōu)秀的用戶界面思想,這一點(diǎn)早已深入人心。可是,另一方面,如何實(shí)現(xiàn)合理的軟件API卻只為少數(shù)人所重視。歷史證明,所有在應(yīng)用上獲得成功的軟件或者Web應(yīng)用無(wú)一不是首先在API的設(shè)計(jì)上滿足了用戶的需求,即便這些用戶幾乎從不直接使用這些API!
軟件系統(tǒng)之間的接口方式
概述
軟件系統(tǒng)之間的接口是實(shí)現(xiàn)一個(gè)系統(tǒng)跟另外系統(tǒng)進(jìn)行信息交互的橋梁,在不同的系統(tǒng)之間,根據(jù)系統(tǒng)的關(guān)聯(lián)程度的不同存在緊耦合和松耦合兩種:緊耦合要求接口響應(yīng)反應(yīng)快,消息不能阻塞;松耦合對(duì)響應(yīng)反應(yīng)要求比較低。在目前應(yīng)用中, Socket 、消息隊(duì)列(Message Queue)、 WebService等都有相應(yīng)的應(yīng)用,但是應(yīng)用中發(fā)現(xiàn)各通訊方式有自己固有的特征,“適合的才是最好的”,這是真理。
在接口和系統(tǒng)信息交互的過(guò)程中,兩種模式使用得很普遍:同步調(diào)用和異步調(diào)用,同步調(diào)用要求接口發(fā)出請(qǐng)求消息后必須等待服務(wù)端系統(tǒng)的應(yīng)答消息,接口阻塞直至超時(shí);異步調(diào)用則發(fā)出請(qǐng)求消息后,接口可以從事其它處理,定時(shí)輪詢(xún)服務(wù)端應(yīng)答消息和消息或事件通知。同步方式簡(jiǎn)單,但是很容易造成接口阻塞,造成消息積壓超時(shí)。
? 技術(shù)實(shí)現(xiàn)
(1)Socket 通訊
Socket 通訊相對(duì)來(lái)說(shuō)是很古老的通訊方式,也是最常用的通訊方式。 Socket 通訊有阻塞和非阻塞兩種方式。在同步方式,采用阻塞編程比較簡(jiǎn)單,但是為了防止接口阻塞,我們需要設(shè)置 Socket 超時(shí),因此可以使用 Socket 的 SELECT 模型(參考如下示例代碼): ReceLen=0;
CurReceLen=0;
for(;;)
{
iResult=select(0,&fdread,NULL,NULL,&timeout);
if(iResult==0) {
AfxMessageBox(“接收應(yīng)答消息超時(shí)?。?!”,MB_OK|MB_ICONERROR); closesocket(Socket);
return FALSE;
}
CurReceLen = recv(Socket, oBuf+ReceLen, len, NO_FLAG_SET); if((CurReceLen》0) && (CurReceLen != SOCKET_ERROR))
{
oBuf[ReceLen+CurReceLen]=‘\0’;
memcpy((char *)&MsgLen,oBuf,sizeof(WORD32));
MsgLen=ntohl(MsgLen);
if(ReceLen+CurReceLen==MsgLen)
{
ReceLen+=CurReceLen;
break;
}
ReceLen+=CurReceLen;
}
}
在異步方式下,采用非阻塞方式實(shí)現(xiàn)比較方便,在非阻塞方式下可使用WSAAsyncSelect模型和 WSAEventSelect 模型: WSAAsyncSelect模型基于消息, WSAEventSelect 模型基于事件,下面的示例代碼設(shè)置了 Socket 進(jìn)行讀寫(xiě)和關(guān)閉操作的消息:
status = WSAAsyncSelect(TempSocket, hWnd, WSA_READ, FD_READ
| FD_CLOSE | FD_WRITE);
if (status == SOCKET_ERROR)
{
{
WriteLogFile(“Set stream socket module fail?。?!IP(%s),Port(%d) and error(%d)”,GetIPAddr((PeerMap+node)-》IPAddr),(PeerMap+node)-》PeerPortNo,WS
AGetLastError());
CloseSocket(TempSocket,__LINE__,__FILE__);
return FALSE;
}
無(wú)論使用阻塞方式或非阻塞方式編程,需要重點(diǎn)考慮的一個(gè)問(wèn)題:粘包現(xiàn)象,即應(yīng)用發(fā)送兩個(gè)或以上的數(shù)據(jù)包,在 Socket 通訊層將數(shù)據(jù)包合并成一個(gè)發(fā)送出去,因
此接收端收到數(shù)據(jù)包以后需要對(duì)數(shù)據(jù)包根據(jù)應(yīng)用定義的長(zhǎng)度進(jìn)行拆分,否則導(dǎo)致應(yīng)用層丟包。 應(yīng)用方式可以由用戶封轉(zhuǎn)成DLL供使用方使用。
(2)消息隊(duì)列(Message Queue)
利用 MSMQ(Microsoft Message Queue),應(yīng)用程序開(kāi)發(fā)人員可以通過(guò)發(fā)送和接收消息方便地與應(yīng)用程序進(jìn)行快速可靠的通信。消息處理為您提供了有保障的消息傳遞和執(zhí)行許多業(yè)務(wù)處理的可靠的防故障方法。 MSMQ與XML Web Services和.Net Remoting一樣,是一種分布式開(kāi)發(fā)技術(shù)。但是在使用XML Web Services或.Net Remoting組件時(shí),Client端需要和Server端實(shí)時(shí)交換信息,Server需要保持聯(lián)機(jī)。MSMQ則可以在Server離線的情況下工作,將Message臨時(shí)保存在Client端的消息隊(duì)列中,以后聯(lián)機(jī)時(shí)再發(fā)送到Server端處理。 顯然,MSMQ不適合于Client需要Server
端及時(shí)響應(yīng)的這種情況,MSMQ以異步的方式和Server端交互,不用擔(dān)心等待Server端的長(zhǎng)時(shí)間處理過(guò)程。 雖然XML Web Services和.Net Remoting都提供了[OneWay]屬性來(lái)處理異步調(diào)用,用來(lái)解決Server端長(zhǎng)方法調(diào)用長(zhǎng)時(shí)間阻礙Client端。但是不能解決大量Client負(fù)載的問(wèn)題,此時(shí)Server接受的請(qǐng)求快于處理請(qǐng)求。 一般情況下,[OneWay]屬性不用于專(zhuān)門(mén)的消息服務(wù)中。 1. 基本術(shù)語(yǔ)和概念( Basic terms and concepts ) “消息”是在兩臺(tái)計(jì)算機(jī)間傳送的數(shù)據(jù)單位。消息可以非常簡(jiǎn)單,例如只包含文本字符串;也可以更復(fù)雜,可能包含嵌入對(duì)象。 消息被發(fā)送到隊(duì)列中?!跋㈥?duì)列”是在消息的傳輸過(guò)程中保存消息的容器。消息隊(duì)列管理器在將消息從它的源中繼到它的目標(biāo)時(shí)充當(dāng)中間人。隊(duì)列的主要目的是提供路由并保證消息的傳遞;如果發(fā)送消息時(shí)接收者不可用,消息隊(duì)列會(huì)保留消息,直到可以成功地傳遞它。 “消息隊(duì)列”是 Microsoft 的消息處理技術(shù),它在任何安裝了 Microsoft Windows 的計(jì)算機(jī)組合中,為任何應(yīng)用程序提供消息處理和消息隊(duì)列功能,無(wú)論這些計(jì)算機(jī)是否在同一個(gè)網(wǎng)絡(luò)上或者是否同時(shí)聯(lián)機(jī)。 “消息隊(duì)列網(wǎng)絡(luò)”是能夠相互間來(lái)回發(fā)送消息的任何一組計(jì)算機(jī)。網(wǎng)絡(luò)中的不同計(jì)算機(jī)在確保消息順利處理的過(guò)程中扮演不同的角色。它們中有些提供路由信息以確定如何發(fā)送消息,有些保存整個(gè)網(wǎng)絡(luò)的重要信息,而有些只是發(fā)送和接收消息。 “消息隊(duì)列”安裝期間,管理員確定哪些服務(wù)器可以互相通信,并設(shè)置特定服務(wù)器的特殊角色。構(gòu)成此“消息隊(duì)列”網(wǎng)絡(luò)的計(jì)算機(jī)稱(chēng)為“站點(diǎn)”,它們之間通過(guò)“站點(diǎn)鏈接”相互連接。每個(gè)站點(diǎn)鏈接都有一個(gè)關(guān)聯(lián)的“開(kāi)銷(xiāo)”,它由管理員確定,指示了經(jīng)過(guò)此站點(diǎn)鏈接傳遞消息的頻率。
“消息隊(duì)列”管理員還在網(wǎng)絡(luò)中設(shè)置一臺(tái)或多臺(tái)作為“路由服務(wù)器”的計(jì)算機(jī)。路由服務(wù)器查看各站點(diǎn)鏈接的開(kāi)銷(xiāo),確定經(jīng)過(guò)多個(gè)站點(diǎn)傳遞消息的最快和最有效的方法,以此決定如何傳遞消息。 2. 隊(duì)列類(lèi)型( Queue Type ) 有兩種主要的隊(duì)列類(lèi)型:由您或網(wǎng)絡(luò)中的其他用戶創(chuàng)建的隊(duì)列和系統(tǒng)隊(duì)列。 用戶創(chuàng)建的隊(duì)列可能是以下任何一種隊(duì)列: “公共隊(duì)列”在整個(gè)“消息隊(duì)列”網(wǎng)絡(luò)中復(fù)制,并且有可能由網(wǎng)絡(luò)連接的所有站點(diǎn)訪問(wèn)。 “專(zhuān)用隊(duì)列”不在整個(gè)網(wǎng)絡(luò)中發(fā)布。相反,它們僅在所駐留的本地計(jì)算機(jī)上可用。專(zhuān)用隊(duì)列只能由知道隊(duì)列的完整路徑名或標(biāo)簽的應(yīng)用程序訪問(wèn)。 “管理隊(duì)列”包含確認(rèn)在給定“消息隊(duì)列”網(wǎng)絡(luò)中發(fā)送的消息回執(zhí)的消息。指定希望MessageQueue 組件使用的管理隊(duì)列(如果有的話)。 “響應(yīng)隊(duì)列”包含目標(biāo)應(yīng)用程序接收到消息時(shí)返回給發(fā)送應(yīng)用程序的響應(yīng)消息。指定希望 MessageQueue 組件使用的響應(yīng)隊(duì)列(如果有的話)。 系統(tǒng)生成的隊(duì)列一般分為以下幾類(lèi): “日記隊(duì)列”可選地存儲(chǔ)發(fā)送消息的副本和從隊(duì)列中移除的消息副本。每個(gè)“消息隊(duì)列”客戶端上的單個(gè)日記隊(duì)列存儲(chǔ)從該計(jì)算機(jī)發(fā)送的消息副本。在服務(wù)器上為每個(gè)隊(duì)列創(chuàng)建了一個(gè)單獨(dú)的日記隊(duì)列。此日記跟蹤從該隊(duì)列中移除的消息。 “死信隊(duì)列”存儲(chǔ)無(wú)法傳遞或已過(guò)期的消息的副本。如果過(guò)期或無(wú)法傳遞的消息是事務(wù)性消息,則被存儲(chǔ)在一種特殊的死信隊(duì)列中,稱(chēng)為“事務(wù)性死信隊(duì)列”。死信存儲(chǔ)在過(guò)期消息所在的計(jì)算機(jī)上。有關(guān)超時(shí)期限和過(guò)期消息的更多信息,請(qǐng)參見(jiàn)默認(rèn)消息屬性。 “報(bào)告隊(duì)列”包含指示消息到達(dá)目標(biāo)所經(jīng)過(guò)的路由的消息,還可以包含測(cè)試消息。每臺(tái)計(jì)算機(jī)上只能有一個(gè)報(bào)告隊(duì)列。 “專(zhuān)用系統(tǒng)隊(duì)列”是一系列存儲(chǔ)系統(tǒng)執(zhí)行消息處理操作所需的管理和通知消息的專(zhuān)用隊(duì)列。 在應(yīng)用程序中進(jìn)行的大多數(shù)工作都涉及訪問(wèn)公共隊(duì)
列及其消息。但是,根據(jù)應(yīng)用程序的日記記錄、確認(rèn)和其他特殊處理需要,在日常操作中很可能要使用幾種不同的系統(tǒng)隊(duì)列。 3. 同步和異步通信( Synchronous VS. Asynchronous Communication ) 隊(duì)列通信天生就是異步的,因?yàn)閷⑾l(fā)送到隊(duì)列和從隊(duì)列中接收消息是在不同的進(jìn)程中完成的。另外,可以異步執(zhí)行接收操作,因?yàn)橐邮障⒌娜丝梢詫?duì)任何給定的隊(duì)列調(diào)用 BeginReceive 方法,然后立即繼續(xù)其他任務(wù)而不用等待答復(fù)。這與人們所了解的“同步通信”截然不同。 在同步通信中,請(qǐng)求的發(fā)送方在執(zhí)行其他任務(wù)前,必須等待來(lái)自預(yù)定接收方的響應(yīng)。發(fā)送方等待的時(shí)間完全取決于接收方處理請(qǐng)求和發(fā)送響應(yīng)所用的時(shí)間。
?同消息隊(duì)列交互( Interacting with Message Queues ) 消息處理和消息為基于服務(wù)器的應(yīng)用程序組件之間的進(jìn)程間通信提供了強(qiáng)大靈活的機(jī)制。同組件間的直接調(diào)用相比,它們具有若干優(yōu)點(diǎn),其中包括: ?穩(wěn)定性 — 組件失敗對(duì)消息的影響程度遠(yuǎn)遠(yuǎn)小于組件間的直接調(diào)用,因?yàn)橄⒋鎯?chǔ)在隊(duì)列中并一直留在那里,直到被適當(dāng)?shù)靥幚?。消息處理同事?wù)處理相似,因?yàn)橄⑻幚硎怯斜WC的。 ?消息優(yōu)先級(jí) — 更緊急或更重要的消息可在相對(duì)不重要的消息之前接收,因此可以為關(guān)鍵的應(yīng)用程序保證足夠的響應(yīng)時(shí)間。 ?脫機(jī)能力 — 發(fā)送消息時(shí),它們可被發(fā)送到臨時(shí)隊(duì)列中并一直留在那里,直到被成功地傳遞。當(dāng)因任何原因?qū)λ桕?duì)列的訪問(wèn)不可用時(shí),用戶可以繼續(xù)執(zhí)行操作。同時(shí),其他操作可以繼續(xù)進(jìn)行,如同消息已經(jīng)得到了處理一樣,這是因?yàn)榫W(wǎng)絡(luò)連接恢復(fù)時(shí)消息傳遞是有保證的。 ?事務(wù)性消息處理 — 將多個(gè)相關(guān)消息耦合為單個(gè)事務(wù),確保消息按順序傳遞、只傳遞一次并且可以從它們的目標(biāo)隊(duì)列中被成功地檢索。如果出現(xiàn)任何錯(cuò)誤,將取消整個(gè)事務(wù)。 ?安全性 — MessageQueue 組件基于的消息隊(duì)列技術(shù)使用 Windows 安全來(lái)保護(hù)訪問(wèn)控制,提供審核,并對(duì)組件發(fā)送和接收的消息進(jìn)行加密和驗(yàn)證。
#e#
?
?在 .Net 環(huán)境下編寫(xiě)簡(jiǎn)單的 Message Queue 程序
(1)先安裝Message Queuing Services 通過(guò)Control Panel,“Add/Remove Programs” – “Add/Remove Windows Components”步驟安裝MSMQ。 MSMQ可以安裝為工作組模式或域模式。如果安裝程序沒(méi)有找到一臺(tái)運(yùn)行提供目錄服務(wù)的消息隊(duì)列的服務(wù)器,則只可以安裝為工作組模式,此計(jì)算機(jī)上的“消息隊(duì)列”只支持創(chuàng)建專(zhuān)用隊(duì)列和創(chuàng)建與其他運(yùn)行“消息隊(duì)列”的計(jì)算機(jī)的直接連接。
(2)配置MSMQ 打開(kāi)Computer Management – Message Queuing,在Private Queues下創(chuàng)建MSMQDemo隊(duì)列
? ? ? ?(3)編寫(xiě)代碼-簡(jiǎn)單演示MSMQ對(duì)象 MessageQueue 類(lèi)是“消息隊(duì)列”周?chē)陌b。MessageQueue 類(lèi)提供對(duì)“消息隊(duì)列”隊(duì)列的引用??梢栽?MessageQueue 構(gòu)造函數(shù)中指定一個(gè)連接到現(xiàn)有資源的路徑,或者可在服務(wù)器上創(chuàng)建新隊(duì)列。在調(diào)用 Send、Peek 或 Receive 之前,必須將
MessageQueue 類(lèi)的新實(shí)例與某個(gè)現(xiàn)有隊(duì)列關(guān)聯(lián)。 MessageQueue 支持兩種類(lèi)型的消息檢索:同步和異步。同步的 Peek 和 Receive 方法使進(jìn)程線程用指定的間隔時(shí)間等待新消息到達(dá)隊(duì)列。異步的 BeginPeek 和 BeginReceive 方法允許主應(yīng)用程序任務(wù)在消息到達(dá)隊(duì)列之前,在單獨(dú)的線程中繼續(xù)執(zhí)行。這些方法通過(guò)使用回調(diào)對(duì)象和狀態(tài)對(duì)象進(jìn)行工作,以便在線程之間進(jìn)行信息通訊。 // Send Message private void btnSendMessage_Click(object sender, System.EventArgs e)
{
// Open queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue(“。\\Private$\\MSMQDemo”);
// Create message System.Messaging.Message message = new System.Messaging.Message(); message.Body = txtMessage.Text.Trim();
message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] {typeof(string)});
// Put message into queue
queue.Send(message); } // Receive Message private void btnReceiveMessage_Click(object sender, System.EventArgs e)
{
// Open queue
System.Messaging.MessageQueue queue = new System.Messaging.MessageQueue(“。\\Private$\\MSMQDemo”);
// Receive message, 同步的Receive方法阻塞當(dāng)前執(zhí)行線程,直到一個(gè)message可以得到
System.Messaging.Message message = queue.Receive();
message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] {typeof(string)});
txtReceiveMessage.Text = message.Body.ToString();
}
Demo界面:
(3) WebService
SOAP 作為一種協(xié)議,同服務(wù)端 WebService 進(jìn)行通訊。微軟提供了 SOAP 協(xié)議的 SDK ,我使用的是微軟的 SOAP Toolkit3.0 ,這是基于 COM 的一套組件,因此具有 COM 的特征,在調(diào)用參數(shù)的處理, windows 和 unix 順序恰好相反,下面的代碼實(shí)現(xiàn)了調(diào)用一個(gè) Web Service :
if(!m_bFlatType)
{
for(i=paramNum,j=0;i》j;i--,j++)
{
VARIANTARG argTemp;
VariantInit(&argTemp);
argTemp=va[i-1];
va[i-1]=va[j];
va[j]=argTemp;
}
}
params.cArgs = paramNum;
params.rgvarg = va;
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;
hr = SoapConnect.pSoapClient[index]-》Invoke(dispidFn, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ?ms,
&result, 0, 0);
if(FAILED(hr))
{
HandleHResult(_T(“Invoke of ”+strService+“ method failed.”), hr); VariantClear(&result);
for(i=0;i《MAX_PARAM_NUM;i++) VariantClear(&va[i]); SysFreeString(bstrServiceName);
CoUninitialize();
return FALSE;
}
總結(jié)
在三種通訊方式中,各有優(yōu)缺點(diǎn),但是主要還在于服務(wù)端采用什么技術(shù)方案來(lái)實(shí)現(xiàn),接口必須對(duì)應(yīng)采用相應(yīng)的通訊模式。
評(píng)論
查看更多