無論是SQL Server的使用者,還是PB的使用者,作為C/S結構開發環境,他們在網絡通信的
實作上,都有一種共同的方法__命名管道。由于目前作業系統的不惟一性,各個系統
都有其獨自的通信協定,導緻了不同系統間通信的困難。盡管TCP/IP協定目前已發展成
為Internet的标準,但仍不能保證C/S應用程式的順利進行。命名管道作為一種通信方
法,有其獨特的優越性,這主要表現在它不完全依賴于某一種協定,而是适用于任何
協定__隻要能夠實作通信。
命名管道具有很好的使用靈活性,表現在:
1) 既可用于本地,又可用于網絡。
2) 可以通過它的名稱而被引用。
3) 支援多客戶機連接配接。
4) 支援雙向通信。
5) 支援異步重疊I/O操作。
不過,目前隻有Windows NT支援服務端的命名管道技術。
一、命名管道程式設計的實作
1.命名管道Server和Client間通信的實作流程
(1)建立連接配接:服務端通過函數CreateNamedPipe建立一個命名管道的執行個體并傳回用于
今後操作的句柄,或為已存在的管道建立新的執行個體。如果在已定義逾時值變為零以前,有
一個執行個體管道可以使用,則建立成功并傳回管道句柄,并用以偵聽來自用戶端的連接配接請求,
該功能通過ConnectNamedPipe函數實作。
另一方面,用戶端通過函數WaitNamedPipe使服務程序等待來自客戶的執行個體連接配接,如
果在逾時值變為零以前,有一個管道可以為連接配接使用,則WaitNamedPipe将傳回True,并
通過調用CreateFile或CallNamedPipe來呼叫對服務端的連接配接。此時服務端将接受用戶端
的連接配接請求,成功建立連接配接,服務端ConnectNamedPipe傳回True,用戶端CreateFile将返
回一指向管道檔案的句柄。
從時序上講,首先是用戶端通過WaitNamedPipe使服務端的CreateFile在限時時間内
建立執行個體成功,然後雙方通過ConnectNamedPipe和CreateFile成功連接配接,并傳回用以通信
的檔案句柄,此時雙方即可進行通信。
(2)通信實作:建立連接配接之後,用戶端與伺服器端即可通過ReadFile和WriteFile,
利用得到的管道檔案句柄,彼此間進行資訊交換。
(3)連接配接終止:當用戶端與服務端的通信結束,或由于某種原因一方需要斷開時,客
戶端應調用CloseFile,而服務端應接着調用DisconnectNamedPipe。當然服務端亦可通
過單方面調用DisconnectNamedPipe終止連接配接。最後應調用函數CloseHandle來關閉該管道。
2.命名管道伺服器端和用戶端代碼實作
(1)用戶端:
HANDLE CltHandle;
char pipenamestr[30];
sprintf(pipenamestr,”\\\\servername\\pipe\\pipename”)
if (WaitNamedPipe( pipenamestr, NMPWAIT_WAIT_FOREVER)==FALSE
// 管道名要遵循UNC,格式為\ \.\pipe\pipname,名字不分大小寫。
AfxMessageBox(“操作失敗,請确定服務端正确建立管道執行個體!”);
Else
CltHandle=CreateFile(pipenamestr, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ| FILE_SHARE_WRITE,NULL, OPEN_EXISTING,
//為了與命名管道連接配接,此參數應一直為OPEN_EXISTING
FILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_WRITE_THROUGH,
// FILE_FLAG_WRITE_THROUGH會使管道WriteFile調用處于阻塞狀态,直到資料傳送成功。
NULL);
If (CltHandle== INVALID_HANDLE_VALUE)
AfxMessageBox(“管道連接配接失敗”);
Else
DoUsertTransactInfo();
//執行使用者自定義資訊交換函數__從管道讀、寫資訊。
……
(2)服務端:
HANDLE SvrHandle;
char pipenamestr[30];
sprintf(pipenamestr,”\\\\.\\pipe\\pipename”)
SvrHandle=CreateNamedPipe(pipenamestr,
PIPE_ACCESS_DUPLEX|FILE_FLAG_WRITE_THROUGH,
//阻塞模式,這種模式僅對”位元組傳輸管道”操作有效。
FILE_WAIT|PIPE_TYPE_BYTE,
//位元組模式
PIPE_UNLIMITED_INSTANCES,
128,128,
NULL,NULL);
// SECURITY_ATTRIBUTES結構指針,描述一個新管道,确定子程序的繼承權,如果為NULL則該命名管道不能被繼承。
If (SvrHandle==INVALID_HANDLE_VALUE)
AfxMessageBox(“管道建立失敗,請确定用戶端提供連接配接可能!”);
Else
If (ConnectNamedPipe(SvrHandle,NULL)==FALSE)
AfxMessageBox(“建立連接配接失敗!”);
Else
DoUsertTransactInfo();
//使用者自定義資訊交換函數
……
二、程式設計的注意事項
1.如果命名管道用戶端已打開,函數将會強迫關閉管道,用DisconnectNamedPipe關閉
的管道,其用戶端還必須用CloseHandle來關閉最後的管道。
2. ReadFile和WriteFile的hFile句柄是由CreateFile及ConnectNamedPipe傳回得到。
3.一個已被某用戶端連接配接的管道句柄在被另一客戶通過ConnectNamedPipe建立連接配接之前,服務端必須用DisconnectNamedPipe函數對已存在的連接配接進行強行拆離。服務端拆離管道會造成管道中資料的丢失,用FlushFileBuffers函數可以保證資料不被丢失。
4.命名管道服務端可以通過新建立的管道句柄或已被連接配接過其他客戶的管道句
柄來使用ConnectNamedPipe函數,但在連接配接新的用戶端之前,服務端必須用函數
DisconnectNamedPipe切斷之前的客戶句柄,否則ConnectNamedPipe 将會傳回False。
5.阻塞模式,這種模式僅對“位元組傳輸管道"操作有效,并且要求用戶端與服務端不
在同一機器上。如果用這種模式,則隻有當函數通過網絡向遠端計算機管道緩沖器寫數
據成功時,才能有效傳回。如果不用這種模式,系統會運作預設方式以提高網絡的工作效率。
6.使用者必須用FILE_CREATE_PIPE_INSTANCE 來通路命名管道對象。新的命名管
道建立後,來自安全參數的通路控制清單定義了通路該命名管道的權限。所有命名管道
執行個體必須使用統一的管道傳輸方式、管道模式等參數。用戶端未啟動,管道服務端不能
執行阻塞讀操作,否則會發生空等的阻塞狀态。當最後的命名管道執行個體的最後一個句柄
被關閉時,就應該删除該命名管道。