【问题标题】:How do you implement a reusable named pipe listener that runs asynchronously?如何实现异步运行的可重用命名管道侦听器?
【发布时间】:2011-04-17 21:39:45
【问题描述】:

我找不到一个很好的例子来说明如何创建一个异步运行的可重用命名管道侦听器。我可以制作一个可重用的监听器:

NamedPipeServerStream pipeServer = new NamedPipeServerStream("MyPipe", PipeDirection.InOut);

    while (true)
    {
            pipeServer.WaitForConnection();

            StreamReader reader = new StreamReader(pipeServer);

            MessageBox.Show(reader.ReadLine());

            pipeServer.Disconnect();
    }

我可以做一个异步监听器:

NamedPipeServerStream pipeServer = new NamedPipeServerStream("MyPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

    pipeServer.BeginWaitForConnection((a) =>
    {
        pipeServer.EndWaitForConnection(a);

        StreamReader reader = new StreamReader(pipeServer);
        MessageBox.Show(reader.ReadLine());

    }, null);

但我似乎无法同时进行。有一个很好的例子吗?我还担心部分发送的消息,因为我认为这是这样的异步通信的问题。

更新: 我离得更近了一点。

pipeServer = new NamedPipeServerStream("MyPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

pipeServer.BeginWaitForConnection((a) =>
{
    pipeServer.EndWaitForConnection(a);

    StreamReader reader = new StreamReader(pipeServer);

    while (running)
    {
        String text = reader.ReadLine();

        if (String.IsNullOrEmpty(text) == false)
        {
            MessageBox.Show(text);
        }
    }

    MessageBox.Show("Done!");

}, null);

这将成功读取一次,并将继续循环,ReadLine 在初始成功读取后返回一个空的空字符串。所以它显然没有阻塞,并且正在尝试再次阅读。问题是如果我第二次发送相同的消息,它不会被接收,并且我的管道编写器说它正在接收错误 2316(尽管我无法弄清楚这意味着什么)。我想我只需要做类似的事情,每次清理管道,就像我列出的第一个代码示例一样,但我还没有让它工作。

【问题讨论】:

  • 系统(即 Win32 API)错误代码在这里:msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx 但是没有错误 2316... 你确定这是错误代码吗?您能否提供异常的完整详细信息(包括类型和消息?
  • 对不起,我直到现在才看到这个,我不再产生错误。这是在作者端产生它的代码: if (pipe == INVALID_HANDLE_VALUE) { cout
  • 原来是错误 231。6 是从别的东西输出的。

标签: .net asynchronous named-pipes reusability


【解决方案1】:

我也担心部分发送的消息

使用本机 (Win32) API 的 NamedPipes 不是问题,所以我非常怀疑它们在使用 .NET 时是否存在问题。但是在native documentation 中确实说:

数据作为消息流写入管道。管道将每个写入操作期间写入的字节视为一个消息单元。 GetLastError 函数在未完全读取消息时返回 ERROR_MORE_DATA。此模式可与 PIPE_READMODE_MESSAGE 或 PIPE_READMODE_BYTE 一起使用。

(注意ERROR_MORE_DATA 是 234。)

文档还说,对于标志 FILE_FLAG_OVERLAPPED(本机等效于 PipeOptions.Asynchronous):

已启用重叠模式。如果启用此模式,则执行读取、写入和连接操作可能需要很长时间才能完成的函数可以立即返回。

我一直使用异步命名管道的异步 IO 操作(即Stream.BeginRead),但这确实意味着失去TextReader 的功能,但是PipeTransmissionMode.Message 是根据传输字节组定义的.

【讨论】:

  • 很高兴知道这一点。我对 BeginRead 非常开放,但我认为我没有正确使用它。我建立了连接,但读取的字节数(从 EndRead 返回)始终为 0。你知道一个很好的例子吗?最好是可重复使用的?
【解决方案2】:

我想我明白了:

pipeServer = new NamedPipeServerStream("MyPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

Boolean connectedOrWaiting = false;

Byte[] buffer = new Byte[65535];

while (running)
{
    if (!connectedOrWaiting)
    {                   
        pipeServer.BeginWaitForConnection((a) => { pipeServer.EndWaitForConnection(a); }, null);

        connectedOrWaiting = true;
    }

    if (pipeServer.IsConnected)
    {
        Int32 count = pipeServer.Read(buffer, 0, 65535);

        if (count > 0)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String message = encoding.GetString(buffer, 0, count);

            MessageBox.Show(message);
        }

        pipeServer.Disconnect();

        connectedOrWaiting = false;
    }
}

这将接受多条消息,并在运行设置为 false 时立即关闭(显然在另一个线程中)。这似乎是我需要的。有人可以验证我没有做傻事吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多