具有多个客户端的命名管道服务器(C#)

3

我有一个用C#编写的命名管道服务器。实现的要点如下:

最初的回答:

    void BeginWaitForNextConnection()
    {
        var pipe = new NamedPipeServerStream(
            PipeName,
            PipeDirection.InOut,
            NamedPipeServerStream.MaxAllowedServerInstances,
            PipeTransmissionMode.Byte,
            PipeOptions.Asynchronous,
            0, // default in buffer size
            0, // default out buffer size
            CreateAllAccessPipeSecurity());

        pipe.BeginWaitForConnection(ClientRequestHandler, pipe);
    }

    void ClientRequestHandler(IAsyncResult ar)
    {
        // Clean up the async call state.
        NamedPipeServerStream pipe = (NamedPipeServerStream)ar.AsyncState;

        pipe.EndWaitForConnection(ar);

        // If we've been asked to shut down, go away.
        if (_stopping)
        {
            pipe.Close();
            return;
        }

        // Set up for the next caller.
        BeginWaitForNextConnection();

        // Handle this client's I/O. This code wraps the pipe stream in BinaryReader and BinaryWriter objects and handles communication with the client.
        HandlePipeClient(pipe);
    }

这段代码在单个连接时可以完美运行,但当多个实例尝试快速连接时就会出现问题。我的客户端代码指定了10秒的超时时间,因此即使10个实例在同一秒钟内尝试连接,我也希望它们都能成功,因为这段代码不应该花费10秒来循环10次“ClientRequestHandler”回调并进入“BeginWaitForNextConnection”——但这正是我看到的情况。对于偶尔的单次连接,这段代码非常可靠,但如果频繁请求,似乎如果在回调和下一个“BeginWaitForConnection”之间到达连接请求,那么该连接不会排队并立即被接收,而是会丢失。
这是否是预期的?什么是惯用的正确解决方案?我只需要启动许多线程同时等待连接吗?

我刚花了一些时间尝试制作一个最小化的问题复现。我能够相当可靠地复现它,尽管奇怪的是,其中一个关键因素似乎是使用Take Command shell进行自动化。如果我只是简单地编写一个尽可能快速运行客户端的程序,使用Process.Create,那么似乎不可能触发这个问题,即使有100个客户端尽可能快地启动。但是,如果我在TCC中输入for /L %i in (1,1,50) do start Client.exe,那么无法连接到服务器的客户端数量会显著但不可预测地增加。 - undefined
如果我连续快速运行我的驱动程序两次,每次客户端都成功。如果我使用TCC自动化并出现错误,然后立即运行我的驱动程序,由我的驱动程序创建的实例也会出现问题。看起来TCC正在做某些事情,导致管道资源出现某种问题,但我无法想象是什么原因。 - undefined
1个回答

0

我有类似的需求。

最终我采用了每个连接一个服务器线程的方案,每个线程在前一个客户端连接之后立即创建。

private void ServerConnectToPipe()
{
    var bw = new BackgroundWorker();
    bw.DoWork += (s, e) => DoServerStuff();
    bw.RunWorkerAsync();
}

private void DoServerStuff()
{
    var serverStream = new NamedPipeServerStream("PipeName", PipeDirection.In, NamedPipeServerStream.MaxAllowedServerInstances);
    var streamReader = new StreamReader(serverStream);

    serverStream.WaitForConnection();

    ServerConnectToPipe();

    Log("Server connection", $"Client connected !");
    while (true)
    {
        var line = streamReader.ReadLine();
        // do stuff
    }
}

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