Winforms 和服务之间的命名管道只能连接一次

Named Pipes Between Winforms and Service Can Only Connect Once

我正在制作一个简单的应用程序来为我正在制作的应用程序试用命名管道。我可以最初连接到管道并写入由正在侦听输入的服务指定的文件。如果我重新启动我的 winforms 应用程序并尝试连接到它只是挂在 .Connect() 方法上的管道。如果我重新启动我的服务,那么我可以再次连接我的 winforms 应用程序......但只有一次(直到我再次重新启动服务)。

这是我的 Windows 服务上的 NamedPipeServerStream。

protected override void OnStart(string[] args)
{
    StartPipe();
}

protected override void OnStop()
{
}

public void StartPipe()
{
    FileStream fs = new FileStream(@"C:\Users\Nate\Desktop\PipeService.txt", FileMode.OpenOrCreate, FileAccess.Write);
    Task.Run(() =>
    {
        var server = new NamedPipeServerStream("PipeService3");
        server.WaitForConnection();
        StreamReader reader = new StreamReader(server);
        while (!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            StreamWriter writer = new StreamWriter(fs);
            writer.WriteLine(line);
            writer.Flush();
        }
    });
}

这是我的 Winforms 应用程序中的 NamePipeClientStream 部分

public StreamWriter writer;
public NamedPipeClientStream client;

public Form1()
{
    InitializeComponent();

    client = new NamedPipeClientStream("PipeService3");
    client.Connect();

    writer = new StreamWriter(client);
}

private void sendButton_Click(object sender, EventArgs e)
{
    string line = textBox1.Text;
    writer.WriteLine(line);
    writer.Flush();
}

这是我的解决方法,但我觉得有一种合法的方法可以做到这一点,而不是在每次有人打开 winforms 应用程序时停止和启动服务。

try
{
    client.Connect(1000);
}
catch
{
    var serviceController = ServiceController.GetServices();
    var pipeService = serviceController.Where(s => s.DisplayName == "PipeService").FirstOrDefault();
    pipeService.Stop();
    pipeService.WaitForStatus(ServiceControllerStatus.Stopped);
    pipeService.Start();
    pipeService.WaitForStatus(ServiceControllerStatus.Running);
    client.Connect();
}

我能够通过将管道设置为递归来解决问题,因此只要客户端断开连接(在我的情况下它只会是一个客户端),命名管道就会被处理掉,并使用相同的新管道管道被命名。 (还包括允许我的 winforms 应用程序作为非管理员仍然连接到使用提升权限的服务启动的管道)

  public void StartPipe()
    {
        System.Threading.Tasks.Task.Run(() =>
        {
            RecursivePipe();
        });
    }
    public void RecursivePipe()
    {
        PipeSecurity pipeSecurity = new PipeSecurity();
        pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
        pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), PipeAccessRights.FullControl, AccessControlType.Allow));

        var server = new NamedPipeServerStream("PipeService7", PipeDirection.InOut, 10, PipeTransmissionMode.Message, PipeOptions.WriteThrough, 1024, 1024, pipeSecurity);

        server.WaitForConnection();
        StreamReader reader = new StreamReader(server);
        while (!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            var lineArray = line.Split('$');
            if (lineArray.Length == 4)
            {
                SetkeyValue(lineArray);
            }
            else if (lineArray.Length == 5)
            {
                setStartupStrat(lineArray);
            }
            else
            {
                DeleteKeyValue(lineArray);
            }


        }
        server.Dispose();
        server.Close();
        RecursivePipe();
    }