?軟件接口概念
計算機世界里的接口這兩個字具有兩種眾所周知的含義:其一是指軟件本身的狹義“接口”,比如各種軟件開發API等。其二則指的是人與軟件之間的交互界面。
我們把這種人-軟件之間的接口稱作“用戶界面”,也就是“UI”。這里要討論的前一種定義: 軟件不同部分之間的交互接口。通常就是所謂的API――應用程序編程接口,其表現的形式是源代碼。API的發明和發展大大促進了計算機產業的進步,同時API幾乎決定著日常運算的各個方面。
大多數程序員秉承為軟件用戶設計優秀的用戶界面思想,這一點早已深入人心。可是,另一方面,如何實現合理的軟件API卻只為少數人所重視。歷史證明,所有在應用上獲得成功的軟件或者Web應用無一不是首先在API的設計上滿足了用戶的需求,即便這些用戶幾乎從不直接使用這些API!
軟件系統之間的接口方式
概述
軟件系統之間的接口是實現一個系統跟另外系統進行信息交互的橋梁,在不同的系統之間,根據系統的關聯程度的不同存在緊耦合和松耦合兩種:緊耦合要求接口響應反應快,消息不能阻塞;松耦合對響應反應要求比較低。在目前應用中, Socket 、消息隊列(Message Queue)、 WebService等都有相應的應用,但是應用中發現各通訊方式有自己固有的特征,“適合的才是最好的”,這是真理。
在接口和系統信息交互的過程中,兩種模式使用得很普遍:同步調用和異步調用,同步調用要求接口發出請求消息后必須等待服務端系統的應答消息,接口阻塞直至超時;異步調用則發出請求消息后,接口可以從事其它處理,定時輪詢服務端應答消息和消息或事件通知。同步方式簡單,但是很容易造成接口阻塞,造成消息積壓超時。
? 技術實現
(1)Socket 通訊
Socket 通訊相對來說是很古老的通訊方式,也是最常用的通訊方式。 Socket 通訊有阻塞和非阻塞兩種方式。在同步方式,采用阻塞編程比較簡單,但是為了防止接口阻塞,我們需要設置 Socket 超時,因此可以使用 Socket 的 SELECT 模型(參考如下示例代碼): ReceLen=0;
CurReceLen=0;
for(;;)
{
iResult=select(0,&fdread,NULL,NULL,&timeout);
if(iResult==0) {
AfxMessageBox(“接收應答消息超時!!!”,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;
}
}
在異步方式下,采用非阻塞方式實現比較方便,在非阻塞方式下可使用WSAAsyncSelect模型和 WSAEventSelect 模型: WSAAsyncSelect模型基于消息, WSAEventSelect 模型基于事件,下面的示例代碼設置了 Socket 進行讀寫和關閉操作的消息:
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;
}
無論使用阻塞方式或非阻塞方式編程,需要重點考慮的一個問題:粘包現象,即應用發送兩個或以上的數據包,在 Socket 通訊層將數據包合并成一個發送出去,因
此接收端收到數據包以后需要對數據包根據應用定義的長度進行拆分,否則導致應用層丟包。 應用方式可以由用戶封轉成DLL供使用方使用。
(2)消息隊列(Message Queue)
利用 MSMQ(Microsoft Message Queue),應用程序開發人員可以通過發送和接收消息方便地與應用程序進行快速可靠的通信。消息處理為您提供了有保障的消息傳遞和執行許多業務處理的可靠的防故障方法。 MSMQ與XML Web Services和.Net Remoting一樣,是一種分布式開發技術。但是在使用XML Web Services或.Net Remoting組件時,Client端需要和Server端實時交換信息,Server需要保持聯機。MSMQ則可以在Server離線的情況下工作,將Message臨時保存在Client端的消息隊列中,以后聯機時再發送到Server端處理。 顯然,MSMQ不適合于Client需要Server
端及時響應的這種情況,MSMQ以異步的方式和Server端交互,不用擔心等待Server端的長時間處理過程。 雖然XML Web Services和.Net Remoting都提供了[OneWay]屬性來處理異步調用,用來解決Server端長方法調用長時間阻礙Client端。但是不能解決大量Client負載的問題,此時Server接受的請求快于處理請求。 一般情況下,[OneWay]屬性不用于專門的消息服務中。 1. 基本術語和概念( Basic terms and concepts ) “消息”是在兩臺計算機間傳送的數據單位。消息可以非常簡單,例如只包含文本字符串;也可以更復雜,可能包含嵌入對象。 消息被發送到隊列中。“消息隊列”是在消息的傳輸過程中保存消息的容器。消息隊列管理器在將消息從它的源中繼到它的目標時充當中間人。隊列的主要目的是提供路由并保證消息的傳遞;如果發送消息時接收者不可用,消息隊列會保留消息,直到可以成功地傳遞它。 “消息隊列”是 Microsoft 的消息處理技術,它在任何安裝了 Microsoft Windows 的計算機組合中,為任何應用程序提供消息處理和消息隊列功能,無論這些計算機是否在同一個網絡上或者是否同時聯機。 “消息隊列網絡”是能夠相互間來回發送消息的任何一組計算機。網絡中的不同計算機在確保消息順利處理的過程中扮演不同的角色。它們中有些提供路由信息以確定如何發送消息,有些保存整個網絡的重要信息,而有些只是發送和接收消息。 “消息隊列”安裝期間,管理員確定哪些服務器可以互相通信,并設置特定服務器的特殊角色。構成此“消息隊列”網絡的計算機稱為“站點”,它們之間通過“站點鏈接”相互連接。每個站點鏈接都有一個關聯的“開銷”,它由管理員確定,指示了經過此站點鏈接傳遞消息的頻率。
“消息隊列”管理員還在網絡中設置一臺或多臺作為“路由服務器”的計算機。路由服務器查看各站點鏈接的開銷,確定經過多個站點傳遞消息的最快和最有效的方法,以此決定如何傳遞消息。 2. 隊列類型( Queue Type ) 有兩種主要的隊列類型:由您或網絡中的其他用戶創建的隊列和系統隊列。 用戶創建的隊列可能是以下任何一種隊列: “公共隊列”在整個“消息隊列”網絡中復制,并且有可能由網絡連接的所有站點訪問。 “專用隊列”不在整個網絡中發布。相反,它們僅在所駐留的本地計算機上可用。專用隊列只能由知道隊列的完整路徑名或標簽的應用程序訪問。 “管理隊列”包含確認在給定“消息隊列”網絡中發送的消息回執的消息。指定希望MessageQueue 組件使用的管理隊列(如果有的話)。 “響應隊列”包含目標應用程序接收到消息時返回給發送應用程序的響應消息。指定希望 MessageQueue 組件使用的響應隊列(如果有的話)。 系統生成的隊列一般分為以下幾類: “日記隊列”可選地存儲發送消息的副本和從隊列中移除的消息副本。每個“消息隊列”客戶端上的單個日記隊列存儲從該計算機發送的消息副本。在服務器上為每個隊列創建了一個單獨的日記隊列。此日記跟蹤從該隊列中移除的消息。 “死信隊列”存儲無法傳遞或已過期的消息的副本。如果過期或無法傳遞的消息是事務性消息,則被存儲在一種特殊的死信隊列中,稱為“事務性死信隊列”。死信存儲在過期消息所在的計算機上。有關超時期限和過期消息的更多信息,請參見默認消息屬性。 “報告隊列”包含指示消息到達目標所經過的路由的消息,還可以包含測試消息。每臺計算機上只能有一個報告隊列。 “專用系統隊列”是一系列存儲系統執行消息處理操作所需的管理和通知消息的專用隊列。 在應用程序中進行的大多數工作都涉及訪問公共隊
列及其消息。但是,根據應用程序的日記記錄、確認和其他特殊處理需要,在日常操作中很可能要使用幾種不同的系統隊列。 3. 同步和異步通信( Synchronous VS. Asynchronous Communication ) 隊列通信天生就是異步的,因為將消息發送到隊列和從隊列中接收消息是在不同的進程中完成的。另外,可以異步執行接收操作,因為要接收消息的人可以對任何給定的隊列調用 BeginReceive 方法,然后立即繼續其他任務而不用等待答復。這與人們所了解的“同步通信”截然不同。 在同步通信中,請求的發送方在執行其他任務前,必須等待來自預定接收方的響應。發送方等待的時間完全取決于接收方處理請求和發送響應所用的時間。
?同消息隊列交互( Interacting with Message Queues ) 消息處理和消息為基于服務器的應用程序組件之間的進程間通信提供了強大靈活的機制。同組件間的直接調用相比,它們具有若干優點,其中包括: ?穩定性 — 組件失敗對消息的影響程度遠遠小于組件間的直接調用,因為消息存儲在隊列中并一直留在那里,直到被適當地處理。消息處理同事務處理相似,因為消息處理是有保證的。 ?消息優先級 — 更緊急或更重要的消息可在相對不重要的消息之前接收,因此可以為關鍵的應用程序保證足夠的響應時間。 ?脫機能力 — 發送消息時,它們可被發送到臨時隊列中并一直留在那里,直到被成功地傳遞。當因任何原因對所需隊列的訪問不可用時,用戶可以繼續執行操作。同時,其他操作可以繼續進行,如同消息已經得到了處理一樣,這是因為網絡連接恢復時消息傳遞是有保證的。 ?事務性消息處理 — 將多個相關消息耦合為單個事務,確保消息按順序傳遞、只傳遞一次并且可以從它們的目標隊列中被成功地檢索。如果出現任何錯誤,將取消整個事務。 ?安全性 — MessageQueue 組件基于的消息隊列技術使用 Windows 安全來保護訪問控制,提供審核,并對組件發送和接收的消息進行加密和驗證。
#e#
?
?在 .Net 環境下編寫簡單的 Message Queue 程序
(1)先安裝Message Queuing Services 通過Control Panel,“Add/Remove Programs” – “Add/Remove Windows Components”步驟安裝MSMQ。 MSMQ可以安裝為工作組模式或域模式。如果安裝程序沒有找到一臺運行提供目錄服務的消息隊列的服務器,則只可以安裝為工作組模式,此計算機上的“消息隊列”只支持創建專用隊列和創建與其他運行“消息隊列”的計算機的直接連接。
(2)配置MSMQ 打開Computer Management – Message Queuing,在Private Queues下創建MSMQDemo隊列
? ? ? ?(3)編寫代碼-簡單演示MSMQ對象 MessageQueue 類是“消息隊列”周圍的包裝。MessageQueue 類提供對“消息隊列”隊列的引用。可以在 MessageQueue 構造函數中指定一個連接到現有資源的路徑,或者可在服務器上創建新隊列。在調用 Send、Peek 或 Receive 之前,必須將
MessageQueue 類的新實例與某個現有隊列關聯。 MessageQueue 支持兩種類型的消息檢索:同步和異步。同步的 Peek 和 Receive 方法使進程線程用指定的間隔時間等待新消息到達隊列。異步的 BeginPeek 和 BeginReceive 方法允許主應用程序任務在消息到達隊列之前,在單獨的線程中繼續執行。這些方法通過使用回調對象和狀態對象進行工作,以便在線程之間進行信息通訊。 // 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方法阻塞當前執行線程,直到一個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 作為一種協議,同服務端 WebService 進行通訊。微軟提供了 SOAP 協議的 SDK ,我使用的是微軟的 SOAP Toolkit3.0 ,這是基于 COM 的一套組件,因此具有 COM 的特征,在調用參數的處理, windows 和 unix 順序恰好相反,下面的代碼實現了調用一個 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;
}
總結
在三種通訊方式中,各有優缺點,但是主要還在于服務端采用什么技術方案來實現,接口必須對應采用相應的通訊模式。
評論