Ví dụ về ống có tên


131

Làm cách nào để tôi viết một ứng dụng đơn giản - tối thiểu cần thiết để nó hoạt động - ứng dụng thử nghiệm minh họa cách sử dụng IPC / Named Faucet?

Ví dụ: làm thế nào một người sẽ viết một ứng dụng bảng điều khiển trong đó Chương trình 1 nói "Xin chào thế giới" cho Chương trình 2 và Chương trình 2 nhận được tin nhắn và trả lời "Roger That" cho Chương trình 1.

Câu trả lời:


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 Xin lỗi, nó ở .Net 4.5. Bạn có thể sử dụngThread.Sleep
LB

2
@Gusdor Tôi có thể đã sử dụng một số primiteves. Nhưng nó sẽ khó đọc hơn. Tôi nghĩ rằng nó là đủ để đưa ra một ý tưởng về cách sử dụng NamedPipes
LB

2
Nếu bạn gặp sự cố khi đường ống đóng lại sau một lần đọc, hãy kiểm tra câu trả lời này: stackoverflow.com/a/895656/941764
jgillich

11
Nếu bạn đang sử dụng .NET 4.5, bạn có thể thay thế Task.Factory.StartNewbằngTask.Run .
Rudey

2
Bạn có phải vứt bỏ reader/ writer? Nếu vậy, bạn chỉ vứt bỏ một trong số họ? Tôi chưa bao giờ thấy một ví dụ trong đó cả hai được gắn vào cùng một luồng.
JoshVarty

21

Đối với một người mới sử dụng IPC và Named Faucet, tôi thấy gói NuGet sau đây là một trợ giúp tuyệt vời.

GitHub: Gói ống được đặt tên cho .NET 4.0

Để sử dụng đầu tiên cài đặt gói:

PS> Install-Package NamedPipeWrapper

Sau đó, một máy chủ ví dụ (được sao chép từ liên kết):

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

Ví dụ khách hàng:

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

client.Start();

Điều tốt nhất đối với tôi là không giống như câu trả lời được chấp nhận ở đây, nó hỗ trợ nhiều khách hàng nói chuyện với một máy chủ.


5
Tôi sẽ không đề xuất gói NuGet này cho sản xuất. Tôi đã triển khai nó và nó có một số lỗi, chủ yếu là do không thể thực sự biết khi nào một tin nhắn đã được nhận đầy đủ ở đầu kia của ống dẫn (dẫn đến các kết nối bị hỏng hoặc kết nối quá sớm (kiểm tra mã trên github nếu bạn không tin tưởng tôi, "WaitForPipeDrain" sẽ không được gọi khi cần), cộng với việc bạn sẽ có nhiều khách hàng ngay cả khi chỉ có một người lắng nghe vì ... quá nhiều vấn đề). Thật đáng buồn vì nó thực sự dễ sử dụng. Tôi đã phải xây dựng lại một từ đầu với ít lựa chọn hơn.
Micaël Félix

Có một điểm tốt, thật không may là người bảo trì ban đầu đã không cập nhật dự án trong nhiều năm, may mắn thay, mặc dù một số nhánh đã tồn tại hầu hết trong số đó khắc phục các vấn đề bạn đã thảo luận.
Martin Laukkanen

2
@MartinLaukkanen: Xin chào, tôi dự định sử dụng NamedPipeWrapper, Bạn có biết ngã ba nào đang sửa lỗi này không? cảm ơn
Wh xuất sắc vào

17

Bạn thực sự có thể viết vào một ống có tên bằng cách sử dụng tên của nó, btw.

Mở trình vỏ lệnh với tư cách Quản trị viên để khắc phục lỗi "Truy cập bị từ chối" mặc định:

echo Hello > \\.\pipe\PipeName

3

Lõi dotnet FYI trên linux không hỗ trợ tênpipes, thay vào đó hãy thử tcplistener nếu bạn đang dùng linux

Mã này có một vòng khách hàng một byte.

  • Máy khách ghi byte
  • Máy chủ đọc byte
  • Máy chủ ghi byte
  • Máy khách đọc byte

Bảng điều khiển máy chủ 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);
            }
        }
    }
}

Bảng điều khiển ứng dụng khách 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 <-- 
            });
        }
    }
}

Sử dụng các đường ống được đặt tên như thế này cho 2 quy trình làm cho tôi trở lạiSystem Unauthorized Accesss Exception - path is denied
Bercovici Adrian

Không chắc chắn có thể chạy như quản trị viên?
patrick
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.