Monday, December 31, 2007

How to: Use Named Pipes to Communicate Between Processes over a Network

How to: Use Named Pipes to Communicate Between Processes over a Network
Named pipes offer more functionality than anonymous pipes. This functionality includes full duplex communication over a network and multiple server instances; message-based communication; and client impersonation, which enables connecting processes to use their own set of permissions on remote servers.

Imports System
Imports System.IO
Imports System.IO.Pipes
Imports System.Threading

Class PipeServer
Shared numThreads As Integer = 4

Shared Sub Main()
Dim i As Integer
For i = 1 To numThreads
Dim newThread As New Thread(New ThreadStart(AddressOf ServerThread))
newThread.Start()
Next
End Sub

Private Shared Sub ServerThread()
Dim pipeServer As New NamedPipeServerStream("testpipe", _
PipeDirection.InOut, numThreads)

Console.WriteLine("NamedPipeServerStream thread created.")

' Wait for a client to connect
pipeServer.WaitForConnection()

Console.WriteLine("Client connected.")
Try
' Read the request from the client. Once the client has
' written to the pipe, its security token will be available.
Dim sr As New StreamReader(pipeServer)
Dim sw As New StreamWriter(pipeServer)
sw.AutoFlush = True

' Verify our identity to the connected client using a
' string that the client anticipates.
sw.WriteLine("I am the true server!")

' Obtain the filename from the connected client.
Dim filename As String = sr.ReadLine()

' Read in the contents of the file while impersonating
' the client.
Dim fileReader As New ReadFileToStream(pipeServer, filename)

' Display the name of the clientr we are impersonating.
Console.WriteLine("Reading file: {0} as user {1}.", _
filename, pipeServer.GetImpersonationUserName())

pipeServer.RunAsClient(AddressOf fileReader.Start)

pipeServer.Disconnect()

sr.Close()
sw.Close()
Catch ex As Exception
Console.WriteLine("ERROR: {0}", ex.Message)
End Try
pipeServer.Close()
End Sub
End Class

Public Class ReadFileToStream
Private m_filename As String
Private m_stream As Stream

Public Sub New(ByVal stream1 As Stream, ByVal filename As String)
m_filename = filename
m_stream = stream1
End Sub

Public Sub Start()
Using sw As New StreamWriter(m_stream)
Dim contents As String = File.ReadAllText(m_filename)
sw.WriteLine(contents)
sw.Flush()
End Using
End Sub
End Class

Imports System
Imports System.IO
Imports System.IO.Pipes
Imports System.Security.Principal

Class PipeClient

Shared Sub Main(ByVal args As String())

Try
Dim pipeClient As New NamedPipeClientStream("localhost", _
"testpipe", PipeDirection.InOut, PipeOptions.None, _
TokenImpersonationLevel.Impersonation)
Dim sw As New StreamWriter(pipeClient)
Dim sr As New StreamReader(pipeClient)
sw.AutoFlush = True

pipeClient.Connect()

' Verify that this is the "true server"
'Dim serverID As String = sr.ReadLine()
If 1 = 1 Then

' The client security token is sent with the first write
sw.WriteLine("c:\textfile.txt")

' Print the file to the screen.
Dim buffer(32) As Char
Dim n As Integer

n = sr.Read(buffer, 0, buffer.Length)
While Not n = 0
Console.Write(buffer, 0, n)
End While
Else
Console.WriteLine("Server could not be verified.")
End If
sw.Close()
sr.Close()
pipeClient.Close()
Catch ex As Exception
Console.WriteLine("ERROR: {0}", ex.Message)
End Try
End Sub
End Class



Robust Programming
The client and server processes in this example are intended to run on the same computer, so the server name provided to the NamedPipeClientStream object is "localhost". If the client and server processes were on separate computers, "localhost" would be replaced with the network name of the computer that runs the server process.