ตัวอย่างของเนมไปป์


131

ฉันจะเขียนขั้นต่ำง่าย ๆ ที่จำเป็นสำหรับการทำงาน - แอปพลิเคชันทดสอบที่แสดงวิธีใช้ IPC / Named Pipes ได้อย่างไร

ตัวอย่างเช่นเราจะเขียนแอปพลิเคชั่นคอนโซลโดยที่โปรแกรม 1 บอกว่า "Hello World" ไปที่ Program 2 และ Program 2 ได้รับข้อความและตอบกลับ "Roger That" ไปที่ Program 1 ได้อย่างไร

คำตอบ:


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 ฉันสามารถใช้ sync-primiteves ได้บ้าง แต่มันยากที่จะอ่าน ฉันคิดว่ามันเพียงพอที่จะให้แนวคิดเกี่ยวกับวิธีใช้ NamedPipes
LB

2
หากคุณมีปัญหาว่าไปป์ปิดหลังจากอ่านหนึ่งตรวจสอบคำตอบนี้: stackoverflow.com/a/895656/941764
jgillich

11
หากคุณกำลังใช้ .NET 4.5 คุณสามารถแทนที่Task.Factory.StartNewTask.Runด้วย
Rudey

2
คุณต้องกำจัดreader/ writerหรือ ถ้าเป็นเช่นนั้นคุณจะกำจัดหนึ่งในนั้นหรือไม่ ฉันไม่เคยเห็นตัวอย่างที่ทั้งสองแนบกับสตรีมเดียวกัน
JoshVarty

21

สำหรับคนที่ยังใหม่กับ IPC และ Named Pipes ฉันพบแพ็คเกจ NuGet ต่อไปนี้เพื่อเป็นความช่วยเหลือที่ดี

GitHub: ตั้งชื่อ Pipe Wrapper สำหรับ. 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" จะไม่ถูกเรียกเมื่อมันควร) รวมทั้งคุณจะมีลูกค้าหลายคนแม้เพียงคนเดียวที่ฟังเพราะ ... ปัญหามากเกินไป) มันเศร้าเพราะมันใช้งานง่ายมาก ฉันต้องสร้างใหม่ตั้งแต่ต้นโดยมีตัวเลือกน้อยลง
MicaëlFélix

ใช่เป็นข้อดี แต่น่าเสียดายที่ผู้ดูแลดั้งเดิมไม่ได้อัปเดตโครงการเป็นเวลาหลายปีโชคดีที่มีส้อมจำนวนมากที่แก้ไขปัญหาที่คุณกล่าวถึง
Martin Laukkanen

2
@MartinLaukkanen: สวัสดีฉันวางแผนที่จะใช้ NamedPipeWrapper คุณรู้หรือไม่ว่า fork ใดที่แก้ไขข้อผิดพลาดนี้ ขอบคุณ
Whiletrue

17

คุณสามารถเขียนไปยังไปป์ที่มีชื่อโดยใช้ชื่อของมันคือ btw

เปิดเชลล์คำสั่งในฐานะผู้ดูแลเพื่อหลีกเลี่ยงข้อผิดพลาด "การเข้าถึงถูกปฏิเสธ" เริ่มต้น:

echo Hello > \\.\pipe\PipeName

3

FYI dotnet core บน linux ไม่รองรับการตั้งชื่อให้ลองใช้ tcplistener แทนหากคุณอยู่ใน linux

รหัสนี้มีลูกค้าไปกลับเป็นไบต์

  • ไคลเอนต์เขียนไบต์
  • เซิร์ฟเวอร์อ่านไบต์
  • เซิร์ฟเวอร์เขียนไบต์
  • ไคลเอนต์อ่านไบต์

แอพเซิร์ฟเวอร์ 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);
            }
        }
    }
}

แอพคอนโซลของ DotNet Core 2.0

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 Unauthorized Accesss Exception - path is denied
Bercovici Adrian

ไม่แน่ใจว่าอาจทำงานเป็นผู้ดูแลระบบได้หรือไม่
แพทริค
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.