C# 跨进程连接匿名管道会产生无效句柄错误I';我使用System.Io.Pipes
我正试图使用System.Io.pipes提供的匿名管道来组合一个类来处理进程之间的Ipc 我遇到的问题是,当我使用单个进程测试类时,管道设置正确,我可以在客户机和服务器之间毫无问题地发送数据。但是,当我将客户机和服务器拆分为单独的进程(在同一台机器上)时,客户机无法连接到服务器管道的末端 调用时引发错误System.Io.Exception无效管道句柄C# 跨进程连接匿名管道会产生无效句柄错误I';我使用System.Io.Pipes,c#,ipc,C#,Ipc,我正试图使用System.Io.pipes提供的匿名管道来组合一个类来处理进程之间的Ipc 我遇到的问题是,当我使用单个进程测试类时,管道设置正确,我可以在客户机和服务器之间毫无问题地发送数据。但是,当我将客户机和服务器拆分为单独的进程(在同一台机器上)时,客户机无法连接到服务器管道的末端 调用时引发错误System.Io.Exception无效管道句柄 _outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection
_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);
该类的完整代码粘贴在下面
基本上它的工作是这样的
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();
}
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();
}
提前感谢您的建议。您没有发布服务器代码,但无论如何。在服务器中:
- 您需要指定客户端的管道句柄在创建时是可继承的
- 启动客户机时,需要指定可继承句柄将被继承
关键的一点是句柄是每个进程的,而不是系统范围的。启动子进程时不要忘记设置UseShellExecute=false,否则句柄将不会被继承。感谢您花时间回答。为清楚起见,此类位于服务器和客户端都引用的共享程序集中。它的操作模式由使用的构造函数决定-无参数表示服务器,有参数表示服务器的管道句柄,表示作为客户端连接。你说的很有道理,我会让你知道它是如何进行的。我决定使用命名管道解决方案,它非常有效。如果你还想用UAC提升子进程,那怎么办?这要求
UseShellExecute
为true
@Alejandro尝试使用将升级的桥接进程,然后启动子进程,并将UseShellExecute
设置为false
。所以我建议以下方案:主流程(用户级)->桥接流程(升级,拥有句柄)->子流程(将在父流程升级后升级)。