C#中的多线程命名管道服务器

17

你好
我想使用 .NET 3.5 中新添加的 NamedPipeServerStream 进行命名管道通信。 我想编写一个多线程管道服务器。默认情况下是否处理,还是我需要编写代码来实现?我的管道服务器应该同时处理多个请求。

有解决方案或示例代码吗?


客户端向命名管道服务器发送的最大请求数是多少? - Ehsan
只要管道的两端都打开,客户端对命名管道进行读写的次数是没有限制的。 - Chris Dickson
3个回答

28

您可以通过反复创建NamedPipeServerStream并等待一个连接,然后为该实例的NamedPipeServerStream生成一个线程,从而编写多线程管道服务器。

根据下面链接的.NET MSDN文档,您只能拥有254个并发客户端。但是,对于Win32 API,您可以传递一个特殊值以获取基于系统资源的无限制。如下所述,MSDN文档似乎是错误的。

以下代码未经测试,请勿仅仅复制粘贴用于生产环境:

    public class PipeServer
    {
        bool running;
        Thread runningThread;
        EventWaitHandle terminateHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
        public string PipeName { get; set; }

        void ServerLoop()
        {
            while (running)
            {
                ProcessNextClient();
            }

            terminateHandle.Set();
        }

        public void Run()
        {
            running = true;
            runningThread = new Thread(ServerLoop);
            runningThread.Start();
        }

        public void Stop()
        {
            running = false;
            terminateHandle.WaitOne();
        }

        public virtual string ProcessRequest(string message)
        {
            return "";
        }

        public void ProcessClientThread(object o)
        {
            NamedPipeServerStream pipeStream = (NamedPipeServerStream)o;

            //TODO FOR YOU: Write code for handling pipe client here

            pipeStream.Close();
            pipeStream.Dispose();
        }

        public void ProcessNextClient()
        {
            try
            {
                NamedPipeServerStream pipeStream = new NamedPipeServerStream(PipeName, PipeDirection.InOut, 254);
                pipeStream.WaitForConnection();

                //Spawn a new thread for each request and continue waiting
                Thread t = new Thread(ProcessClientThread);
                t.Start(pipeStream);
            }
            catch (Exception e)
            {//If there are no more avail connections (254 is in use already) then just keep looping until one is avail
            }
        }

@Brian:你为什么说“你只能有254个并发客户端”?默认情况下,当调用Win32 CreateNamedPipe API时,NamedPipeServerStream指定PIPE_UNLIMITED_INSTANCES,并且Win32文档中说:“可以创建的管道实例数量仅受系统资源的可用性限制”。 - Chris Dickson
maxNumberOfServerInstances小于1或大于254时,会抛出ArgumentOutOfRangeException异常。http://msdn.microsoft.com/en-us/library/bb355105.aspx - Brian R. Bondy
2
@Brian:NamedPipeServerStream构造函数的文档有误。值“-1”对应于PIPE_UNLIMITED_INSTANCES,也是可接受的值。if (((maxNumberOfServerInstances < 1) || (maxNumberOfServerInstances > 0xfe)) && (maxNumberOfServerInstances != -1)) { throw new ArgumentOutOfRangeException("maxNumberOfServerInstances", SR.GetString("ArgumentOutOfRange_MaxNumServerInstances")); } - Chris Dickson
我在这里看到:http://msdn.microsoft.com/en-us/library/aa365150(v=vs.85).aspx 它提到基于系统资源的无限制,但我想知道.NET实现是否不同? - Brian R. Bondy
@Chris:我在我的答案中做了记录。 - Brian R. Bondy
显示剩余4条评论

23

每个NamedPipeServerStream实例都是Stream实现,包装着一个命名管道实例的句柄。您可以(以及多线程管道服务器会)为同一个命名管道拥有多个NamedPipeServerStream实例:每个实例都包装着针对不同客户端服务的命名管道实例的句柄。命名管道实例(即使是相同的管道)由操作系统分开,因此不需要任何显式编码来保持每个客户端与服务器之间的通信分开。

您需要显式编写的是服务器的线程模型。用于多线程化服务器的最简单方法在这个SO答案中解释了,其中包括一个伪代码模板。如果需要支持大量并发调用者,更可扩展的实现将使用线程池和异步方法,而不是为每个连接创建专用线程。


那么我们需要为每个客户端创建新的服务器流吗? - Ehsan

0

NamedPipeServerStream 是一种点对点的连接方式。您必须自己同步调用 - 例如将调用写入队列,然后您的服务器从同步队列中读取并进行调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接