gpt4 book ai didi

c# - 跨进程连接匿名管道会出现无效句柄错误,我正在使用 System.Io.Pipes

转载 作者:太空狗 更新时间:2023-10-29 23:01:45 24 4
gpt4 key购买 nike

我正在尝试使用 System.Io.Pipes 提供的匿名管道组合一个类来处理进程之间的 Ipc。

我遇到的问题是,当我使用单个进程测试类时,管道设置正确,我可以毫无问题地在客户端和服务器之间发送数据。但是,当我将客户端和服务器拆分为不同的进程(在同一台机器上)时,客户端无法连接到服务器管道的末端。

调用时出现错误System.Io.Exception Invalid pipe handle

_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);

类的完整代码粘贴在下面。

基本上它的工作原理是这样的;

  1. 服务器进程。为入站数据创建匿名管道集 - 将此称为管道 A
  2. 服务器进程。启动客户端进程并通过命令参数传递 PipeHandle
  3. 客户流程。连接到管道 A 的末端
  4. 客户流程。为入站数据创建匿名管道集(管道 B)5 客户端进程。使用管道 A 将管道句柄传回服务器
  5. 服务器进程。连接到管道 B 的末端

所以现在我们有两个匿名管道,指向服务器和客户端之间的相反方向。

这是我的 IPC 类的完整代码

    public class MessageReceivedEventArgs : EventArgs
{
public string Message { get; set; }
}

public class IpcChannel : IDisposable
{
private AnonymousPipeServerStream _inboundPipeServerStream;
private StreamReader _inboundMessageReader;
private string _inboundPipeHandle;

private AnonymousPipeClientStream _outboundPipeServerStream;
private StreamWriter _outboundMessageWriter;

public delegate void MessageReceivedHandler(object sender, MessageReceivedEventArgs e);
public event MessageReceivedHandler MessageReceived;

private Thread _clientListenerThread;
private bool _disposing = false;

public IpcChannel()
{
SetupServerChannel();
}

public IpcChannel(string serverHandle)
{
SetupServerChannel();
// this is the client end of the connection

// create an outbound connection to the server
System.Diagnostics.Trace.TraceInformation("Connecting client stream to server : {0}", serverHandle);
SetupClientChannel(serverHandle);

IntroduceToServer();
}

private void SetupClientChannel(string serverHandle)
{
_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);
_outboundMessageWriter = new StreamWriter(_outboundPipeServerStream)
{
AutoFlush = true
};
}

private void SetupServerChannel()
{
_inboundPipeServerStream = new AnonymousPipeServerStream(PipeDirection.In);
_inboundMessageReader = new StreamReader(_inboundPipeServerStream);
_inboundPipeHandle = _inboundPipeServerStream.GetClientHandleAsString();
_inboundPipeServerStream.DisposeLocalCopyOfClientHandle();

System.Diagnostics.Trace.TraceInformation("Created server stream " + _inboundPipeServerStream.GetClientHandleAsString());

_clientListenerThread = new Thread(ClientListener)
{
IsBackground = true
};

_clientListenerThread.Start();

}

public void SendMessage(string message)
{
System.Diagnostics.Trace.TraceInformation("Sending message {0} chars", message.Length);

_outboundMessageWriter.WriteLine("M" + message);
}

private void IntroduceToServer()
{
System.Diagnostics.Trace.TraceInformation("Telling server callback channel is : " + _inboundPipeServerStream.GetClientHandleAsString());

_outboundMessageWriter.WriteLine("CI" + _inboundPipeServerStream.GetClientHandleAsString());
}

public string ServerHandle
{
get
{
return _inboundPipeHandle;
}
}

private void ProcessControlMessage(string message)
{
if (message.StartsWith("CI"))
{
ConnectResponseChannel(message.Substring(2));
}
}

private void ConnectResponseChannel(string channelHandle)
{
System.Diagnostics.Trace.TraceInformation("Connecting response (OUT) channel to : {0}", channelHandle);

_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, channelHandle);
_outboundMessageWriter = new StreamWriter(_outboundPipeServerStream);
_outboundMessageWriter.AutoFlush = true;
}

private void ClientListener()
{
System.Diagnostics.Trace.TraceInformation("ClientListener started on thread {0}", Thread.CurrentThread.ManagedThreadId);

try
{
while (!_disposing)
{
var message = _inboundMessageReader.ReadLine();
if (message != null)
{
if (message.StartsWith("C"))
{
ProcessControlMessage(message);
}
else if (MessageReceived != null)
MessageReceived(this, new MessageReceivedEventArgs()
{
Message = message.Substring(1)
});
}
}
}
catch (ThreadAbortException)
{
}
finally
{

}
}

public void Dispose()
{
_disposing = true;

_clientListenerThread.Abort();

_outboundMessageWriter.Flush();
_outboundMessageWriter.Close();
_outboundPipeServerStream.Close();
_outboundPipeServerStream.Dispose();

_inboundMessageReader.Close();
_inboundMessageReader.Dispose();

_inboundPipeServerStream.DisposeLocalCopyOfClientHandle();
_inboundPipeServerStream.Close();
_inboundPipeServerStream.Dispose();
}
}

在单个进程中,可以这样使用;

class Program
{
private static IpcChannel _server;
private static IpcChannel _client;

static void Main(string[] args)
{
_server = new IpcChannel();
_server.MessageReceived += (s, e) => Console.WriteLine("Server Received : " + e.Message);

_client = new IpcChannel(_server.ServerHandle);
_client.MessageReceived += (s, e) => Console.WriteLine("Client Received : " + e.Message);


Console.ReadLine();

_server.SendMessage("This is the server sending to the client");

Console.ReadLine();

_client.SendMessage("This is the client sending to the server");

Console.ReadLine();

_client.Dispose();
_server.Dispose();
}

提前感谢您的任何建议。

最佳答案

您没有发布服务器代码,但无论如何。在服务器中:

  • 您需要在创建时指定客户端的管道句柄是可继承的。
  • 启动客户端时,您需要指定继承可继承句柄。

如果您错过了这些步骤中的任何一个,那么管道句柄在客户端进程中将无效。

此外,您的第 4 步将不起作用。如果您在客户端创建一个管道句柄,当您将它传回时,它对服务器没有任何意义。您可以使用 DuplicateHandle 来完成这项工作函数,但在服务器中创建所有句柄并在客户端中继承它们要容易得多。

关键点是句柄是每个进程的,而不是系统范围的。

关于c# - 跨进程连接匿名管道会出现无效句柄错误,我正在使用 System.Io.Pipes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9332986/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com