基於Windows API的命名管道的封裝與使用詳解
命名管道是一種程式間通訊(RPC)的方式,類似於socket,命名管道的一端為server,另一端為client,client與server之間支援單向或雙向通訊。與socket相比,命名管道更適合本地程式間的通訊,使用更方便和高效。
與socket相同,命名管道在通訊之前,客戶端和伺服器端必須建立連線。好比兩個人約會,需要事先商量好一個時間在某一個地點(如:某某咖啡廳)見面,見了面後就可以愉快的暢談了。
命名管道的名字類似於這個約好的咖啡廳,通過這個名字,客戶端與服務端建立連線。
誰是客戶端誰是服務端,建立連線的過程是怎樣的? 還是以約會為例,兩個人約好了時間在某個咖啡廳見面,肯定有一個人先到有一個人後到,如果先到的人到了咖啡廳看對方沒來,認為對方爽約,就立即離開了,則這樣的約會一定會失敗。所以為了能成功約會,先到的人到了咖啡廳應該等待一段時間,半個小時,1個小時,1天,甚至可以等上10年(忠誠的八公)。這樣一般會等到另一個人到來,約會成功,下面就可以愉快的交談了。先來的人就是服務端,他需要的特殊操作是等待,後來的人是客戶端,他來到咖啡廳後,要找到等待他的人,客戶端的特殊操作就是連線。
我封裝一個類CPipe,利用Windows提供的API實現了Pipe連線和通訊的功能。
CreatePipe是服務端呼叫,建立命名管道,為防止重複建立,需要先測試該命名管道是否已經建立(可以使用WaitNamedPipe測試)
BOOL CPipe::CreatePipe(const char* pipename)
{
if(m_hPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hPipe);
m_hPipe = INVALID_HANDLE_VALUE;
}
//建立命名管道
m_hPipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX |
(OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0), PIPE_TYPE_BYTE |
PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0,
60000, NULL);
if(m_hPipe == INVALID_HANDLE_VALUE)
{
WT_Error("CPipe::CreatePipe: lasterr=%d\n", GetLastError());
return FALSE;
}
CreateThread(0, 0, PipeServerListenProc, this, 0, 0);
WaitForSingleObject(m_hEvent, 2000); //wait child thread running
return TRUE;
}
客戶端使用OpenPipe連線命名管道:
BOOL CPipe::OpenPipe(const char* pipename)
{
if(m_hPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hPipe);
m_hPipe = INVALID_HANDLE_VALUE;
}
m_hPipe = ::CreateFile(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, OVERLAPPED_IO ? FILE_FLAG_OVERLAPPED : 0, NULL);
if(m_hPipe == INVALID_HANDLE_VALUE)
{
WT_Error("CPipe::CreatePipe: lasterr=%d\n", GetLastError());
return FALSE;
}
m_bConnected = TRUE;
CreateThread(0, 0, PipeClientListenProc, this, 0, 0);
WaitForSingleObject(m_hEvent, 2000); //wait child thread running
return TRUE;
}
如果不想區分服務端和客戶端,即:不管是客戶端還是服務端用同一個函式完成管道的連線,可使用BindPipe:
BOOL CPipe::BindPipe(DWORD dwPortId)
{
char pipename[256];
sprintf(pipename, PIPENAME, dwPortId);
WT_Trace("BindPipe: name=%s\n", pipename);
if (!WaitNamedPipe(pipename, NMPWAIT_USE_DEFAULT_WAIT))
{
//若命名管道不存在則建立(將成為服務端)
return CreatePipe(dwPortId);
}
else
{
//若命名管道存在則連線(將成為客戶端)
return OpenPipe(dwPortId);
}
}
相關文章
- windows命名管道Windows
- 利用windows api實現程式通訊(命名管道)WindowsAPI
- 基於celery及redis封裝sanic的apiRedis封裝API
- 詳解vue中Axios的封裝與API介面的管理VueiOS封裝API
- Linux中的pipe(管道)與named pipe(FIFO 命名管道)Linux
- Windows 關於Robocopy的使用詳解Windows
- 對MFC封裝Windows通訊API的研究 (轉)封裝WindowsAPI
- [譯]使用 Proxy 更好的封裝 Storage API封裝API
- 基於C語言EOF與getchar()的使用詳解C語言
- Flutter 基於Bloc框架的封裝FlutterBloC框架封裝
- xargs 命令詳解,xargs 與管道的區別
- xargs命令詳解,xargs與管道的區別
- 介紹 Linux 中的管道和命名管道Linux
- laravel Es的封裝與使用Laravel封裝
- 基於 Fetch 的請求封裝封裝
- 基於javascript的拖拽類封裝^o^JavaScript封裝
- 基於Tencent封裝的通用UI框架封裝UI框架
- 基於retrofit的網路框架的終極封裝(二)-與retrofit的對接與解耦,以及遇到的坑框架封裝解耦
- notification 全解和 api 的二次封裝API封裝
- 基於透明fragment的長流程封裝技巧Fragment封裝
- 基於Docker封裝的開發包工具Docker封裝
- 基於NET 6.0 封裝的 Fast.Framework封裝ASTFramework
- 使用命名管道承載gRPCRPC
- 【.NET 與樹莓派】MPD 的 Mini-API 封裝樹莓派API封裝
- 設計Go API的管道使用原則GoAPI
- 基於C語言的Q格式使用詳解C語言
- vue中axios的使用與封裝VueiOS封裝
- 基於webpack5封裝的cli工具packxWeb封裝
- ALDownloadManager 基於Alamofire封裝的下載器封裝
- 基於iOS 10、realm封裝的下載器iOS封裝
- 基於vue-resource的網路層封裝Vue封裝
- 基於retrofit的網路框架的終極封裝(一):第一層引數組裝層的API設計框架封裝API
- Java封裝(Encapsulation)-詳解Java封裝
- Linux下xargs命令詳解及xargs與管道的區別Linux
- 基於Promise實現對Ajax的簡單封裝Promise封裝
- 基於 uber 開源的 zap 二次封裝封裝
- 基於gin框架封裝的web專案骨架goskeleton框架封裝WebGo
- 基於 Zxing 封裝的 Hndxing 掃碼庫封裝