大型軟體專案常拆解為多個互動的小程式,彼此透過通訊協定交換資料。這些程式可能跨機器、跨作業系統、跨語言,也可能僅在同一台機器上運行,類似同一程式中的不同執行緒。本文專注於 C++/CLI 進程間通訊 (IPC),以 Socket 為核心機制,不涉及網路層面的遠端通訊。
典型應用包含「伺服端」等待請求、「客戶端」發送請求。伺服端處理後回傳結果。實際系統中,一個程式可能同時扮演伺服端與客戶端角色(如資料庫伺服端需存取遠端檔案伺服器)。本文以「服務提供者」與「服務消費者」的抽象關係為基礎進行說明。
範例程式監聽指定連接埠,接收客戶端傳送的兩個整數,計算總和並回傳。
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^) {
Console::WriteLine("Port number {0} is ill-formed", argv[0]);
Environment::Exit(2);
}
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);
}
// 取得本機 IP 並建立端點
IPAddress^ ipAddress = Dns::GetHostEntry(Dns::GetHostName())->AddressList[0];
IPEndPoint^ ipEndpoint = gcnew IPEndPoint(ipAddress, port);
// 建立 TCP Socket 並開始監聽
Socket^ listenerSocket = gcnew Socket(AddressFamily::InterNetwork,
SocketType::Stream, ProtocolType::Tcp);
listenerSocket->Bind(ipEndpoint);
listenerSocket->Listen(1); // 佇列長度 1
Console::WriteLine("Server listener blocking status is {0}", listenerSocket->Blocking);
// 接受連線
Socket^ serverSocket = listenerSocket->Accept();
Console::WriteLine("New connection accepted");
listenerSocket->Close(); // 單一客戶端模式,關閉監聽 Socket
// 建立資料流與讀寫器
NetworkStream^ netStream = gcnew NetworkStream(serverSocket);
BinaryReader^ br = gcnew BinaryReader(netStream);
BinaryWriter^ bw = gcnew BinaryWriter(netStream);
try {
while (true) {
int value1 = br->ReadInt32();
int value2 = br->ReadInt32();
Console::Write("Received values {0,3} and {1,3}", value1, value2);
int result = value1 + value2;
bw->Write(result);
Console::WriteLine(", sent result {0,3}", result);
}
}
catch (EndOfStreamException^) { /* 客戶端關閉連線 */ }
catch (IOException^ e) {
Console::WriteLine("IOException {0}", e);
}
serverSocket->Shutdown(SocketShutdown::Both);
serverSocket->Close();
netStream->Close();
Console::WriteLine("Shutting down server");
}
Accept() 等待連線。listenerSocket 負責監聽,serverSocket 負責通訊,支援多客戶端擴展。EndOfStreamException (正常關閉) 與 IOException (異常中斷)。客戶端連線後發送隨機整數對,同步等待結果,每次間隔 3 秒以便觀察。
// ... 參數解析略 ...
IPAddress^ ipAddress = Dns::GetHostEntry(Dns::GetHostName())->AddressList[0];
IPEndPoint^ ipEndpoint = gcnew IPEndPoint(ipAddress, port);
Socket^ clientSocket = gcnew Socket(AddressFamily::InterNetwork,
SocketType::Stream, ProtocolType::Tcp);
clientSocket->Connect(ipEndpoint);
NetworkStream^ netStream = gcnew NetworkStream(clientSocket);
BinaryReader^ br = gcnew BinaryReader(netStream);
BinaryWriter^ bw = gcnew BinaryWriter(netStream);
Random^ random = gcnew Random;
for (int i = 1; i <= messageCount; ++i) {
int value1 = static_cast<int>(random->NextDouble() * 100);
int value2 = static_cast<int>(random->NextDouble() * 100);
bw->Write(value1);
bw->Write(value2);
Console::Write("Sent values {0,3} and {1,3}", value1, value2);
int result = br->ReadInt32();
Console::WriteLine(", received result {0,3}", result);
Thread::Sleep(3000);
}
clientSocket->Shutdown(SocketShutdown::Both);
clientSocket->Close();
netStream->Close();
Console::WriteLine("Shutting down client");
Server listener blocking status is True
New connection accepted
Received values 42 and 69, sent result 111
Received values 66 and 71, sent result 137
Received values 7 and 93, sent result 100
Received values 43 and 65, sent result 108
Received values 45 and 3, sent result 48
Shutting down server
Sent values 42 and 69, received result 111
Sent values 66 and 71, received result 137
Sent values 7 and 93, received result 100
Sent values 43 and 65, received result 108
Sent values 45 and 3, received result 48
Notified server we're shutting down
Shutting down client
實務上常需傳遞自訂物件(如金融交易:存款、轉帳、提款),需引入序列化機制。配合適當的序列化/反序列化,伺服端可處理多型物件請求。
Server 2600
Waiting for new connection request
New connection accepted
Started thread Thread-1
Waiting for new connection request
Executing thread Thread-1
Received values 56 and 35, sent result 91
New connection accepted
Started thread Thread-2
Waiting for new connection request
Executing thread Thread-2
Received values 69 and 66, sent result 135
Received values 48 and 20, sent result 68
Received values 84 and 45, sent result 129
Received values 6 and 97, sent result 103
Shutting down server thread Thread-2
Received values 76 and 9, sent result 85
Shutting down server thread Thread-1