Windows API 程序間通訊,管道(Pipe)
阿新 • • 發佈:2019-01-27
通過pipe程序間通訊
**************************************//* 標頭檔案 */
#include <windows.h>
#include <stdio.h>
#include <tchar.h>/* 常量 */#define PIPE_TIMEOUT 5000#define BUFSIZE 4096/* 結構定義 */
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR chRequest[BUFSIZE];
DWORD cbRead;
TCHAR chReply[BUFSIZE];
DWORD cbToWrite;
} PIPEINST, *LPPIPEINST;
/* 函式宣告 */
VOID DisconnectAndClose(LPPIPEINST);
BOOL CreateAndConnectInstance(LPOVERLAPPED);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
/* 全域性變數 */
HANDLE hPipe;
/* ************************************
* int main(VOID)
* 功能 pipe 通訊服務端主函式
**************************************/int main(VOID)
{
HANDLE hConnectEvent;
OVERLAPPED oConnect;
LPPIPEINST lpPipeInst;
DWORD dwWait, cbRet;
BOOL fSuccess, fPendingIO;
// 用於連線操作的事件物件 hConnectEvent = CreateEvent(
NULL, // 預設屬性 TRUE, // 手工reset TRUE, // 初始狀態 signaled NULL); // 未命名if (hConnectEvent == NULL)
{
printf("CreateEvent failed with %d.\n", GetLastError());
return0;
}
// OVERLAPPED 事件 oConnect.hEvent = hConnectEvent;
// 建立連線例項,等待連線 fPendingIO = CreateAndConnectInstance(&oConnect);
while (1)
{
// 等待客戶端連線或讀寫操作完成 dwWait = WaitForSingleObjectEx(
hConnectEvent, // 等待的事件 INFINITE, // 無限等待 TRUE);
switch (dwWait)
{
case0:
// pending if (fPendingIO)
{
// 獲取 Overlapped I/O 的結果 fSuccess = GetOverlappedResult(
hPipe, // pipe 控制代碼 &oConnect, // OVERLAPPED 結構 &cbRet, // 已經傳送的資料量 FALSE); // 不等待if (!fSuccess)
{
printf("ConnectNamedPipe (%d)\n", GetLastError());
return0;
}
}
// 分配記憶體 lpPipeInst = (LPPIPEINST) HeapAlloc(GetProcessHeap(),0,sizeof(PIPEINST));
if (lpPipeInst == NULL)
{
printf("GlobalAlloc failed (%d)\n", GetLastError());
return0;
}
lpPipeInst->hPipeInst = hPipe;
// 讀和寫,注意CompletedWriteRoutine和CompletedReadRoutine的相互呼叫 lpPipeInst->cbToWrite =0;
CompletedWriteRoutine(0, 0, (LPOVERLAPPED) lpPipeInst);
// 再建立一個連線例項,以響應下一個客戶端的連線 fPendingIO = CreateAndConnectInstance(
&oConnect);
break;
// 讀寫完成 case WAIT_IO_COMPLETION:
break;
default:
{
printf("WaitForSingleObjectEx (%d)\n", GetLastError());
return0;
}
}
}
return0;
}
/* ************************************
* CompletedWriteRoutine
* 寫入pipe操作的完成函式
* 介面參見FileIOCompletionRoutine回撥函式定義
*
* 當寫操作完成時被呼叫,開始讀另外一個客戶端的請求
**************************************/
VOID WINAPI CompletedWriteRoutine(
DWORD dwErr,
DWORD cbWritten,
LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fRead = FALSE;
// 儲存overlap例項 lpPipeInst = (LPPIPEINST) lpOverLap;
// 如果沒有錯誤if ((dwErr ==0) && (cbWritten == lpPipeInst->cbToWrite))
{
fRead = ReadFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chRequest,
BUFSIZE*sizeof(TCHAR),
(LPOVERLAPPED) lpPipeInst,
// 寫讀操作完成後,呼叫CompletedReadRoutine (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
}
if (! fRead)
// 出錯,斷開連線 DisconnectAndClose(lpPipeInst);
}
/* ************************************
* CompletedReadRoutine
* 讀取pipe操作的完成函式
* 介面參見FileIOCompletionRoutine回撥函式定義
*
* 當讀操作完成時被呼叫,寫入回覆
**************************************/
VOID WINAPI CompletedReadRoutine(
DWORD dwErr,
DWORD cbBytesRead,
LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fWrite = FALSE;
// 儲存overlap例項 lpPipeInst = (LPPIPEINST) lpOverLap;
// 如果沒有錯誤if ((dwErr ==0) && (cbBytesRead !=0))
{
// 根據客戶端的請求,生成回覆 GetAnswerToRequest(lpPipeInst);
// 將回複寫入到pipe fWrite = WriteFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chReply, //將響應寫入pipe lpPipeInst->cbToWrite,
(LPOVERLAPPED) lpPipeInst,
// 寫入完成後,呼叫CompletedWriteRoutine (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine);
}
if (! fWrite)
// 出錯,斷開連線 DisconnectAndClose(lpPipeInst);
}
/* ************************************
* VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
* 功能 斷開一個連線的例項
* 引數 lpPipeInst,斷開並關閉的例項控制代碼
**************************************/
VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
{
// 關閉連線例項if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) )
{
printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
}
// 關閉 pipe 例項的控制代碼 CloseHandle(lpPipeInst->hPipeInst);
// 釋放if (lpPipeInst != NULL)
HeapFree(GetProcessHeap(),0, lpPipeInst);
}
/* ************************************
* BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
* 功能 建立連線例項
* 引數 lpoOverlap,用於overlapped IO的結構
* 返回值 是否成功
**************************************/
BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
{
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\samplenamedpipe");
// 建立named pipe hPipe = CreateNamedPipe(
lpszPipename, // pipe 名 PIPE_ACCESS_DUPLEX |// 可讀可寫 FILE_FLAG_OVERLAPPED, // overlapped 模式
// pipe模式 PIPE_TYPE_MESSAGE |// 訊息型別 pipe PIPE_READMODE_MESSAGE |// 訊息讀模式 PIPE_WAIT, // 阻塞模式 PIPE_UNLIMITED_INSTANCES, // 無限制例項 BUFSIZE*sizeof(TCHAR), // 輸出快取大小 BUFSIZE*sizeof(TCHAR), // 輸入快取大小 PIPE_TIMEOUT, // 客戶端超時 NULL); // 預設安全屬性if (hPipe == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with %d.\n", GetLastError());
return0;
}
// 連線到新的客戶端return ConnectToNewClient(hPipe, lpoOverlap);
}
/* ************************************
* BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
* 功能 建立連線例項
* 引數 lpoOverlap,用於overlapped IO的結構
* 返回值 是否成功
**************************************/
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL fConnected, fPendingIO = FALSE;
// 開始一個 overlapped 連線 fConnected = ConnectNamedPipe(hPipe, lpo);
if (fConnected)
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return0;
}
switch (GetLastError())
{
// overlapped連線進行中. case ERROR_IO_PENDING:
fPendingIO = TRUE;
break;
// 已經連線,因此Event未置位 case ERROR_PIPE_CONNECTED:
if (SetEvent(lpo->hEvent))
break;
// errordefault:
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return0;
}
}
return fPendingIO;
}
// TODO根據客戶端的請求,給出響應VOID GetAnswerToRequest(LPPIPEINST pipe)
{
_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
lstrcpyn( pipe->chReply, TEXT("Default answer from server") ,BUFSIZE);
pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
}
**************************************//* 標頭檔案 */
#include <windows.h>
#include <stdio.h>
#include <tchar.h>/* 常量 */#define PIPE_TIMEOUT 5000#define BUFSIZE 4096/* 結構定義 */
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR chRequest[BUFSIZE];
DWORD cbRead;
TCHAR chReply[BUFSIZE];
DWORD cbToWrite;
} PIPEINST,
/* 函式宣告 */
VOID DisconnectAndClose(LPPIPEINST);
BOOL CreateAndConnectInstance(LPOVERLAPPED);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
HANDLE hPipe;
/* ************************************
* int main(VOID)
* 功能 pipe 通訊服務端主函式
**************************************/int main(VOID)
{
HANDLE hConnectEvent;
OVERLAPPED oConnect;
LPPIPEINST lpPipeInst;
DWORD dwWait, cbRet;
BOOL fSuccess, fPendingIO;
// 用於連線操作的事件物件
NULL, // 預設屬性 TRUE, // 手工reset TRUE, // 初始狀態 signaled NULL); // 未命名if (hConnectEvent == NULL)
{
printf("CreateEvent failed with %d.\n", GetLastError());
return0;
}
// OVERLAPPED 事件 oConnect.hEvent = hConnectEvent;
// 建立連線例項,等待連線 fPendingIO = CreateAndConnectInstance(&oConnect);
while (1)
{
// 等待客戶端連線或讀寫操作完成 dwWait = WaitForSingleObjectEx(
hConnectEvent, // 等待的事件 INFINITE, // 無限等待 TRUE);
switch (dwWait)
{
case0:
// pending if (fPendingIO)
{
// 獲取 Overlapped I/O 的結果 fSuccess = GetOverlappedResult(
hPipe, // pipe 控制代碼 &oConnect, // OVERLAPPED 結構 &cbRet, // 已經傳送的資料量 FALSE); // 不等待if (!fSuccess)
{
printf("ConnectNamedPipe (%d)\n", GetLastError());
return0;
}
}
// 分配記憶體 lpPipeInst = (LPPIPEINST) HeapAlloc(GetProcessHeap(),0,sizeof(PIPEINST));
if (lpPipeInst == NULL)
{
printf("GlobalAlloc failed (%d)\n", GetLastError());
return0;
}
lpPipeInst->hPipeInst = hPipe;
// 讀和寫,注意CompletedWriteRoutine和CompletedReadRoutine的相互呼叫 lpPipeInst->cbToWrite =0;
CompletedWriteRoutine(0, 0, (LPOVERLAPPED) lpPipeInst);
// 再建立一個連線例項,以響應下一個客戶端的連線 fPendingIO = CreateAndConnectInstance(
&oConnect);
break;
// 讀寫完成 case WAIT_IO_COMPLETION:
break;
default:
{
printf("WaitForSingleObjectEx (%d)\n", GetLastError());
return0;
}
}
}
return0;
}
/* ************************************
* CompletedWriteRoutine
* 寫入pipe操作的完成函式
* 介面參見FileIOCompletionRoutine回撥函式定義
*
* 當寫操作完成時被呼叫,開始讀另外一個客戶端的請求
**************************************/
VOID WINAPI CompletedWriteRoutine(
DWORD dwErr,
DWORD cbWritten,
LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fRead = FALSE;
// 儲存overlap例項 lpPipeInst = (LPPIPEINST) lpOverLap;
// 如果沒有錯誤if ((dwErr ==0) && (cbWritten == lpPipeInst->cbToWrite))
{
fRead = ReadFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chRequest,
BUFSIZE*sizeof(TCHAR),
(LPOVERLAPPED) lpPipeInst,
// 寫讀操作完成後,呼叫CompletedReadRoutine (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
}
if (! fRead)
// 出錯,斷開連線 DisconnectAndClose(lpPipeInst);
}
/* ************************************
* CompletedReadRoutine
* 讀取pipe操作的完成函式
* 介面參見FileIOCompletionRoutine回撥函式定義
*
* 當讀操作完成時被呼叫,寫入回覆
**************************************/
VOID WINAPI CompletedReadRoutine(
DWORD dwErr,
DWORD cbBytesRead,
LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fWrite = FALSE;
// 儲存overlap例項 lpPipeInst = (LPPIPEINST) lpOverLap;
// 如果沒有錯誤if ((dwErr ==0) && (cbBytesRead !=0))
{
// 根據客戶端的請求,生成回覆 GetAnswerToRequest(lpPipeInst);
// 將回複寫入到pipe fWrite = WriteFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chReply, //將響應寫入pipe lpPipeInst->cbToWrite,
(LPOVERLAPPED) lpPipeInst,
// 寫入完成後,呼叫CompletedWriteRoutine (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine);
}
if (! fWrite)
// 出錯,斷開連線 DisconnectAndClose(lpPipeInst);
}
/* ************************************
* VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
* 功能 斷開一個連線的例項
* 引數 lpPipeInst,斷開並關閉的例項控制代碼
**************************************/
VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
{
// 關閉連線例項if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) )
{
printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
}
// 關閉 pipe 例項的控制代碼 CloseHandle(lpPipeInst->hPipeInst);
// 釋放if (lpPipeInst != NULL)
HeapFree(GetProcessHeap(),0, lpPipeInst);
}
/* ************************************
* BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
* 功能 建立連線例項
* 引數 lpoOverlap,用於overlapped IO的結構
* 返回值 是否成功
**************************************/
BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
{
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\samplenamedpipe");
// 建立named pipe hPipe = CreateNamedPipe(
lpszPipename, // pipe 名 PIPE_ACCESS_DUPLEX |// 可讀可寫 FILE_FLAG_OVERLAPPED, // overlapped 模式
// pipe模式 PIPE_TYPE_MESSAGE |// 訊息型別 pipe PIPE_READMODE_MESSAGE |// 訊息讀模式 PIPE_WAIT, // 阻塞模式 PIPE_UNLIMITED_INSTANCES, // 無限制例項 BUFSIZE*sizeof(TCHAR), // 輸出快取大小 BUFSIZE*sizeof(TCHAR), // 輸入快取大小 PIPE_TIMEOUT, // 客戶端超時 NULL); // 預設安全屬性if (hPipe == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with %d.\n", GetLastError());
return0;
}
// 連線到新的客戶端return ConnectToNewClient(hPipe, lpoOverlap);
}
/* ************************************
* BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
* 功能 建立連線例項
* 引數 lpoOverlap,用於overlapped IO的結構
* 返回值 是否成功
**************************************/
BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL fConnected, fPendingIO = FALSE;
// 開始一個 overlapped 連線 fConnected = ConnectNamedPipe(hPipe, lpo);
if (fConnected)
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return0;
}
switch (GetLastError())
{
// overlapped連線進行中. case ERROR_IO_PENDING:
fPendingIO = TRUE;
break;
// 已經連線,因此Event未置位 case ERROR_PIPE_CONNECTED:
if (SetEvent(lpo->hEvent))
break;
// errordefault:
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return0;
}
}
return fPendingIO;
}
// TODO根據客戶端的請求,給出響應VOID GetAnswerToRequest(LPPIPEINST pipe)
{
_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
lstrcpyn( pipe->chReply, TEXT("Default answer from server") ,BUFSIZE);
pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
}