首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C#:异步NamedPipeServerStream管道正在关闭异常

C#:异步NamedPipeServerStream管道正在关闭异常
EN

Stack Overflow用户
提问于 2012-07-12 11:08:12
回答 2查看 25.2K关注 0票数 5

我先前就同一主题提出的问题:C#: Asynchronous NamedPipeServerStream understanding,现在我有了下一个问题:

代码语言:javascript
运行
复制
private void StartListeningPipes()
{
    try
    {
        isPipeWorking = true;
                namedPipeServerStream = new NamedPipeServerStream(PIPENAME, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, BUFFERSIZE, BUFFERSIZE);
                Console.Write("Waiting for client connection...");
                while(isPipeWorking)
                {
            IAsyncResult asyncResult = namedPipeServerStream.BeginWaitForConnection(this.WaitForConnectionAsyncCallback, null);
                        Thread.Sleep(3*1000);
                }
        }
        //// Catch the IOException that is raised if the pipe is broken or disconnected.
        catch (IOException e)
        {
        Console.WriteLine("IOException: {0}. Restart pipe server...", e.Message);
                StopListeningPipes();
                StartListeningPipes();
        }
        //// Catch ObjectDisposedException if server was stopped. Then do nothing.
        catch (ObjectDisposedException)
        {
        }
}

private void WaitForConnectionAsyncCallback(IAsyncResult result)
{
    try
    {
        namedPipeServerStream.EndWaitForConnection(result);
        Console.WriteLine("Client connected.");
        namedPipeServerStream.WaitForPipeDrain();
                byte[] buff = new byte[BUFFERSIZE];
                namedPipeServerStream.Read(buff, 0, BUFFERSIZE);
                string recStr = TrimNulls(buff);
                Array.Clear(buff, 0, buff.Length);
                Console.WriteLine();
                Console.WriteLine("'"+recStr+"'");
    }
    catch (Exception e)
    {
        Console.WriteLine("Error: " + e.Message);            
        }
}

但我得到了

The pipe is being closed Exception每次我收到客户端的消息

为什么?

我的当事人:

代码语言:javascript
运行
复制
 using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(General.PIPENAME))
{
    try
        {
        byte[] bytes = General.Iso88591Encoding.GetBytes(sendingMessage);
                pipeStream.Write(bytes, 0, bytes.Length);
                pipeStream.Flush();
                pipeStream.WaitForPipeDrain();
        }
        catch (TimeoutException)
        {
        Console.WriteLine("Timeout error!");
        }
    catch (Exception e)
        {
        Console.WriteLine(string.Format("Error! ", e.Message));
        }
}

目前的最终代码是:

代码语言:javascript
运行
复制
/// <summary>
        /// Create new NamedPipeServerStream for listening to pipe client connection
        /// </summary>
        private void ListenForPipeClients()
        {
            if (!this.isListeningToClients)
                return;

            try
            {
                PipeSecurity ps = new PipeSecurity();
                PipeAccessRule par = new PipeAccessRule("Everyone", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
                ps.AddAccessRule(par);
                pipeClientConnection = new NamedPipeServerStream(General.PIPENAME, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, General.BUFFERSIZE, General.BUFFERSIZE, ps);
                Console.Write("Waiting for client connection...");
                /*namedPipeServerStream.WaitForConnection();
                OnPipeConnected(namedPipeServerStream);*/
                IAsyncResult result = pipeClientConnection.BeginWaitForConnection(OnPipeConnected, pipeClientConnection);
            }
            catch (ObjectDisposedException)
            {
                //// Catch ObjectDisposedException if server was stopped. Then do nothing.
            }
            catch (Exception e)
            {
                Console.WriteLine("Error occures: {0}. Restart pipe server...", e.Message);
                this.logger.Add(LogLevel.Warning, string.Format("Error occures: {0}. Restart pipe server...", e.Message));
                ListenForPipeClients();
            }
        }

        /// <summary>
        /// Async callback on client connected action
        /// </summary>
        /// <param name="asyncResult">Async result</param>
        private void OnPipeConnected(IAsyncResult asyncResult)
        {
            using (var conn = (NamedPipeServerStream)asyncResult.AsyncState)
            {
                try
                {
                    conn.EndWaitForConnection(asyncResult);
                    Console.WriteLine("Client connected.");
                    PipeClientConnection clientConnection = new PipeClientConnection(conn, notifierSenderCache, defaultStorageTime);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    this.logger.Add(LogLevel.Warning, e.Message);
                }
            }

            ListenForPipeClients();
        }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-12 11:25:24

似乎每个客户端都需要一个单独的NamedPipeServerStream。(请注意,发现这个问题的人不是我,请看其他答案。)我可以想象,工作服务器端的外观如下(草稿代码):

代码语言:javascript
运行
复制
while(this.isServerRunning)
{
     var pipeClientConnection = new NamedPipeServerStream(...);

     try
     {
         pipeClientConnection.WaitForConnection();
     }
     catch(...)
     {
         ...
         continue;
     }

     ThreadPool.QueueUserWorkItem(state =>
          {
               // we need a separate variable here, so as not to make the lambda capture the pipeClientConnection variable, which is not recommended in multi-threaded scenarios
               using(var pipeClientConn = (NamedPipeServerStream)state)
               {
                    // do stuff
                    ...
               }
          }, pipeClientConnection);
}

作为附带说明,正如在对您的问题的评论中所指出的,通过循环调用BeginWaitForConnection,每3秒启动一个新的异步调用是在浪费内存(这不会浪费内存的唯一情况是,新连接的间隔小于3秒,但我怀疑您是否能够确定这一点)。您可以看到,基本上每3秒就启动一个新的异步调用,而不管最后一个调用是否仍在等待或已经完成。此外,它--再一次--没有考虑到每个客户端都需要一个单独的NamedPipeServerStream

要解决这个问题,您需要消除循环,并使用回调方法“链接”BeginWaitForConnection调用。在使用.NET时,您将经常在异步I/O中看到类似的模式。

代码语言:javascript
运行
复制
private void StartListeningPipes()
{
    if(!this.isServerRunning)
    {
        return;
    }

    var pipeClientConnection = new NamedPipeServerStream(...);

    try
    {
        pipeClientConnection.BeginWaitForConnection(asyncResult =>
            {
                // note that the body of the lambda is not part of the outer try... catch block!
                using(var conn = (NamedPipeServerStream)asyncResult.AsyncState)
                {
                    try
                    {
                        conn.EndWaitForConnection(asyncResult);
                    }
                    catch(...)
                    {
                        ...
                    }

                    // we have a connection established, time to wait for new ones while this thread does its business with the client
                    // this may look like a recursive call, but it is not: remember, we're in a lambda expression
                    // if this bothers you, just export the lambda into a named private method, like you did in your question
                    StartListeningPipes();

                    // do business with the client
                    conn.WaitForPipeDrain();
                    ...
                }
            }, pipeClientConnection);
    }
    catch(...)
    {
        ...
    }
}

控制流将如下所示:

  • 主线程StartListeningPipes():创建NamedPipeServerStream,启动BeginWaitForConnection()
  • 线程池线程1客户机#1连接,BeginWaitForConnection()回调: EndWaitForConnection()然后是StartListeningPipes()
  • 线程池线程1 StartListeningPipes():创建新的NamedPipeServerStream,BeginWaitForConnection()调用
  • 线程池线程1返回到BeginWaitForConnection()回调:开始处理与连接的客户端的业务(#1)
  • 线程池线程2客户机#2连接,BeginWaitForConnection()回调:.
  • ..。

我认为这比使用阻塞I/O要困难得多--事实上,我不太确定我是否正确,如果您看到任何错误,请指出它--而且它也更令人困惑。

要在两个示例中暂停服务器,显然需要将this.isServerRunning标志设置为false

票数 9
EN

Stack Overflow用户

发布于 2012-07-12 11:23:25

好的。吓死我了。每个客户端应该有一个NamedPipeServerStream。因此,如果异步操作已经完成,则必须重新创建NamedPipeServerStream。谢谢这个Multithreaded NamePipeServer in C#

应:

代码语言:javascript
运行
复制
while(isPipeWorking)
            {
                IAsyncResult asyncResult = namedPipeServerStream.BeginWaitForConnection(this.WaitForConnectionAsyncCallback, null);
                Thread.Sleep(3*1000);
                if (asyncResult.IsCompleted)
                {
                    RestartPipeServer();
                    break;
                }
            }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11450522

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档