?? 17.3.3 客戶端程序.txt
字號:
17.3.3 客戶端程序
接下來創建命名管道的客戶端程序。同樣,可以將客戶端程序添加到已有的服務器程序所在的工作
區: NamedPipeSrv中,所以,在此工作區中新建一個單文檔類型的 MFC應用程序,工程取名為:
NamedPipeClt,同時設置該工程所在的目錄與 NamedPipeSrv工程的目錄平級。
然后,為該工程增加一個子菜單,菜單名稱為"命名管道"。接著,為該子菜單添加三個菜單項,并
分別為它們添加相應的命令響應函數,本例選擇 CNamedPipeCltView類接收這些命令響應函數。各
菜單項的 B、名稱,以及響應函數如表 17.14所示。
表 17.14添加的菜單項及相應的晌應函數
ID 菜單名稱 響應函數
IDM_PIPE_CONNECT 連接管道 OnPipeConnect
IDM PIPE READ 讀取數據 OnPipeR四d
IDM PIPE WRITE 寫入數據 OnPipeWrite
接下來,為 CNamedPipeCltView類增加一個句柄變量,用來保存命名管道實例的句柄。
private:
HANDLE hPipe;
同樣地,在 CNamedPipeCltView類的構造函數中將其初始化為 NULL:
CNarnedPipeCltView:: CNarnedPipeCltView ()
{ 11 TODO: add construction code here hPipe =NULL;
然后,在 CNamedPipeCltView類的析構函數中,如果判斷該句柄有值,則調用 CloseHandle關閉該
句柄:
CNamedPipeCltView: : -CNamedPipeCltView. ()
if (hPipe)
CloseHandle(hPipe);
.
1.連接命名管道
客戶端在連接服務器端程序創建的命名管道之前,首先應判斷一下,是否有可以利用的命名管道,
這可以通過調用WaitNamedPipe函數實現,該函數會一直等待,直到指定的超時間隔己過,或者指定
的命名管道的實例可以用來連接了,也就是說該管道的服務器進程有了一個未決的
ConnectNamedPipe操作。 WaitNamedPipe函數的原型聲明如下所示:
BOOL WaitNamedPipe(LPCTSTR lpNamedPipeName , DWORD nTimeOut) ;
該函數有兩個參數,各自的含義分別如下所述。
. lpNamedPipeName
指定命名管道的名稱,這個名稱必須包括創建該命名管道的服務器進程所在的機器的名稱,該名稱
的格式必須是:"\.\pipe\pipename"。如果在同一臺機器上編寫的命名管道的服務器端程序和客戶
端程序,則當指定這個名稱時,在開始的兩個反斜杠后可以設置一個圓點,表示服務器進程在本地
機器上運行;如果是跨網絡通信,則在這個圓點位置處應指定服務器端程序所在的主機名。
. nTimeOut
指定超時間隔。其取值如表17.15所示。
表17.15 nTimeOut參數取值
取值 說明
NMPWAIT USE DEFAULT WAIT 超時間隔就是服務器端創建該命名管道時指定的超時值
NMPWAIT WAIT FOREVER 一直等待,直到出現了一個可用的命名管道的實例
也就是說,如果這個參數的值是~PWA1T_USE_DEFAULT_WA1T,井且在服務器端調用 CreateNamedPipe
函數創建命名管道時,設置的超時間隔為 IOOOms,那么 WaitNamedPipe函數將以服務器端指定的
1000ms為超時間隔。但有一點需要注意,對同一個命名管道的所有實例來說,它們必須使用同樣的
超時間隔。
如果當前命名管道的實例可以使用,那么客戶端就可以調用CreateFile函數打開這個命名管道,與
服務器端進程進行通信了。因此,客戶端的連接命名管溢的代碼如例 17-12所示。
1~IJ 17-12
void CNamedPipeCltView::OnPipeConnect()
// TODO : Add your command handler code here
//判斷是否有可以利用的命名管道
if ( !WaitNamedPipe ( "\\\\.\\pipe\\MyPipe" ,NMPWAIT_WAIT_FOREVER) )
{
MessageBox("當前沒有可利用的命名管道實例!");
return;
//打開可用的命名管道,并與服務器端進程進行通信
hPipe=CreateFile("\\\\.\\pipe\\MyPipe" ,GENERIC_READ | GENERIC_WRITE,
0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL) ;
if(INVALID_HANDLE_VALUE==hPipe)
{
MessageBox ( n打開命名管道失敗!");
hPipe=NULL;
return;
在如例 17-12所示的OnPipeConnect函數中,首先調用WaitNamedPipe函數,將其超時值設置為
NMPWAIT_WAIT_FOREVER,即讓該函數一直等待,直到指定的命名管道的一個實例可以利用時為止。
并對WaitNamedPipe函數的返回值進行判斷,如果該函數調用失敗,即返回值是0,則提示用戶="當
前沒有可利用的命名管道實例!",然后立即返回。
如果當前指定命名管道有一個實例可以使用,那么就調用 CreateFile函數打開該命名管道。前面介
紹 CreateFile函數時己經提到,該函數不僅可以對文件進行操作,還可以對管道進行操作。當然,
這里指定的文件名就是想要訪問的管道名稱:并且為了對管道進行讀取和寫入操作,需要同時指定
GENE陽已阻AD和GENE陽C-wm四這兩種訪問方式; CreateFile函數的第三個參數用來指定共享方式,
因為本例中,該管道實例只能接受一個客戶端請求的到來,不需要共享,因此將該參數設置為 0;
第四個參數是設置安全屬性,本例將其設置為NULL;第五個參數是指定創建標記,本例將其設置為
OPEN_EXIST劇G,即打開現有的管道:第六個參數是指定文件屬性,本例將其指定為 FILE
ATIRBIJTE-NORMAL;最后一個參數是指定模板文件,本例將其設置為NULL。
如果CreateFile函數調用失敗,返回值將是因VALlD_HANDLE_VALUE。因此,如果判斷該函數的返回
值是劇VALID_HANDLE_VAL阻,則提示用戶:"打開命名管道失敗!",并將管道句柄 ChPipe)設置為
NULL,然后立即返回。
2.讀取數據
如果客戶端成功打開了指定的命名管道,那么就可以進行讀取和寫入操作了。這里,我們可以直接
復制上面服務器端己編寫的從命名管道讀取數據的代碼,結果如例17-13所示。
fJ~ 17-13
void CNamedPipeCltView::OnPipeRead()
{
// TODO: Add your command handler code here
char buf[100];
DWORD dwRead;
if(!ReadFile(hPipe,buf , 100 ,&dwRead ,NULL))
MessageBox(n讀取數據失敗!");
return;
MessageBox(buf) ;
3.寫入數據
這里,我們可以直接復制上面服務器端己編寫的向命名管道寫入數據的代碼,但為了加以區分,將
客戶端寫入的數據修改為 26‘命名管道測試程序飛即客戶端向命名管道寫入數據的代碼如例 17-14
所示。
例 17-14
void CNamedPipeCltView::OnPipeWrite()
// TODO: Add your command handler code here
char buf [ 1= "命名管道測試程序";
DWORD dwWrite;
if(!WriteFile(hPipe, buf , strlen(buf)+1 , &dwWrite ,NULL))
{
MessageBox("寫入數據失敗!");
return;
至此我們就完成了利用命名管道實現進程間通信的客戶端程序,利用 Build命令生成 NamedPipeClt
程序。
因為采用命名管道實現進程間的通信時,通信的兩個進程間不需要有任何關系,所以可以獨立地運
行 NamedPipeSrv和 NamedPipeClt這兩個進程,然后在服務器端單擊 E命名管道\創建管道】菜單
項創建指定的命名管道,在客戶端進程中單擊【命名管道\連接管道】菜單項連接到這個命名管道:
接著在服務器端單擊【命名管道飛寫入數據】菜單項向命名管道中寫入數據,在客戶端單擊【命名
管道飛讀取數據】菜單項從命名管道讀取數據,這時客戶端將彈出一個消息框,提示收到一個網址
字符串: ''http://www.sunxin.org'',程序運行界面如圖 17.6所示。當然,也可以由客戶端進程
寫入數據,服務器端進程讀取數據,即單擊客戶端程序的【命名管道飛寫入數據】菜單項向命名管
道中寫入數據,然后在服務器端單擊【命名管道飛讀取數據】菜單項從命名管道讀取數據,這時服
務器端將彈出一個消息框,提示收到"命名管道測試程序"字符串,程序運行界面如圖 17.7所示。
以上就是采用命名管道完成進程間通信的實現,具體過程是:在服務器端調用 CreateNamedPipe創建
命名管道之后,調用 ConnectNamedPipe函數讓服務器端進程等待客戶端進程連接到該命名管道的實
例上。在客戶端,首先調用 WaitNamedPipe函數判斷當前是否有可以利用的命名管道實例,如果有,
就調用 CreateFile函數打開該命名管道的實例,并建立一個連接。
......... 1655
第17
E皿函
文件巳搞錯(0 .警('fJ幌酣)(!J)命名智;置也
Dt.聲匾吁 .&~ .r~畫!
Y
戳" 性悟,,,..附.銳....,.01'。囂'
眼l
{
就精 黯蟠 '-.
EZ
圖 17.6利用命名管道實現進程間圖 17.7利用命名管道實現進程間
通信的程序結果(一)通信的程序結果〈二〉
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -