当前位置: 首页 > 知识库问答 >
问题:

一个命名管道能做我想做的事吗?

云开诚
2023-03-14

这是take II,前几周我发了帖子,我的问题被搁置,我调整了我的文本,但无法得到评论,系统关闭了原来的帖子。

服务器端:只读-服务器打开管道,然后定期检查是否有内容(即不在流末尾)并读取信息。此检查必须以轮询为基础,因为只有在轮询期间,才有有效的上下文来传递数据。。

客户端:仅写-打开管道、写入管道、关闭(Client.exe多次调用,生命周期短,下面的代码是测试代码),例如,其他一些脚本将“使用信息调用Client.exe”

>

  • 这个工作流可以在管道中处理吗?例如,只显示第一个客户端消息的客户端代码片段被服务器看到

    如果管道可以在编码后实现这一点,大多数示例都是针对具有类似生命周期的客户端服务器。

    代码片段

        for (int i = 0; i < 10; i++)
        {
            //Client - simulate exe starting and ending
            var client = new NamedPipeClientStream(".", "PipesOfPiece", PipeDirection.Out, PipeOptions.WriteThrough);
            client.Connect();
            StreamWriter writer = new StreamWriter(client);
    
            Console.WriteLine("Client about to send message");
            writer.WriteLine("Called from client i = {0}", i);
    
            writer.Close();
            client.Close();
    
            Thread.Sleep(5000);
        }
        // server snippet
            var server = new NamedPipeServerStream("PipesOfPiece", PipeDirection.In);
            server.WaitForConnection(); <= can this we optional with code below
            StreamReader reader = new StreamReader(server);
            html" target="_blank">while (true)
            {
                // simulate start of poll code
                if (server.IsConnected)
                {
                    if (!reader.EndOfStream)
                    {
                        var line = reader.ReadToEnd();
                        Console.WriteLine("Server: {0}", line);
                    }
                } // End of poll code
                Thread.Sleep(1000);
            }
          // server snippet
        var server = new NamedPipeServerStream("PipesOfPiece", PipeDirection.In);
            server.WaitForConnection(); <= can this we optional with code below
            StreamReader reader = new StreamReader(server);
            while (true)
            {
                // simulate start of poll code
                if (server.IsConnected)
                {
                    if (!reader.EndOfStream)
                    {
                        var line = reader.ReadToEnd();
                        Console.WriteLine("Server: {0}", line);
                    }
                } // End of poll code
                Thread.Sleep(1000);
            }
    

    所以我对我的管道生锈了,我希望一个管道可以打开,写入然后读取,并且waitforlink()是在你想要这个的情况下存在的,并且是可选的。我想这一切都取决于谁拥有管道,也就是说,如果服务器打开一个管道并等待某人为它编写,为什么它需要等待连接?(我希望服务器是所有者,所以当它结束时,管道就消失了)

  • 共有1个答案

    万明辉
    2023-03-14

    如果没有一个好的、最少的、完整的代码示例,能够可靠地再现您遇到的任何特定问题,就不可能提供关于如何解决该问题的具体建议。不过,我至少可以尝试回答您关于如何使用命名管道的一些问题,并提供一个代码示例来说明其中的一些概念。


    首先,一些规则和观察:

    • 管道实例只能用于一个连接。请注意,管道继承,流有一个非常特定的范例:打开一个,读到最后,然后就完成了流。有些流,如FileStream,是可查找的,但即使在那里,您也只能处理单个资源(即原始文件…您无法将FileStream重新连接到其他文件),而且网络流甚至不可查找
    • 在对管道执行I/O之前,必须先连接管道
    • 您可能有多个同名的管道实例(如果正确初始化它们…默认情况下,任何给定名称只能有一个管道)
    • 试图连接到命名管道的客户端将等待该管道存在。它不需要在客户端启动连接时存在
    • 只有一个客户端可以连接到管道的任何给定实例。服务器管道的任何给定实例在其整个生命周期内只能处理单个客户机(请参阅上面的第一点)

    那么,你的问题呢?

    这个工作流程可以在管道中处理吗?

    如果我正确理解工作流程,可以。但是你需要小心正确地执行它。

    据我所知,您希望您的服务器只尝试定期从客户端读取数据。同时,您希望客户机能够随时向管道写入数据。这是可以做到的,但并不简单。

    请注意,如上所述,您不能打开单个服务器管道,然后让多个客户端定期连接和断开与该管道的连接。第一个客户端连接后,管道将不再可用。这是一个流,第一个客户端的断开会导致流到达其末端。完成了。

    还要注意的是,虽然客户端可以尝试连接到一个尚不存在的管道,但它会等到可以连接时再连接。因此,如果希望客户端不必等到轮询间隔过期,则需要维护一个随时可以连接的服务器管道。

    但您已经说过,您将无法在任意时间点处理从服务器管道读取的数据,而只能在轮询间隔期间处理。

    因为管道本身并不支持这个特定场景,所以实现它的正确方法是将行为分成两个不同的组件。维护一个简单的管道服务器,打开管道,等待客户端连接,读取客户端发送的任何内容,关闭管道,然后重新开始。

    然后有一个中间类,它可以充当服务器I/O和任何最终接收数据的组件之间的中介。该中介将在收到数据后保留一份数据副本(管道代码将在收到数据后立即将其发送给中介,无论轮询间隔如何);然后,轮询组件将在其下一个轮询间隔(即,当您所说的“上下文”实际上可用于传递数据时)检索数据。

    我希望可以打开一个管道,先写后读,waitforconnect()可以用于需要的情况,并且是可选的

    不幸的是,你的希望与现实不符。管道可以是双向的;i、 e.“先写后读”。但是WaitForConnect()不是可选的。服务器在尝试从管道读取数据之前必须等待连接,对于该管道实例,它将只能从单个客户端接收数据。

    我希望服务器是所有者,所以当它结束时,管道消失了

    服务器进程是真正创建管道的进程。所以,从这个意义上说,它是所有者。是的,当服务器进程终止时,它创建的任何管道都将被销毁。


    下面是一个简单的代码示例,演示了多个并发服务器和客户端的使用。您可以使用示例顶部声明的常量来调整每个参数的数量。

    在运行它时,请注意,如果活动的客户端比服务器多,那么其他客户端只需等待服务器管道可用后再连接即可。一旦有人被发现,他们将连接并正常进行。如果服务器管道实例的数量至少与尝试连接的客户机的数量相同,那么所有客户机都将同时得到服务。

    // NOTE: as a sample program, contrary to normal and correct
    // programming practices error-handling has been omitted, and
    // non-awaited async methods have been declared as void.
    class Program
    {
        private const string _kserverName = "TestSO33093954NamedPipeClients";
        private const int _kmaxServerCount = 3;
        private const int _kmaxClientCount = 3;
    
        static void Main(string[] args)
        {
            StartServers(_kmaxServerCount);
            StartClients(_kmaxClientCount);
    
            Console.WriteLine("Clients are being started. Press return to exit program.");
            Console.ReadLine();
        }
    
        private static async void StartClients(int clientCount)
        {
            for (int i = 0; i < clientCount; i++)
            {
                RunClient(i);
                await Task.Delay(300);
            }
        }
    
        private static async void RunClient(int instance)
        {
            NamedPipeClientStream client = new NamedPipeClientStream(
                ".", _kserverName, PipeDirection.InOut, PipeOptions.Asynchronous);
    
            client.Connect();
    
            ReadClient(client);
    
            using (StreamWriter writer = new StreamWriter(client))
            {
                writer.AutoFlush = true;
    
                for (int i = 0; i < 5; i++)
                {
                    string text =
                        string.Format("Instance #{0}, iteration #{1}", instance, i);
    
                    Console.WriteLine("Client send: " + text);
                    await writer.WriteLineAsync(text);
                    await Task.Delay(1000);
                }
    
                client.WaitForPipeDrain();
            }
        }
    
        private static async void ReadClient(Stream stream)
        {
            using (TextReader reader = new StreamReader(stream))
            {
                string line;
    
                while ((line = await reader.ReadLineAsync()) != null)
                {
                    Console.WriteLine("Client recv: " + line);
                }
            }
        }
    
        private static void StartServers(int maxServerInstances)
        {
            for (int i = 0; i < maxServerInstances; i++)
            {
                RunServer(maxServerInstances);
            }
        }
    
        private static async void RunServer(int maxServerInstances)
        {
            while (true)
            {
                using (NamedPipeServerStream server = new NamedPipeServerStream(
                    _kserverName, PipeDirection.InOut, maxServerInstances,
                     PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
                {
                    await server.WaitForConnectionAsync();
    
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    Decoder decoder = Encoding.UTF8.GetDecoder();
    
                    while ((bytesRead =
                        await server.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        int cch = decoder.GetCharCount(buffer, 0, bytesRead);
                        char[] rgch = new char[cch];
    
                        decoder.GetChars(buffer, 0, bytesRead, rgch, 0);
                        Console.Write("Server recv: " + new string(rgch));
    
                        await server.WriteAsync(buffer, 0, bytesRead);
                    }
                }
            }
        }
    }
    
    static class PipeExtensions
    {
        // As I am not running with .NET 4.6 yet, I need this little helper extension
        // to wrap the APM-based asynchronous connection-waiting with the await-friendly
        // Task-based syntax. Anyone using .NET 4.6 will have this in the framework already
        public static Task WaitForConnectionAsync(this NamedPipeServerStream server)
        {
            return Task.Factory.FromAsync(
                server.BeginWaitForConnection, server.EndWaitForConnection, null);
        }
    }
    
     类似资料:
    • 我用‘固定’使‘导航’不动。然而,如果有一个“标题”,则有一个与“标题”区域一样多的边距。在向上移动了多少‘头部’区域后,我想把它固定在那个位置。我在用“反应”所以很难找到方法。我正在自学,所以我原来知道的不多,所以我来学习一些新的东西。 null null

    • 我想做一个跟https://geojson.io/一样的可交互的地球,而且还不卡,请问应该用什么方案实现?

    • 问题内容: 我试图为我在shell脚本编写过程中经常使用的路径设置“别名”。我尝试了一下,但是失败了: 我该如何运作? 但是,可行。 问题答案: 由于它是一个环境变量(别名在中具有不同的定义),因此您需要使用类似以下内容的值对其进行评估: 要么: 但是实际上,如果您只想轻松切换到该目录,则可以创建一个 真实的 别名(在诸如的启动文件之一中),这样我可以更容易地保存击键: 然后,您可以使用(不使用)

    • 想要做一个能够自适应的卡片布局,该怎么做? 就是能够根据里面方块的数量,去填满整个大方块,小方块的数量不确定。

    • 缘起 我记得自己很小的时候(大概3岁还是4岁),我爸喜欢用红白机玩坦克大战和魂斗罗。但是我妈不喜欢,她认为打游戏会影响休息,而且伤眼睛,还减少电视机的寿命。我印象里面他们为此吵过架,我妈赢了,还把游戏机摔坏了,我们就没得玩了。 直到再后来我快10岁,我爸以学电脑、练五笔打字为由,又弄回来一台小霸王学习机。放假的时候我们爷俩终于又可以一起通关魂斗罗了。但是平时我妈依然不让我玩,而且这次我爸也跟她站在

    • 我是流视频从服务器与ExoPlayer,我想显示特定秒的视频对话,所以我想听ExoPlayer的持续时间,并得到哪一秒是当前的第二次播放,如果它是我想要的时间比停止播放器和显示对话。由于视频是流式的,我无法获得第二个处理程序,因为视频可能停止的情况下,用户的互联网质量低,或者可能用户改变播放器搜索栏等。那么解决方案是什么呢?谢谢。