<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      用命名管道完成局域網上2臺主機間的文件拷貝

      [摘要]作者: 徐原 能實現局域網上兩臺主機間文件拷貝的方法有很多種,這里介紹的“命名管道”(Named Pipe )是一種比較可靠的進程間通信機制,可用在同一臺計算機不同進程間,也可用在不同計算機的不...
      作者: 徐原

        能實現局域網上兩臺主機間文件拷貝的方法有很多種,這里介紹的“命名管道”(Named Pipe )是一種比較可靠的進程間通信機制,可用在同一臺計算機不同進程間,也可用在不同計算機的不同進程間,可以是單向的,也可以是雙向的,Windows NT、Windows 2000、Windows 95和Windows 98均提供了對它的支持,而且在Unix下也有類似的概念。它是在Microsoft LAN管理器和IBMLAN服務器網絡操作系統上實現的。
      命名管道使用了MSNP(微軟網絡提供者)重定向器,這樣應用程序便可以不用了解網絡協議的細節而利用該機制實現網絡上的數據傳輸。它采用“命名管道文件系統”(Named Pipe File System)接口,其命名是采用UNC(通用命名規范)格式的:
      \\ServerName\Pipe\[pipename]
      \\ServerName指明命名管道是在那個服務器上創建的,ServerName既可以是一個實際的計算機名,也可以是小數點(“.”)以指明是在本機上創建;\Pipe是一個硬編碼(Hardcode)不用區分大小寫的字符串用以指明這是一個管道名,該文件名從屬于NPFS;[pipename]是實際的自定義的管道名,該名稱在前面指定的服務器上必須是唯一的,該名稱可以包含多級目錄,但目錄名必須不是已經創建的管道名,例:
      \\.\Pipe\xyPipe’這是一個合法管道名
      \\.\Pipe\xyPipe\Pipe’這不是一個合法的管道名,因為前面的目錄\\.\Pipe\xyPipe是一個已經創建的管道名了。
      \\.\Pipe\xxyPipe\Pipe’這也是一個合法的文件名
      命名管道有兩種基本通信模式:字節模式和消息模式。在字節模式中,數據是以字節流的形式在管道種傳輸,數據之間沒有邊界,在管道寫入和讀出操作中是以字節流即數據塊為基本單位操作的,這適合傳輸大容量數據;在消息模式中,數據是以一條條不連續的消息為基本傳輸單元,消息和消息之間有邊界,在管道寫入和讀出操作中也是以消息為單位進行操作的,這種方式適合傳輸量小的數據。因為現在的文件大小常常有幾百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常數組合使用以限定客戶端的讀取模式?梢允褂肞IPE_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 = "\\.\pipe\xyvanPipe"
      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的一些特征,如無連接數據報服務和允許向一個組發送消息的命名功能。


      日韩精品一区二区三区高清