用命名的管道實現區域網兩臺主機的檔案拷貝

能實現區域網上兩臺主機間檔案拷貝的方法有很多種,這裡由小編介紹的“命名管道”***Named Pipe ***是一種比較可靠的程序間通訊機制,可用在同一臺計算機不同程序間,也可用在不同計算機的不同程序間,可以是單向的,也可以是雙向的,希望對你有幫助!

方法:

命名管道使用了MSNP***網路提供者***重定向器,這樣應用程式便可以不用瞭解網路協議的細節而利用該機制實現網路上的資料傳輸。它採用“命名管道檔案系統”***Named Pipe File System***介面,其命名是採用UNC***通用命名規範***格式的:

]

指明命名管道是在那個伺服器上建立的,ServerName既可以是一個實際的計算機名,也可以是小數點***“.”***以指明是在本機上建立;\Pipe是一個硬編碼***Hardcode***不用區分大小寫的字串用以指明這是一個管道名,該檔名從屬於NPFS;[pipename]是實際的自定義的管道名,該名稱在前面指定的伺服器上必須是唯一的,該名稱可以包含多級目錄,但目錄名必須不是已經建立的管道名,例:

這是一個合法管道名

這不是一個合法的管道名,因為前面的目錄是一個已經建立的管道名了。

這也是一個合法的檔名

命名管道有兩種基本通訊模式:位元組模式和訊息模式。在位元組模式中,資料是以位元組流的形式在管道種傳輸,資料之間沒有邊界,在管道寫入和讀出操作中是以位元組流即資料塊為基本單位操作的,這適合傳輸大容量資料;在訊息模式中,資料是以一條條不連續的訊息為基本傳輸單元,訊息和訊息之間有邊界,在管道寫入和讀出操作中也是以訊息為單位進行操作的,這種方式適合傳輸量小的資料。因為現在的檔案大小常常有幾百K甚至更大,所以程式中選擇使用位元組模式。

下面詳細介紹一下CreateNamedPipe******這個函式

該函式C原型如下:

HANDLE CreateNamedPipe***

LPCTSTR lpName, // pointer to pipe name

DWORD dwOpenMode, // pipe open mode

DWORD dwPipeMode, // pipe-specific modes

DWORD nMaxInstances, // maximum number of instances

DWORD nOutBufferSize, // output buffer size, in bytes

DWORD nInBufferSize, // input buffer size, in bytes

DWORD nDefaultTimeOut, // time-out time, in milliseconds

LPSECURITY_ATTRIBUTES lpSecurityAttributes // pointer to security attributes

***;

lpName:為前面所述的命名管道名。

dwOpenMode:為命名管道開啟的模式,有PIPE_ACCESS_DUMPLEX***雙向***、PIPE_ACCESS_INBOUND***輸入***、PIPE_ACCESS_OUTBOUND***輸出***這三種,這些標誌還可以和一些附加的I/O控制和模式的常數組合使用,詳細可參考MSDN。

dwPipeMode:為管道傳輸模式,有前面所述的PIPE_TYPE_BYTE***位元組模式***和PIPE_TYPE_MESSAGE***訊息模式***兩種,可以和PIPE_READMODE_BYTE和PIPE_READMODE_MESSAGE常數組合使用以限定客戶端的讀取模式。可以使用PIPE_TYPE_MESSAGE 和 PIPE_READMODE_BYTE組合來指定傳送者以訊息模式向管道傳送資料,而接收者一次可以讀取任意數量的位元組。注意不可將PIPE_TYPE_BYTE和PIPE_READMODE_MESSAGE組合使用,這樣會導致CreateNamedPipe******函式呼叫失敗,因為位元組模式沒有邊界,在接收端用訊息模式讀取的時候無法判斷訊息的邊界。

程式碼:

nMaxInstances:管道最大的連線例項控制代碼,其範圍在1到255之間。

nOutBufferSize和nInBufferSize分別指明管道輸出和輸入緩衝區的大小,如設為0則使用系統預設大小。

nDefaultTimeOut以毫秒為單位設定客戶機等待同命名管道建立連線的最長時間。

LpSecurityAttruibutes為一個安全描述符,設為Null表示使用系統預設的描述符,同時控制代碼不可繼承。

要注意的是在程式中命名管道的寫操作中一次最大隻能寫64K位元組的資料,下面是伺服器端程式***模組中***:

Public Declare Function CreateNamedPipe Lib "kernel32" Alias "CreateNamedPipeA" ***ByVal lpName As String, ByVal dwOpenMode As Long, ByVal dwPipeMode As Long, ByVal nMaxInstances As Long, ByVal nOutBufferSize As Long, ByVal nInBufferSize As Long, ByVal nDefaultTimeOut As Long, ByVal lpSecurityAttributes As Long*** As Long

Public Declare Function ConnectNamedPipe Lib "kernel32" ***ByVal hNamedPipe As Long, ByVal lplong As Long*** As Long

Public Declare Function ReadFile Lib "kernel32" ***ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lplong As Long*** As Long

Public Declare Function WriteFile Lib "kernel32" ***ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lplong As Long*** As Long

Public Declare Function CloseHandle Lib "kernel32" ***ByVal hObject As Long*** As Long

Public Declare Function WaitNamedPipe Lib "kernel32" Alias "WaitNamedPipeA" ***ByVal lpNamedPipeName As String, ByVal nTimeOut As Long*** As Long

Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" ***ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long*** As Long

Public Declare Function DisconnectNamedPipe Lib "kernel32" ***ByVal hNamedPipe As Long*** As Long

Public Declare Function GetFileSize Lib "kernel32" ***ByVal hFile As Long, lpFileSizeHigh As Long*** As Long

Public Const PIPE_ACCESS_DUPLEX = &H3

Public Const PIPE_ACCESS_INBOUND = &H1

Public Const PIPE_ACCESS_OUTBOUND = &H2

Public Const PIPE_CLIENT_END = &H0

Public Const PIPE_NOWAIT = &H1

Public Const PIPE_READMODE_BYTE = &H0

Public Const PIPE_READMODE_MESSAGE = &H2

Public Const PIPE_SERVER_END = &H1

Public Const PIPE_TYPE_BYTE = &H0

Public Const PIPE_TYPE_MESSAGE = &H4

Public Const PIPE_UNLIMITED_INSTANCES = 255

Public Const PIPE_WAIT = &H0

Public Const FILE_SHARE_READ = &H1

Public Const FILE_SHARE_WRITE = &H2

Public Const GENERIC_READ = &H80000000

Public Const GENERIC_WRITE = &H40000000

Public Const GENERIC_EXECUTE = &H20000000

Public Const GENERIC_ALL = &H10000000

Public Const OPEN_EXISTING = 3

Public Const ERROR_PIPE_BUSY = 231&

Public Const ERROR_PIPE_CONNECTED = 535&

Public Const ERROR_PIPE_LISTENING = 536&

Public Const ERROR_PIPE_NOT_CONNECTED = 233&

Public Const ERROR_NO_DATA = 232&

Public Const BufferSize& = 51200

Public hNamePipe&, hFile&, strNamePipe$

Form中有三個按鈕,分別是“建立命名管道”***CreateNPipe***、“傳送檔案”***SendFile***、“關閉命名管道”***CloseNamePipe***,視窗中還有一個CommonDialog控制元件,命名為“CDlg1”。Form中程式碼:

Dim outBuffer****** As Byte, inBuffer****** As Byte, BytesRead As Long, BytesWrite As Long, BytesReaded As Long, BytesWrited As Long

Private Sub CloseNamePipe_Click******

DisconnectNamedPipe hNamePipe

CloseHandle hNamePipe

CreateNPipe.Enabled = True

SendFile.Enabled = False

CloseNamePipe.Enabled = False

End Sub

Private Sub CreateNPipe_Click******

Dim hReturn&

strNamePipe = ""

hNamePipe = CreateNamedPipe***strNamePipe, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE Or PIPE_READMODE_BYTE, 1, 0, 0, 0, 0***

If hNamePipe <> -1 Then

hReturn = ConnectNamedPipe***hNamePipe, 0***

If hReturn = 0 Then

MsgBox "管道無法等待客戶端的連線!", vbInformation Or vbOKOnly

Unload Me

Else

Label1 = "已同客戶機連線上!"

End If

CreateNPipe.Enabled = False

SendFile.Enabled = True

CloseNamePipe.Enabled = True

Else

MsgBox "無法建立命名管道!", vbInformation Or vbOKOnly

Unload Me

End If

End Sub

Private Sub Form_Load******

With CDlg1

.CancelError = True

.DialogTitle = "請選擇要傳輸的檔案:"

.filename = ""

.Filter = "所有檔案****.****|*.*"

.Flags = cdlOFNExplorer Or cdlOFNFileMustExist Or cdlOFNPathMustExist

.InitDir = "d:\"

End With

SendFile.Enabled = False

CloseNamePipe.Enabled = False

End Sub

Private Sub Form_QueryUnload***Cancel As Integer, UnloadMode As Integer***

DisconnectNamedPipe hNamePipe

CloseHandle hFile

CloseHandle hNamePipe

End Sub

Private Sub SendFile_Click******

On Error Resume Next

Dim strFileName$, lpFileSize&, lpFileSizeHigh&, lpFileSizeLeast&, byteEnd****** As Byte

Dim strShortName$

CDlg1.ShowOpen

If Err.Number = 32755 Then Exit Sub

strFileName = CDlg1.filename

strShortName = CDlg1.FileTitle

hFile = CreateFile***strFileName, GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0***

If hFile = -1 Then

MsgBox "無法開啟檔案" & strFileName, vbInformation Or vbOKOnly

Exit Sub

End If

lpFileSize = GetFileSize***hFile, lpFileSizeHigh***

If lpFileSize = 0 Then

MsgBox "該檔案大小為零,不用傳送!", vbInformation Or vbOKOnly

CloseHandle hFile

Exit Sub

End If

lpFileSizeLeast = lpFileSize

byteEnd****** = StrConv***strShortName, vbFromUnicode***

ReDim outBuffer***UBound***byteEnd******

ByteCopy byteEnd, outBuffer

WriteFile hNamePipe, byteEnd***0***, UBound***byteEnd*** + 1, BytesWrited, 0 '傳送短檔名

ReDim inBuffer***5***

ReadFile hNamePipe, inBuffer***0***, 6, BytesReaded, 0 '讀取客戶端對話資訊

If StrConv***inBuffer, vbUnicode*** = "Cancel" Then

MsgBox "客戶端儲存時選擇了取消,傳送終止!", vbInformation Or vbOKOnly

CloseHandle hFile

Exit Sub

End If

Label1.Caption = "正在傳輸中…"

While lpFileSize > 0

If lpFileSize > BufferSize Then

ReDim outBuffer***BufferSize - 1***

ReadFile hFile, outBuffer***0***, BufferSize, BytesReaded, 0

WriteFile hNamePipe, outBuffer***0***, BytesReaded, BytesWrited, 0

Else

ReDim outBuffer***lpFileSize - 1***

ReadFile hFile, outBuffer***0***, lpFileSize, BytesReaded, 0

WriteFile hNamePipe, outBuffer***0***, lpFileSize, BytesWrited, 0

End If

lpFileSize = lpFileSize - BytesReaded

ReadFile hNamePipe, inBuffer***0***, 6, BytesReaded, 0

Wend

byteEnd****** = StrConv***"EOF", vbFromUnicode***

ReDim outBuffer***UBound***byteEnd******

ByteCopy byteEnd, outBuffer

WriteFile hNamePipe, outBuffer***0***, 3, BytesWrited, 0

CloseHandle hFile

Label1 = "傳送檔案完畢!"

End Sub

Public Sub ByteCopy***bySrc****** As Byte, byDes****** As Byte***

Dim I As Long

For i = LBound***bySrc*** To UBound***bySrc***

byDes***i*** = bySrc***i***

Next

End Sub

客戶端程式***模組中程式和伺服器端是一樣的,這裡省略不寫了***,Form中有一個Text框,用以輸入要開啟連線的伺服器端的命名管道的名稱,一個CommonDialog***CDlg1***控制元件,另還有一“連線命名管道”***Connect***按鈕和“斷開連線”***Disconnect***按鈕,程式如下:

Dim inBuffer****** As Byte, BytesRead&, BytesReaded&, BytesWrited&, strFileName$

Private Sub Connect_Click******

Dim hRes&

strNamePipe = Text1

hRes = WaitNamedPipe***strNamePipe, -1***

If hRes = 0 Then

MsgBox "沒有可用的命名管道以供連線!", vbInformation Or vbOKOnly

Exit Sub

End If

hNamePipe = CreateFile***strNamePipe, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0***

If hNamePipe = 0 Then

MsgBox "無法開啟指定的命名管道進行讀寫!", vbInformation Or vbOKOnly

Exit Sub

End If

FileSave

End Sub

Private Sub Disconnect_Click******

CloseHandle hFile

CloseHandle hNamePipe

End Sub

Private Sub Form_Load******

With CDlg1

.CancelError = True

.DialogTitle = "儲存為:"

.FileName = ""

' .Filter = "所有檔案****.****|*.*"

.Flags = cdlOFNExplorer Or cdlOFNOverwritePrompt

.InitDir = "d:\"

End With

End Sub

Private Sub FileSave******

BytesRead = 51200

Dim AckByte****** As Byte

ReDim inBuffer***BytesRead - 1***

On Error Resume Next

Do

ReadFile hNamePipe, inBuffer***0***, BytesRead, BytesReaded, 0

If BytesReaded < 258 Then

strFileName = Trim***StrConv***inBuffer, vbUnicode******

strFileName = Left***strFileName, InStr***strFileName, Chr***0****** - 1***

If strFileName Like "EOF*" And BytesReaded = 3 Then

CloseHandle hFile

MsgBox "檔案接收完畢!", vbInformation Or vbOKOnly Or vbSystemModal

Exit Sub

Else

CDlg1.Filter = UCase***GetExtension***strFileName****** & "檔案****." & GetExtension***strFileName*** & "***|*." & GetExtension***strFileName***

CDlg1.FileName = Left***strFileName, InStr***strFileName, "."*** - 1***

ReSelect: CDlg1.ShowSave

If Err.Number = 32755 Then

AckByte****** = StrConv***"Cancel", vbFromUnicode***

WriteFile hNamePipe, AckByte***0***, UBound***AckByte********* + 1, BytesWrited, 0

MsgBox "你選擇了取消鍵!", vbInformation Or vbOKOnly

Exit Sub

End If

hFile = CreateFile***CDlg1.FileName, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0***

If hFile = -1 Then

MsgBox "無法建立指定檔案,請重新選擇檔名!", vbInformation Or vbOKOnly

GoTo ReSelect

End If

AckByte****** = StrConv***"RecvOk", vbFromUnicode***

WriteFile hNamePipe, AckByte***0***, UBound***AckByte********* + 1, BytesWrited, 0

End If

Else

WriteFile hFile, inBuffer***0***, BytesReaded, BytesWrited, 0

AckByte****** = StrConv***"RecvOk", vbFromUnicode***

WriteFile hNamePipe, AckByte***0***, UBound***AckByte********* + 1, BytesWrited, 0

End If

Loop Until 1 = 0

End Sub

Private Function GetExtension***ByVal FileName$*** As String

GetExtension = Right***FileName, Len***FileName*** - InStr***FileName, "."******

End Function

Public Sub ByteCopy***bySrc****** As Byte, byDes****** As Byte***

Dim i&

For i = LBound***bySrc*** To UBound***bySrc***

byDes***i*** = bySrc***i***

Next

End Sub

Private Sub Form_QueryUnload***Cancel As Integer, UnloadMode As Integer***

CloseHandle hFile

CloseHandle hNamePipe

End Sub

該程式在VB5、Windows NT 4.0上除錯通過。

在處理網路事務上,命名管道介面比Net BIOS要好,而且只需使用一個簡單的呼叫就可達到目的,而無需通過Net BIOS執行許多操作。然而,命名管道介面並不提供Net BIOS的一些特徵,如無連線資料報服務和允許向一個組傳送訊息的命名功能。

希望小編的整理對你有幫助,謝謝!