名前付きパイプの例


131

IPC /名前付きパイプの使用方法を示す、シンプルな-動作するために最低限必要な最小限の-テストアプリケーションをどのように記述しますか?

たとえば、プログラム1がプログラム2に「Hello World」と言い、プログラム2がメッセージを受信して​​プログラム1に「Roger That」と返信するコンソールアプリケーションを作成するにはどうすればよいでしょうか。

回答:


166
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();
                }
            });
        }
    }
}

1
@JordanTrainor申し訳ありませんが、それは.Net 4.5です。使用できますThread.Sleep
LB

2
@Gusdor私はいくつかの同期プリミティブを使用できたでしょう。しかし、それは読みにくくなります。NamedPipesの使用方法についてのアイデアを提供するだけで十分だと思います
LB

2
1回の読み取り後にパイプが閉じるという問題がある場合は、この回答を確認してください:stackoverflow.com/a/895656/941764
jgillich

11
あなたは.NET 4.5を使用している場合は、できる置き換えるTask.Factory.StartNewTask.Run
Rudey 2015年

2
reader/ を処分する必要がありwriterますか?もしそうなら、あなたはそれらのうちの1つだけを処分しますか?両方が同じストリームに接続されている例を見たことがありません。
JoshVarty 2015

21

IPCと名前付きパイプを初めて使用する人にとって、次のNuGetパッケージが非常に役立つことがわかりました。

GitHub:.NET 4.0用の名前付きパイプラッパー

最初に使用するには、パッケージをインストールします。

PS> Install-Package NamedPipeWrapper

次に、サンプルサーバー(リンクからコピー):

var server = new NamedPipeServer<SomeClass>("MyServerPipe");
server.ClientConnected += delegate(NamedPipeConnection<SomeClass> conn)
    {
        Console.WriteLine("Client {0} is now connected!", conn.Id);
        conn.PushMessage(new SomeClass { Text: "Welcome!" });
    };

server.ClientMessage += delegate(NamedPipeConnection<SomeClass> conn, SomeClass message)
    {
        Console.WriteLine("Client {0} says: {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();

私にとっての最も良い点は、ここで受け入れられている回答とは異なり、単一のサーバーと通信する複数のクライアントをサポートすることです。


5
このNuGetパッケージを本番環境で使用することはお勧めしません。私はそれを実装しましたが、主にメッセージがパイプのもう一方の端で完全に受信されたときに本当に知ることができないためにいくつかのバグがあります(接続が切断されるか、接続がすぐに終了しません(コードを確認してください) githubが信頼できない場合は、「WaitForPipeDrain」が呼び出されないはずです)。さらに、1つだけがリッスンしている場合でも複数のクライアントが存在します...問題が多すぎるため)。本当に使いやすかったので悲しいです。オプションを減らして、ゼロから再構築する必要がありました。
–MicaëlFélix2016

はい、良い点です。残念ながら、最初のメンテナは何年もの間プロジェクトを更新していませんでしたが、幸いにも多くのフォークが存在していて、あなたが議論した問題を修正しています。
Martin Laukkanen、2016年

2
@MartinLaukkanen:こんにちは、NamedPipeWrapperを使用する予定です。このバグを修正しているのはどのフォークですか。感謝
Whiletrue

17

名前btwを使用して、名前付きパイプに実際に書き込むことができます。

管理者としてコマンドシェルを開き、デフォルトの「アクセスが拒否されました」エラーを回避します。

echo Hello > \\.\pipe\PipeName

3

LinuxのFYI dotnetコアはnamedpipesをサポートしていません。Linuxを使用している場合は、代わりにtcplistenerを試してください。

このコードは、1バイトのクライアントラウンドトリップを備えています。

  • クライアントがバイトを書き込む
  • サーバーがバイトを読み取る
  • サーバーがバイトを書き込む
  • クライアントがバイトを読み取る

DotNet Core 2.0 Server ConsoleApp

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);
            }
        }
    }
}

DotNet Core 2.0クライアントConsoleApp

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 <-- 
            });
        }
    }
}

ちょうど2つのプロセスのためにこのような名前付きパイプを使用すると、私をレンダリングするSystem Unauthorized Accesss Exception - path is denied
Bercoviciエイドリアン

おそらく管理者として実行されますか?
パトリック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.