匿名管道和命名管道

管道分为匿名管道和命名管道,匿名管道只能在有共同祖先的(有亲缘关系)进程中使用,而命名管道可以在任意进程中使用。所以两个独立的进程如果想通过管道通信,只能通过命名管道,而不能通过匿名管道通信。

匿名管道 AnonymousPipeServerStream

  1. 匿名管道是未命名的单向管道,通常在父进程和子进程之间传输数据。
  2. 匿名管道始终是本地管道;它们不能通过网络使用。
  3. PipeDirection不支持值InOut,因为匿名管道定义为单向管道。
  4. 匿名管道不支持 PipeTransmissionMode.Message 读取模式。
  5. 匿名管道的客户端必须通过调用 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()方法无法获取客户端的用户名信心,且会报异常。