命名管道上的FileNotFoundException
本文关键字:FileNotFoundException 管道 | 更新日期: 2023-09-27 18:04:44
我有一个命名管道客户端/服务器设置。服务器运行在Windows托管服务中。当我在本地主机和开发集成环境上运行代码时,它运行得很好;我能够通过我的命名管道客户端连接到服务器。我的客户机和服务器实现如下:
如前所述,这在我的机器和开发环境上运行良好。我已经将其部署到测试服务器,但是,每次我的客户机连接到服务器时,它都会抛出FileNotFoundException。我在服务器代码的重要位置放置了try catch块,但是我的服务器端代码都无法处理此异常,并且我的服务因异常而失败。
任何关于为什么会发生这种情况的见解将是伟大的。
编辑
我更新了我的代码,使用这个:
private static PipeSecurity PipeSecurity
{
get
{
var security = new PipeSecurity();
security.AddAccessRule(new PipeAccessRule("Users", PipeAccessRights.ReadWrite, AccessControlType.Allow));
security.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
security.AddAccessRule(new PipeAccessRule(WindowsIdentity.GetCurrent().User, PipeAccessRights.FullControl, AccessControlType.Allow));
security.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow));
return security;
}
}
var pipeStream = new NamedPipeServerStream(PipeName, PipeDirection.InOut, MaxThreads, PipeTransmissionMode.Message, PipeOptions.WriteThrough, 1024, 1024, PipeSecurity);
_logger.InfoFormat("CreatedServerInstance: {0}, Waiting for Connection.", _clientCount+1);
pipeStream.WaitForConnection();
异常似乎发生在管道流. waitforconnection()行,只要客户端连接。奇怪的是,它没有捕捉到异常,并立即使服务失败。我的服务在本地系统下运行。请注意,我并没有同时使用这些规则,我只是粘贴了它,这样你就知道我是如何单独尝试的。我深入研究了微软发布的源代码资源管理器工具,以跟踪FileNotFoundException的来源。它似乎来自system'security'accesscontrol'nativeobjectsecurity.cs。这个类是pipessecurity类的继承对象,用来调用SetAccessRule和AddAccessRule的基方法。
使用命名管道时必须考虑以下几点:
关于管道的命名,请看这里:https://msdn.microsoft.com/en-us/library/windows/desktop/aa365783(v=vs.85).aspx。它解释了当您在服务器上创建管道时,您必须使用''.'pipe'PipeName
符号来标识本地机器(这是由. net包装器为您处理的)。但是,当您连接到管道时,您必须通过在管道URL中包含服务器名称来确保您连接到正确的服务器。''ServerName'pipe'PipeName
您必须考虑的另一个方面是访问控制。您必须确保管道的创建具有适当的权限,以允许远程客户端连接到它。https://msdn.microsoft.com/en-us/library/windows/desktop/aa365600 (v = vs.85) . aspx。请确保正确设置了管道的ACL。
根据你对问题的描述,听起来你的问题可能与命名有关。
这里是一些示例代码从服务器我写了一会儿:
private void SpawnServer()
{
PipeSecurity pipeSa = new PipeSecurity();
// let everyone read from the pipe but not write to it
// this was my use case - others may be different
pipeSa.SetAccessRule(new PipeAccessRule("Everyone", PipeAccessRights.Read, System.Security.AccessControl.AccessControlType.Allow));
pipeSa.SetAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), PipeAccessRights.Read, System.Security.AccessControl.AccessControlType.Allow));
pipeSa.SetAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow));
pipeSa.SetAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.ServiceSid, null), PipeAccessRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
pipeSa.SetAccessRule(new PipeAccessRule(WindowsIdentity.GetCurrent().Owner, PipeAccessRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
var pipeInstance = new NamedPipeServerStream(_pipeName, PipeDirection.InOut, 128, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, 128, 128, pipeSa);
PipeClient pipeClient = new PipeClient(pipeInstance, Interlocked.Increment(ref _totalclients));
pipeInstance.BeginWaitForConnection(HandlePipeConnection, Tuple.Create(pipeInstance, pipeClient));
}
// this method asynchronously handles a new pipe connection and starts
// another server to handle other incoming connections
private void HandlePipeConnection(IAsyncResult ar)
{
var pipeServer = (ar.AsyncState as Tuple<NamedPipeServerStream, PipeClient>).Item1;
var pipeClient = (ar.AsyncState as Tuple<NamedPipeServerStream, PipeClient>).Item2;
try
{
pipeServer.EndWaitForConnection(ar);
// not shown here, I had the server
// send the new client a message upon connect
// if (!pipeClient.SendMessage(announceMessage))
// throw new Exception("Send message failed for new pipe client connection!");
pipeClient.Error += PipeClient_Error;
pipeClient.Disposed += PipeClient_Disposed;
pipeClient.MessagesReceived += PipeClient_MessagesReceived;
pipeClient.Read();
}
catch (Exception exc)
{
// Log Exception
pipeClient.Dispose();
}
try
{
SpawnServer();
}
catch (IOException)
{
// if an IO error occurs, most likely it's because max pipe clients reached..
// in my case I was raising an event here
}
catch (Exception exc)
{
// otherwise handle the error here (raise another event - not shown..)
}
}
上面的代码使用了一个名为PipeClient
的类,这是我编写的一个类,它包装了一个NamedPipeClientStream
,以便以一种易于与客户端接口的方式公开它。该类包含用于读取和写入管道客户端流的助手方法,以及在接收(读取)数据和发生错误时引发的一些事件。我不打算粘贴完整的类实现因为它与问题没有直接关系但我将粘贴在构造函数
public class PipeClient
: IDisposable
{
private PipeStream _pipeInstance = null;
private bool _disposed = false;
private int _clientId = 0;
public PipeClient(PipeStream pipeInstance, int clientid)
{
_pipeInstance = pipeInstance;
// this class can be used both by clients and by the server to
// represent connected clients
// on the server, the clients are already connected; for clients code they are not and the stream will be of a different kind
if (!_pipeInstance.IsConnected && _pipeInstance is NamedPipeClientStream)
((NamedPipeClientStream)_pipeInstance).Connect(100);
_clientId = clientid;
// more internals being set up here (not shown)
// such as buffers for reads, queue for messages to send out etc.
}
// convenience constructor to create a pipe client from a pipe name
public PipeClient(string pipeName, bool readOnly)
: this(new NamedPipeClientStream(".", pipeName, readOnly ? PipeDirection.In : PipeDirection.InOut, PipeOptions.Asynchronous), 0)
{
}
// rest of the class not shown..
}