Cómo utilizar canalizaciones con nombre para copiar archivos entre dos hosts en la LAN
Hay muchas formas de copiar archivos entre dos hosts en una LAN. La "canalización con nombre" presentada aquí es un mecanismo de comunicación entre procesos relativamente confiable que se puede usar en la misma computadora. También se puede utilizar entre diferentes procesos en diferentes computadoras. Puede ser unidireccional o bidireccional. Windows NT, Windows 2000, Windows 95 y Windows 98 lo admiten y también están disponibles en Unix. . Se implementa en los sistemas operativos de red de servidores Microsoft LAN Manager e IBM LAN.
Las canalizaciones con nombre utilizan el redirector MSNP (Microsoft Network Provider) para que las aplicaciones puedan utilizar este mecanismo para transmitir datos en la red sin conocer los detalles del protocolo de red. Utiliza la interfaz "Named Pipe File System" y su denominación está en formato UNC (Convención de nomenclatura universal):
\\ServerName\Pipe\[pipename]
\\ServerName especifica el servidor en el que se creó la canalización con nombre. ServerName puede ser un nombre de computadora real o un punto decimal (".") para indicar que se creó en esta máquina. \Pipe es un caso codificado (Hardcode) A; -cadena insensible que indica que se trata de un nombre de tubería. El nombre del archivo pertenece a NPFS; [nombre de tubería] es el nombre de tubería personalizado real, que debe ser único en el servidor especificado anteriormente, el nombre puede contener directorios de varios niveles, pero el. El nombre del directorio no debe ser el nombre de una tubería ya creada, por ejemplo:
\\.\Pipe\xyPipe'Este es un nombre de tubería legal
\\.\Pipe\ xyPipe\Pipe' no es un nombre de tubería legal, porque el directorio anterior \\.\Pipe\xyPipe es un nombre de tubería ya creado.
\\.\Pipe\xxyPipe\Pipe’ Este también es un nombre de archivo legal
Las canalizaciones con nombre tienen dos modos de comunicación básicos: modo byte y modo mensaje. En el modo de bytes, los datos se transmiten en la tubería en forma de un flujo de bytes y no hay límites entre los datos en las operaciones de escritura y lectura de la tubería, la unidad básica de operación es el flujo de bytes, es decir, el bloque de datos. que es adecuado para transmitir datos de gran capacidad; en el modo de mensaje, los datos se basan en mensajes discontinuos como unidad de transmisión básica. En las operaciones de escritura y lectura de canales, los mensajes también se operan en unidades. Es adecuado para transmitir pequeñas cantidades de datos. Debido a que los tamaños de archivos actuales suelen ser cientos de K o incluso mayores, el programa opta por utilizar el modo byte.
La siguiente es una introducción detallada a la función CreateNamedPipe(). El prototipo C de esta función es el siguiente:
HANDLE CreateNamedPipe(
LPCTSTR lpName, // puntero al nombre de la tubería
DWORD dwOpenMode, // modo de apertura de la tubería
DWORD dwPipeMode, // modos específicos de la tubería
DWORD nMaxInstances, // máximo número de instancias
DWORD nOutBufferSize, // tamaño del búfer de salida, en bytes
DWORD nInBufferSize, // tamaño del búfer de entrada, en bytes
DWORD nDefaultTimeOut, / / tiempo de espera, en milisegundos
LPSECURITY_ATTRIBUTES lpSecurityAttributes // puntero a los atributos de seguridad
);
lpName: es el nombre de la canalización con nombre mencionada anteriormente. .
dwOpenMode: Hay tres modos para abrir canalizaciones con nombre: PIPE_ACCESS_DUMPLEX (bidireccional), PIPE_ACCESS_INBOUND (entrada) y PIPE_ACCESS_OUTBOUND (salida). Estos indicadores también se pueden combinar con algunos modos de seguridad y control de E/S adicionales. Se utilizan combinaciones constantes; consulte MSDN para obtener más detalles.
dwPipeMode: Es el modo de transmisión de tubería. Hay dos tipos de PIPE_TYPE_BYTE (modo byte) y PIPE_TYPE_MESSAGE (modo de mensaje) mencionados anteriormente. Se puede usar en combinación con las constantes PIPE_READMODE_BYTE y PIPE_READMODE_MESSAGE. modo de lectura del cliente. Puede usar la combinación PIPE_TYPE_MESSAGE y PIPE_READMODE_BYTE para especificar que el remitente envíe datos a la canalización en modo de mensaje y que el receptor pueda leer cualquier número de bytes a la vez. Tenga en cuenta que PIPE_TYPE_BYTE y PIPE_READMODE_MESSAGE no se pueden usar en combinación. Esto hará que la llamada a la función CreateNamedPipe() falle, porque el modo de bytes no tiene límites y los límites del mensaje no se pueden determinar cuando el extremo receptor lee en modo de mensaje.
nMaxInstances: el identificador de instancia de conexión más grande de la canalización, que va de 1 a 255.
nOutBufferSize y nInBufferSize especifican el tamaño de los buffers de entrada y salida de la canalización respectivamente. Si se establece en 0, se utiliza el tamaño predeterminado del sistema.
nDefaultTimeOut establece el tiempo máximo en milisegundos que el cliente debe esperar para establecer una conexión con la canalización nombrada.
LpSecurityAttruibutes es un descriptor de seguridad. Configurarlo en Nulo significa usar el descriptor predeterminado del sistema y el identificador no se puede heredar.
Cabe señalar que en la operación de escritura de la canalización con nombre en el programa, solo se puede escribir un máximo de 64 K bytes de datos a la vez.
El siguiente es el. programa del lado del servidor:
(en módulo):
Función de declaración pública CreateNamedPipe Lib "kernel32" Alias "CreateNamedPipeA" (ByVal lpName As String, ByVal dwOpenMode As Long, ByVal dwPipeMode Mientras, ByVal nMaxInstances Mientras, ByVal nOutBufferSize Mientras, ByVal nInBufferSize Mientras, ByVal nDefaultTimeOut Mientras, ByVal lpSecurityAttributes Mientras) Mientras
Función de declaración pública ConnectNamedPipe Lib "kernel32" (ByVal hNamedPipe Como Long, ByVal lplong As Long) As Long
Función de declaración pública ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lplong As Long) As Long
Función de declaración pública WriteFile Lib "kernel32" (ByVal hFile mientras, lpBuffer como cualquiera, ByVal nNumberOfBytesToWrite mientras, lpNumberOfBytesWritten mientras, ByVal lplong mientras) Mientras
Declaración pública Función CloseHandle Lib "kernel32" (ByVal hObject As Long) Mientras
Función de declaración pública WaitNamedPipe Lib "kernel32" Alias "WaitNamedPipeA" (ByVal lpNamedPipeName As String, ByVal nTimeOut As Long) Mientras p>
Función de declaración pública CreateFile Lib "kernel32" Alias " CreateFileA" (ByVal lpFileName como cadena, ByVal dwDesiredAccess mientras, ByVal dwShareMode mientras, ByVal lpSecurityAttributes mientras, ByVal dwCreationDisposition mientras, ByVal dwFlagsAndAttributes mientras, ByVal hTemplateFile As Long) As Long
Función de declaración pública DisconnectNamed
Pipe Lib "kernel32" (ByVal hNamedPipe As Long) Mientras
Función de declaración pública GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) Mientras tanto Public Const PIPE_ACCESS_DUPLEX = &H3
Const pública PIPE_ACCESS_INBOUND = &H1
Const pública PIPE_ACCESS_OUTBOUND = &H2
Const pública PIPE_CLIENT_END = &H0
Const pública PIPE_NOWAIT = &H1
Const pública PIPE_READMODE_BYTE = &H0
Const pública PIPE_READMODE_MESSAGE = &H2
Const pública PIPE_SERVER_END = &H1
Const pública PIPE_TYPE_BYTE = &H0
Const pública PIPE_TYPE_MESSAGE = &H4
Const pública PIPE_UNLIMITED_INSTANCES = 255
Const pública PIPE_WAIT = &H0
Const pública FILE_SHARE_READ = &H1
Const pública FILE_SHARE_WRITE = &H2
Const pública GENERIC_READ = &H80000000
Const pública GENERIC_WRITE = &H40000000
Const pública GENERIC_EXECUTE = &H20000000
Const pública GENERIC_ALL = &H1000000 0
Const pública OPEN_EXISTING = 3
Const pública ERROR_PIPE_BUSY = 231&
Const pública ERROR_PIPE_CONNECTED = 535&
Const pública ERROR_PIPE_LISTENING = 536& p >
Public Const ERROR_PIPE_NOT_CONNECTED = 233&
Public Const ERROR_NO_DATA = 232& Public Const BufferSize& = 51200
Public hNamePipe&, hFile&, strNamePipe$ Hay tres botones en el formulario, a saber "Crear" canalización con nombre "(CreateNPipe), "Enviar archivo" (SendFile), "Cerrar canalización con nombre" (CloseNamePipe), y también hay un CommonDia en la ventana
control de registro, denominado "CDlg1".
Código en el formulario:
Atenuar outBuffer() como byte, inBuffer() como byte, BytesRead mientras, BytesWrite mientras, BytesReaded mientras, BytesWrited mientras
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 o PIPE_READMODE_BYTE, 1, 0, 0, 0, 0)
Si hNamePipe <> -1 entonces
hReturn = ConnectNamedPipe( hNamePipe, 0)
Si hReturn = 0 Entonces
MsgBox "¡La tubería no puede esperar a la conexión del cliente!", vbInformation O vbOKOnly
Descargarme p>
Else
Label1 = "¡Conectado al cliente!"
End If
CreateNPipe.Enabled = False
SendFile.Enabled = True
CloseNamePipe.Enabled = True
Else
MsgBox "¡No se puede crear una canalización con nombre!", vbInformation o vbOKOnly
Descargarme
Finalizar si
Finalizar sub privado Form_Load()
Con CDlg1
.CancelError = True
.DialogTitle = "Seleccione los archivos a transferir:"
.filename = ""
.Filter = "Todos los archivos (*.*)|*.* "
.Flags = cdlOFNExplorer O cdlOFNFileMustExist O cdlOFNPathMustExist
.InitDir = "d:\"
Finalizar con
SendFile.Enabled = False
CloseNamePipe.Enabled = False
End Sub Private Sub Form_QueryUnload(Cancelar como entero, UnloadMode como entero)
DisconnectNamedPipe hNam
ePipe
CloseHandle hFile
CloseHandle hNamePipe
Fin Sub Private Sub SendFile_Click()
En caso de error Reanudar siguiente
Dim strFileName$, lpFileSize&, lpFileSizeHigh&, lpFileSizeLeast&, byteEnd() como byte
Dim strShortName$
CDlg1.ShowOpen
Si Err.Number = 32755 Entonces Salir de Sub
strFileName = CDlg1.filename
strShortName = CDlg1.FileTitle
hFile = CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ o FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0 , 0)
Si hFile = -1 Entonces
MsgBox "No se puede abrir el archivo" & strFileName, vbInformation o vbOKOnly
Salir de Sub
Finalizar si
lpFileSize = GetFileSize(hFile, lpFileSizeHigh)
Si lpFileSize = 0 Entonces
MsgBox "El tamaño del archivo es cero, ¡no es necesario enviarlo! ", vbInformation O vbOKOnly
CloseHandle hFile
Salir 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 'Enviar nombre de archivo corto
ReDim inBuffer(5)
ReadFile hNamePipe, inBuffer(0), 6, BytesReaded, 0 'Leer información de conversación del cliente
If StrConv(inBuffer, vbUnicode) = "Cancelar" Entonces
MsgBox "¡El cliente seleccionó cancelar al guardar y el envío finaliza! ", vbInformation O vbOKOnly
CloseHandle hFile
Salir Sub
End If
Label1.Caption = "Transmitiendo..."
Mientras lpFileSize > 0
Si lpFileSize > BufferSize entonces
ReDim outBuffer(BufferSize - 1)
ReadF
ile 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 = "¡Transferencia de archivo completada!"
End Sub
Public Sub ByteCopy(bySrc() As Byte, byDes() como byte)
Atenuar I mientras
For i = LBound(bySrc) a UBound(bySrc)
byDes(i) = bySrc(i)
Next
End Sub Por lo demás, agrégame en QQ y te engordaré y te daré 83989024