在本地進程間通訊 (IPC) 中,Socket 雖然通用但開銷較大。Windows 命名管道 提供了高效、可靠、雙向的通訊機制,適合輕量級本地 IPC。本文完整呈現基於 MFC 的命名管道伺服器端實現,涵蓋核心 API、類別設計、執行緒模型與實戰代碼。
| API | 用途 | 關鍵參數 |
|---|---|---|
CreateNamedPipe | 伺服器建立管道 | 管道名、雙向/單向、阻塞/非阻塞、實例數、緩衝區大小 |
ConnectNamedPipe | 等待客戶端連線 | 管道句柄、Overlapped 結構 (非同步) |
CreateFile | 客戶端開啟管道 | 管道名、存取模式、共享模式、建立方式 |
WriteFile/ReadFile | 資料收發 | 緩衝區、位元組數、Overlapped (非同步) |
DisconnectNamedPipe | 斷開連線 | 管道句柄 |
WaitNamedPipe | 客戶端等待管道可用 | 管道名、超時時間 |
CMyPipe - 管道核心屬性
#pragma once
class CMyPipe {
public:
CMyPipe();
CMyPipe(LPCTSTR lpctstr); // 管道名稱重載
~CMyPipe();
protected:
HANDLE MyPipe; // 管道句柄
CString MyPipeName; // 管道名稱 (格式:\\.\pipe\name)
};
CPipeServer - 伺服器業務邏輯CPipeServer* m_pPipeServerAfxBeginThread 啟動 ServerReadProcCWnd* 回呼顯示接收訊息InitPipeServer/UnInitPipeServer
bool CPipeServer::ServerReplyInfo(CString StrReply) {
MyPipe = CreateNamedPipe(MyPipeName,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // 雙向 + 非同步
PIPE_TYPE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
256, 256, // 輸出/輸入緩衝區
NULL, NULL);
if (MyPipe != INVALID_HANDLE_VALUE) {
m_StrReply = StrReply;
m_pWinThread = AfxBeginThread(ServerReadProc, (LPVOID)this);
return true;
}
return false;
}
UINT CPipeServer::ServerReadProc(LPVOID lParam) {
CPipeServer* pPipeServer = (CPipeServer*)lParam;
TCHAR buffer[256];
DWORD dwRead, dwWritten;
while (ConnectNamedPipe(pPipeServer->MyPipe, NULL)) {
while (ReadFile(pPipeServer->MyPipe, buffer, 256*sizeof(TCHAR), &dwRead, NULL)) {
if (dwRead == 0) break;
if (_tcscmp(buffer, _T("exit")) == 0) { // 關閉指令
DisconnectNamedPipe(pPipeServer->MyPipe);
CloseHandle(pPipeServer->MyPipe);
return 0;
}
// 顯示到 UI 列表框
if (pPipeServer->m_pWndServer) {
((CListBox*)pPipeServer->m_pWndServer->GetDlgItem(IDC_LBCONTENT))
->InsertString(0, buffer);
}
// 回應客戶端
_tcscpy(buffer, pPipeServer->m_StrReply);
WriteFile(pPipeServer->MyPipe, buffer, (_tcslen(buffer)+1)*sizeof(TCHAR), &dwWritten, NULL);
}
DisconnectNamedPipe(pPipeServer->MyPipe);
}
CloseHandle(pPipeServer->MyPipe);
return 0;
}
void CMyDialog::OnBnClickedBtnconnect() {
CPipeServer* pPipeServer = (CPipeServer*)this;
CString caption;
GetDlgItem(IDC_BTNCONNECT)->GetWindowText(caption);
if (caption == _T("連接")) {
for (UINT i = 0; i < pPipeServer->m_InstanceCount; ++i) {
pPipeServer->m_pPipeServer[i].SethWndServer(this);
pPipeServer->m_pPipeServer[i].ServerReplyInfo(_T("伺服器應答!"));
}
GetDlgItem(IDC_BTNCONNECT)->SetWindowText(_T("斷開"));
} else {
for (UINT i = 0; i < pPipeServer->m_InstanceCount; ++i)
pPipeServer->m_pPipeServer[i].ServerExit();
GetDlgItem(IDC_BTNCONNECT)->SetWindowText(_T("連接"));
}
}
參考 QQ tencent:// 協議,可註冊自定義 URI Scheme 啟動本地程式:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\MyApp]
@="MyApp Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\MyApp\shell\open\command]
@="\"D:\\Path\\MyApp.exe\" \"%1\""
網頁中 `` 點擊即啟動程式並傳遞參數。
FILE_FLAG_OVERLAPPED + 執行緒池實現高併發\\.\pipe\name (本機) 或 \\Server\pipe\name (跨網路)INVALID_HANDLE_VALUE、GetLastError()CloseHandle、DisconnectNamedPipe 成對呼叫