現在,把大型軟件項目分解為一些相交互的小程序似乎變得越來越普遍,程序各部分之間的通訊可使用某種類型的通訊協議,這些程序可能運行在不同的機器上、不同的操作系統中、以不同的語言編寫,但也有可能只在同一台機器上,實際上,這些程序可看成是同一程序中的不同線程。而本文主要討論C++/CLI程序間的通訊,當然,在此是討論進程間通訊,而不是網絡通訊。
簡介
試想一個包含數據庫查詢功能的應用,通常有一個被稱為服務端的程序,等待另一個被稱為客戶端程序發送請求,當接收到請求時,服務端執行相應功能,並把結果(或者錯誤信息)返回給客戶端。在許多情況中,有著多個客戶端,所有的請求都會在同一時間發送到同一服務端,這就要求服務端程序要更加高級、完善。
在某些針對此任務的環境中,服務端程序可能只是眾多程序中的一個程序,其他可能也是服務端或者客戶端程序,實際上,如果我們的數據庫服務端需要訪問不存在於本機的文件,那麼它就可能成為其他某個文件服務器的一個客戶端。一個程序中可能會有一個服務線程及一個或多個客戶線程,因此,我們需小心使用客戶端及服務端這個術語,雖然它們表達了近似的抽象含義,但在具體實現上卻大不相同。從一般的觀點來看,客戶端即為服務端所提供服務的"消費者",而服務端也能成為其他某些服務的客戶端。
服務端套接字
讓我們從一個具體有代表性的服務端程序開始(請看例1),此程序等待客戶端發送一對整數,把它們相加之後返回結果給客戶端。
例1:
using namespace System;
using namespace System::IO;
using namespace System::Net;
using namespace System::Net::Sockets;
int main(array<String^>^ argv)
{
if (argv->Length != 1)
{
Console::WriteLine("Usage: Server port");
Environment::Exit(1);
}
int port = 0;
try
{
port = Int32::Parse(argv[0]);
}
catch (FormatException^ e)
{
Console::WriteLine("Port number {0} is ill-formed", argv[0]);
Environment::Exit(2);
}
/*1*/ if (port < IPEndPoint::MinPort || port > IPEndPoint::MaxPort)
{
Console::WriteLine("Port number must be in the range {0}-{1}",
IPEndPoint::MinPort, IPEndPoint::MaxPort);
Environment::Exit(3);
}
/*2*/ IPAddress^ ipAddress =
Dns::GetHostEntry(Dns::GetHostName())->AddressList[0];
/*3*/ IPEndPoint^ ipEndpoint = gcnew IPEndPoint(ipAddress, port);
/*4*/ Socket^ listenerSocket = gcnew Socket(AddressFamily::InterNetwork,
SocketType::Stream, ProtocolType::Tcp);
/*5*/ listenerSocket->Bind(ipEndpoint);
/*6*/ listenerSocket->Listen(1);
/*7*/ Console::WriteLine("Server listener blocking status is {0}",
listenerSocket->Blocking);
/*8*/ Socket^ serverSocket = listenerSocket->Accept();
Console::WriteLine("New connection accepted");
/*9*/ listenerSocket->Close();
/*10*/ NetworkStream^ netStream = gcnew NetworkStream(serverSocket);
/*11*/ BinaryReader^ br = gcnew BinaryReader(netStream);
/*12*/ BinaryWriter^ bw = gcnew BinaryWriter(netStream);
try
{
int value1, value2;
int result;
while (true)
{
/*13*/ value1 = br->ReadInt32();
/*14*/ value2 = br->ReadInt32();
Console::Write("Received values {0,3} and {1,3}",
value1, value2);
result = value1 + value2;
/*15*/ bw->Write(result);
Console::WriteLine(", sent result {0,3}", result);
}
}
/*16*/ catch (EndOfStreamException^ e)
{
}
/*17*/ catch (IOException^ e)
{
Console::WriteLine("IOException {0}", e);
}
/*18*/ serverSocket->Shutdown(SocketShutdown::Both);
/*19*/ serverSocket->Close();
/*20*/ netStream->Close();
Console::WriteLine("Shutting down server");
}