VC 下命名管道程式設計的原理及實現

2021-05-24 15:15:24 字數 3226 閱讀 4849

每乙個命名管道都有乙個唯一的名字以區分於存在於系統的命名物件列表中的其他命名管道。管道伺服器在呼叫createnamedpipe()函式建立命名管道的乙個或多個例項時為其指定了名稱。對於管道客戶機,則是在呼叫createfile()或callnamedpipe()函式以連線乙個命名管道例項時對管道名進行指定。命名管道的命名規範與郵槽有些類似,對其標識也是採用的unc格式:

//server/pipe/[path]name

其中,第一部分//server指定了伺服器的名字,命名管道服務即在此伺服器建立,其字串部分可表示為乙個小數點(表示本機)、星號(當前網路字段)、網域名稱或是乙個真正的服務;第二部分/pipe與郵槽的/mailslot一樣是乙個不可變化的硬編碼字串,以指出該檔案是從屬於npfs;第三部分/[path]name則使應用程式可以唯一定義及標識乙個命名管道的名字,而且可以設定多級目錄。

命名管道提供了兩種基本的通訊模式:位元組模式和訊息模式。可在createnamepipe()建立命名管道時分別用pipe_type_byte和pipe_type_message標誌進行設定。在位元組模式中,資訊以連續位元組流的形式在客戶與伺服器之間流動。這也就意味著,對於客戶機應用和伺服器應用,在任何乙個特定的時間段內,都無法準確知道有多少位元組從管道中讀出或寫入。在這種通訊模式中,一方在向管道寫入某個數量的位元組後,並不能保證管道另一方能讀出等量的位元組。對於訊息模式,客戶機和伺服器則是通過一系列不連續的資料報進行資料的收發。從管道發出的每一條訊息都必須作為一條完整的訊息讀入。

使用命名管道

管道伺服器首次呼叫createnamedpipe()函式時,使用nmaxinstance引數指定了能同時存在的管道例項的最大數目。伺服器可以重複呼叫createnamedpipe()函式去建立管道新的例項,直至達到設定的最大例項數。下面給出createnamedpipe()的函式原型:

handle createnamedpipe(

lpctstr lpname, // 指向管道名稱的指標

dword dwopenmode, // 管道開啟模式

dword dwpipemode, // 管道模式

dword nmaxinstances, // 最大例項數

dword noutbuffersize, // 輸出快取大小

dword ninbuffersize, // 輸入快取大小

dword ndefaulttimeout, // 超時設定

lpsecurity_attributes lpsecurityattributes // 安全屬性指標);

如果在已定義超時值變為零以前,有乙個例項管道可以使用,則建立成功並返回管道控制代碼,以此偵聽來自客戶機的連線請求。另一方面,客戶機通過函式waitnamedpipe()使伺服器程序等待來自客戶的例項連線。如果在超時值變為零以前,有乙個管道可供連線使用,則函式將成功返回,並通過呼叫createfile()或callnamedpipe()來呼叫對伺服器的連線。此時伺服器將接受客戶的連線請求,成功建立連線,伺服器呼叫的等待客戶機建立連線的connectnamedpipe()函式也將成功返回。

從呼叫時序上看,首先是客戶機通過waitnamedpipe()使伺服器的createfile()在限時時間內建立例項成功,然後雙方通過connectnamedpipe()和createfile()成功連線,在返回用以通訊的檔案控制代碼後,客戶、服務雙方即可進行通訊。

在建立了連線後,客戶機與伺服器即可通過readfile()和writefile()並利用得到的管道控制代碼,以檔案讀寫的形式彼此間進行資訊交換。 當客戶與伺服器的通訊結束,或是由於某種原因一方需要斷開時,由客戶機呼叫closefile()函式關閉開啟的管道控制代碼,伺服器隨即呼叫disconnectnamedpipe()函式。當然,伺服器也可以通過單方面呼叫disconnectnamedpipe()來終止連線。在終止連線後呼叫函式closehandle()來關閉此管道。下面給出的程式清單即是按照上述方法實現的命名管道伺服器和客戶機進行通訊的簡單程式實現**:

伺服器端:

m_hpipe = createnamedpipe(".//pipe//test", pipe_access_duplex, pipe_type_byte | pipe_readmode_byte, 1, 0, 0, 1000, null); // 建立命名管道

if (m_hpipe == invalid_handle_value)

m_smessage = "建立命名管道失敗!";

else

由於connectnamedpipe()函式在沒有客戶機連線到伺服器時會無限等待下去,因此為避免由此引起主線程的阻塞,為其開闢了乙個子執行緒readproc:

uint readproc(lpvoid lpvoid)

else

// 從管道讀取資料

if (readfile(pview->m_hpipe, buffer, sizeof(buffer), &readnum, null) == false)

else

return 1;}

在客戶同伺服器建立連線後,connectnamedpipe()才會返回,其下語句才得以執行。隨後的readfile()將負責把客戶寫入管道的資料讀取出來。在全部操作完成後,伺服器可以通過呼叫函式disconnectnamedpipe()而終止連線:

if (disconnectnamedpipe(m_hpipe) == false) // 終止連線

m_smessage = "終止連線失敗!";

else

客戶機端:

cstring message = "[測試資料,由客戶機發出]"; // 要傳送的資料

dword writenum; // 傳送的是資料長度

// 等待與伺服器的連線

if (waitnamedpipe(".//pipe//test", nmpwait_wait_forever) == false)

// 開啟已建立的管道控制代碼

handle hpipe = createfile(".//pipe//test", generic_read | generic_write, 0, null, open_existing, file_attribute_normal, null);

if (hpipe == invalid_handle_value)

else

// 向管道寫入資料

if (writefile(hpipe, message, message.getlength(), &writenum, null) == false)

else

closehandle(hpipe); // 關閉管道控制代碼

VC命名管道通訊的實現

無論是 sql server 的使用者,還是 pb的使用者,作為 c s結構開發環境,他們在網路通訊的 實現上,都有一種共同的方法 命名管道。由於當前作業系統的不惟一性,各個系統 都有其獨自的通訊協議,導致了不同系統間通訊的困難。儘管 tcp ip 協議目前已發展成 為 internet 的標準,但...

VC命名管道通訊的實現

無論是 sql server 的使用者,還是 pb的使用者,作為 c s結構開發環境,他們在網路通訊的 實現上,都有一種共同的方法 命名管道。由於當前作業系統的不惟一性,各個系統 都有其獨自的通訊協議,導致了不同系統間通訊的困難。儘管 tcp ip 協議目前已發展成 為internet 的標準,但仍...

VC 下對匿名管道的程式設計實現

總的來說,匿名管道程式是比較簡單的。在下面將要給出的程式示例中,將由父程序 管道伺服器 建立乙個子程序 管道客戶機 子程序回見個其全部的標準輸出傳送到匿名管道中,父程序再從管道讀取資料,一直到子程序關閉管道的寫控制代碼。其中,匿名管道伺服器程式的實現清單如下 startupinfo si proce...