Pipe
匿名管道和命名管道
管道分为匿名管道和命名管道,匿名管道只能在有共同祖先的(有亲缘关系)进程中使用,而命名管道可以在任意进程中使用。所以两个独立的进程如果想通过管道通信,只能通过命名管道,而不能通过匿名管道通信。
匿名管道 AnonymousPipeServerStream
- 匿名管道是未命名的单向管道,通常在父进程和子进程之间传输数据。
- 匿名管道始终是本地管道;它们不能通过网络使用。
- PipeDirection不支持值InOut,因为匿名管道定义为单向管道。
- 匿名管道不支持 PipeTransmissionMode.Message 读取模式。
-
匿名管道的客户端必须通过调用 GetClientHandleAsString 方法从服务器端提供的管道句柄创建。
//AnonymousPipeServerStream public class Program { static void Main(string[] args) { Process pipeClient = new Process(); pipeClient.StartInfo.FileName = “pipeClient.exe”;
using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable)) { pipeClient.StartInfo.Arguments = pipeServer.GetClientHandleAsString(); pipeClient.StartInfo.UseShellExecute = false; pipeClient.Start(); pipeServer.DisposeLocalCopyOfClientHandle(); try { using (StreamWriter sw = new StreamWriter(pipeServer)) { sw.AutoFlush = true; sw.WriteLine("SYNC"); pipeServer.WaitForPipeDrain(); Console.Write("[SERVER] Enter text: "); sw.WriteLine(Console.ReadLine()); } } catch (IOException e) { Console.WriteLine("[SERVER] Error: {0}", e.Message); } } pipeClient.WaitForExit(); pipeClient.Close(); Console.ReadKey(); } }
//AnonymousPipeClientStream public class Program { static void Main(string[] args) { if (args.Length > 0) { using (AnonymousPipeClientStream pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[0])) { using (StreamReader sr = new StreamReader(pipeClient)) { string temp; temp = sr.ReadLine(); Console.WriteLine(“[CLIENT] Echo: “ + sr.ReadLine()); } } } } }
Chrome查看命名管道
输入地址file://.//pipe//可以直接查看电脑中的命名管道。
使用PowerShell查看命名管道
[System.IO.Directory]::GetFiles("\\.\\pipe\\")
命名管道
System.IO.IOException: The user name or password is incorrect.
在win2003以后,操作系统就默认禁止了匿名访问命名管道,如果要实现远程管道访问,需要一个有效的身份进行验证。比如建立smb连接或者建立IPC连接等。如果直接访问匿名管道,会返回The user name or password is incorrect.异常。可以使用net use指令先建立IPC连接。
net use \\192.168.2.51\ipc$ "password" /user:"username"
Example
public static void RunNamedPipeServer()
{
using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut))
{
Console.WriteLine("Waiting for client connection...");
pipeServer.WaitForConnection();
Console.WriteLine($"Client connected. {pipeServer.GetImpersonationUserName()}");
try
{
using (StreamReader sr = new StreamReader(pipeServer))
using (StreamWriter sw = new StreamWriter(pipeServer))
{
sw.AutoFlush = true;
while (true)
{
Console.Write("Enter text: ");
sw.WriteLine(Console.ReadLine());
string response= sr.ReadLine();
if (string.IsNullOrEmpty(response))
{
Console.WriteLine("Client disconnected.");
break;
}
else
{
Console.WriteLine($"Response: {response}");
}
}
}
}
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
}
}
public static void RunNamedPipeClient()
{
using (var pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation))
{
Console.WriteLine("Connecting to server...");
pipeClient.Connect();
Console.WriteLine("Server connected.");
try
{
using (StreamReader sr = new StreamReader(pipeClient))
using (StreamWriter sw = new StreamWriter(pipeClient))
{
sw.AutoFlush = true;
while (true)
{
string input = sr.ReadLine();
if (string.IsNullOrEmpty(input))
{
Console.WriteLine("Server disconnected.");
break;
}
else
{
Console.WriteLine(input);
sw.WriteLine($"Client received: {input}");
}
}
}
}
catch (IOException e)
{
Console.WriteLine("ERROR: {0}", e.Message);
}
}
}
TokenImpersonationLevel
当使用TokenImpersonationLevel.Anonymous和TokenImpersonationLevel.None时,NamedPipeServerStream.GetImpersonationUserName()方法无法获取客户端的用户名信心,且会报异常。