如何实现异步运行的可重用命名管道侦听器?

时间:2010-09-27 17:27:51

标签: .net asynchronous named-pipes reusability

我找不到一个很好的例子,说明如何创建一个异步运行的可重用命名管道侦听器。我可以成为一个可重复使用的听众:

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(虽然我无法弄清楚这意味着什么)。我想我只需要做一些类似于每次管道清理的事情,就像我列出的第一个代码示例一样,但我还没有完成工作。

2 个答案:

答案 0 :(得分:7)

我想我已经明白了:

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时立即关闭(显然在另一个线程中)。这似乎是我需要的。有人可以证实我没有做任何愚蠢的事吗?

答案 1 :(得分:2)

  

我也关注部分发送的消息

使用本机(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被定义为术语无论如何都要传输字节组。