C# 命名管道的示例

C# 命名管道的示例,c#,ipc,named-pipes,C#,Ipc,Named Pipes,我如何编写一个简单的测试应用程序,演示如何使用IPC/命名管道 例如,如何编写一个控制台应用程序,其中程序1向程序2说“Hello World”,程序2接收消息并向程序1回复“Roger That”。对于刚接触IPC并命名为Pipes的人,我发现下面的NuGet包非常有帮助 using System; using System.IO; using System.IO.Pipes; using System.Linq; using System.Text; using System.Threadi

我如何编写一个简单的测试应用程序,演示如何使用IPC/命名管道


例如,如何编写一个控制台应用程序,其中程序1向程序2说“Hello World”,程序2接收消息并向程序1回复“Roger That”。

对于刚接触IPC并命名为Pipes的人,我发现下面的NuGet包非常有帮助

using System;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            StartServer();
            Task.Delay(1000).Wait();


            //Client
            var client = new NamedPipeClientStream("PipesOfPiece");
            client.Connect();
            StreamReader reader = new StreamReader(client);
            StreamWriter writer = new StreamWriter(client);

            while (true)
            {
                string input = Console.ReadLine();
                if (String.IsNullOrEmpty(input)) break;
                writer.WriteLine(input);
                writer.Flush();
                Console.WriteLine(reader.ReadLine());
            }
        }

        static void StartServer()
        {
            Task.Factory.StartNew(() =>
            {
                var server = new NamedPipeServerStream("PipesOfPiece");
                server.WaitForConnection();
                StreamReader reader = new StreamReader(server);
                StreamWriter writer = new StreamWriter(server);
                while (true)
                {
                    var line = reader.ReadLine();
                    writer.WriteLine(String.Join("", line.Reverse()));
                    writer.Flush();
                }
            });
        }
    }
}

要使用“先安装”软件包,请执行以下操作:

PS> Install-Package NamedPipeWrapper
然后是一个示例服务器(从链接复制):

var server=newnamedpipeserver(“MyServerPipe”);
server.ClientConnected+=委托(NamedPipeConnection conn)
{
WriteLine(“客户端{0}现在已连接!”,conn.Id);
conn.PushMessage(新SomeClass{Text:“欢迎!”});
};
server.ClientMessage+=委托(NamedPipeConnection conn,SomeClass消息)
{
WriteLine(“客户端{0}说:{1}”,conn.Id,message.Text);
};
server.Start();
示例客户端:

var client = new NamedPipeClient<SomeClass>("MyServerPipe");
client.ServerMessage += delegate(NamedPipeConnection<SomeClass> conn, SomeClass message)
    {
        Console.WriteLine("Server says: {0}", message.Text);
    };

client.Start();
var client=newnamedpipeclient(“MyServerPipe”);
client.ServerMessage+=委托(NamedPipeConnection conn,SomeClass消息)
{
WriteLine(“服务器说:{0}”,message.Text);
};
client.Start();

对我来说,它最好的一点是,与这里公认的答案不同,它支持多个客户机与单个服务器对话

您实际上可以使用命名管道的名称写入命名管道,顺便说一句

以管理员身份打开命令shell,以绕过默认的“访问被拒绝”错误:

Linux dotnet core不支持命名管道

如果部署到Linux,请尝试TcpListener

此命名管道客户端/服务器代码将一个字节往返于服务器

  • 客户端写入字节
  • 服务器读取字节
  • 服务器写入字节
  • 客户端读取字节
DotNet Core 2.0服务器控制台AP

using System;
using System.IO.Pipes;
using System.Threading.Tasks;

namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            var server = new NamedPipeServerStream("A", PipeDirection.InOut);
            server.WaitForConnection();

            for (int i =0; i < 10000; i++)
            {
                var b = new byte[1];
                server.Read(b, 0, 1); 
                Console.WriteLine("Read Byte:" + b[0]);
                server.Write(b, 0, 1);
            }
        }
    }
}
using System;
using System.IO.Pipes;
using System.Threading.Tasks;

namespace Client
{
    class Program
    {
        public static int threadcounter = 1;
        public static NamedPipeClientStream client;

        static void Main(string[] args)
        {
            client = new NamedPipeClientStream(".", "A", PipeDirection.InOut, PipeOptions.Asynchronous);
            client.Connect();

            var t1 = new System.Threading.Thread(StartSend);
            var t2 = new System.Threading.Thread(StartSend);

            t1.Start();
            t2.Start(); 
        }

        public static void StartSend()
        {
            int thisThread = threadcounter;
            threadcounter++;

            StartReadingAsync(client);

            for (int i = 0; i < 10000; i++)
            {
                var buf = new byte[1];
                buf[0] = (byte)i;
                client.WriteAsync(buf, 0, 1);

                Console.WriteLine($@"Thread{thisThread} Wrote: {buf[0]}");
            }
        }

        public static async Task StartReadingAsync(NamedPipeClientStream pipe)
        {
            var bufferLength = 1; 
            byte[] pBuffer = new byte[bufferLength];

            await pipe.ReadAsync(pBuffer, 0, bufferLength).ContinueWith(async c =>
            {
                Console.WriteLine($@"read data {pBuffer[0]}");
                await StartReadingAsync(pipe); // read the next data <-- 
            });
        }
    }
}
使用系统;
使用System.IO.Pipes;
使用System.Threading.Tasks;
命名空间服务器
{
班级计划
{
静态void Main(字符串[]参数)
{
var server=newnamedpipeserverstream(“A”,PipeDirection.InOut);
WaitForConnection();
对于(int i=0;i<10000;i++)
{
var b=新字节[1];
读取(b,0,1);
Console.WriteLine(“读取字节:+b[0]);
server.Write(b,0,1);
}
}
}
}
DotNet Core 2.0客户端控制台

using System;
using System.IO.Pipes;
using System.Threading.Tasks;

namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            var server = new NamedPipeServerStream("A", PipeDirection.InOut);
            server.WaitForConnection();

            for (int i =0; i < 10000; i++)
            {
                var b = new byte[1];
                server.Read(b, 0, 1); 
                Console.WriteLine("Read Byte:" + b[0]);
                server.Write(b, 0, 1);
            }
        }
    }
}
using System;
using System.IO.Pipes;
using System.Threading.Tasks;

namespace Client
{
    class Program
    {
        public static int threadcounter = 1;
        public static NamedPipeClientStream client;

        static void Main(string[] args)
        {
            client = new NamedPipeClientStream(".", "A", PipeDirection.InOut, PipeOptions.Asynchronous);
            client.Connect();

            var t1 = new System.Threading.Thread(StartSend);
            var t2 = new System.Threading.Thread(StartSend);

            t1.Start();
            t2.Start(); 
        }

        public static void StartSend()
        {
            int thisThread = threadcounter;
            threadcounter++;

            StartReadingAsync(client);

            for (int i = 0; i < 10000; i++)
            {
                var buf = new byte[1];
                buf[0] = (byte)i;
                client.WriteAsync(buf, 0, 1);

                Console.WriteLine($@"Thread{thisThread} Wrote: {buf[0]}");
            }
        }

        public static async Task StartReadingAsync(NamedPipeClientStream pipe)
        {
            var bufferLength = 1; 
            byte[] pBuffer = new byte[bufferLength];

            await pipe.ReadAsync(pBuffer, 0, bufferLength).ContinueWith(async c =>
            {
                Console.WriteLine($@"read data {pBuffer[0]}");
                await StartReadingAsync(pipe); // read the next data <-- 
            });
        }
    }
}
使用系统;
使用System.IO.Pipes;
使用System.Threading.Tasks;
命名空间客户端
{
班级计划
{
公共静态int-threadcounter=1;
公共静态NamedPipeClientStream客户端;
静态void Main(字符串[]参数)
{
client=newnamedpipeclientstream(“.”,“A”,PipeDirection.InOut,PipeOptions.Asynchronous);
client.Connect();
var t1=新系统.Threading.Thread(StartSend);
var t2=新系统.Threading.Thread(StartSend);
t1.Start();
t2.Start();
}
公共静态void StartSend()
{
int thisThread=线程计数器;
threadcounter++;
启动同步(客户端);
对于(int i=0;i<10000;i++)
{
var buf=新字节[1];
buf[0]=(字节)i;
client.WriteAsync(buf,0,1);
WriteLine($@“Thread{thisThread}编写:{buf[0]}”);
}
}
公共静态异步任务StartReadingAsync(NamedPipeClientStream管道)
{
变量缓冲长度=1;
字节[]pBuffer=新字节[bufferLength];
wait pipe.ReadAsync(pBuffer,0,bufferLength).ContinueWith(async=>
{
WriteLine($@“读取数据{pBuffer[0]}”);

等待开始同步(管道);//阅读下一个数据@JordanTrainor抱歉,它在.Net 4.5中。你可以使用
线程。睡眠
@Gusdor我本可以使用一些sync primiteves。但是它会更难阅读。我认为这足以让你了解如何使用namedpipes如果你在一次阅读后发现管道关闭的问题,请检查以下答案:如果你使用的是.Net4.5,你可以。你必须处理
读卡器
/
写卡器
?如果是的话,你只处理其中一个吗?我从来没有见过一个例子,其中两个都连接到同一个流。我不推荐这个NuGet包用于生产。我已经实现了它,它有一些bug,主要是因为无法真正知道消息何时出现ge在管道的另一端已被完全接收(导致连接中断,或连接过早结束(如果您不信任我,请检查github上的代码,“WaitForPipeDrain”在应该调用的时候不会被调用),此外,即使只有一个客户端在侦听,您也会有多个客户端,因为…问题太多)。很遗憾,因为它真的很容易使用。我不得不用更少的选项从头开始重建一个。是的,很好的一点,不幸的是,最初的维护人员已经多年没有更新项目了,幸运的是,尽管存在许多分叉,其中大多数修复了您讨论的问题。@MartinLaukkanen:您好,我计划使用NamedPipeWrapper,您知道吗哪个叉子在修复这个错误?thanks@MartinLaukkanen我们可以用fork来修复上面提到的bug吗?我不记得我具体使用了哪一个,但我建议查看fork网络图上的提交,以确定哪一个修复了您关心的问题:对2个进程使用命名管道会使我<代码>系统未经授权访问异常-路径被拒绝
不确定是否可以作为管理员运行?