王朝网络
分享
 
 
 

用命名管道实现局域网上两台主机间的文件拷贝

王朝厨房·作者佚名  2007-01-04
宽屏版  字体: |||超大  

作者: 徐原

能实现局域网上两台主机间文件拷贝的方法有很多种,这里介绍的“命名管道”(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常数组合使用以限定客户端的读取模式。可以使用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 = "\\.\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的一些特征,如无连接数据报服务和允许向一个组发送消息的命名功能。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有