2015-07-24 7 views
-1

У меня есть именованный канал клиент/сервер. Сервер работает внутри службы Windows. когда я запускаю свой код в своей локальной интеграции с localhost и dev, он работает нормально; Я могу подключиться к серверу через мой клиент именованного канала. Мои клиентские и серверные реализации выглядят следующим образом:FileNotFoundException на именованной трубе

Как уже упоминалось ранее, это отлично работает на моей машине и в среде разработчиков. Я развернул это на тестовом сервере, однако каждый раз, когда мой клиент подключается к серверу, он будет генерировать 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(); 

Исключение, кажется, происходит на линии pipeStream.WaitForConnection() как только клиент подключается. это странно, что он не поймает исключения, и он сразу же отключил службу. Моя служба работает под локальной системой. Обратите внимание, что я не использую эти правила в одно и то же время, я просто вложил его, чтобы вы знали, как я пробовал их все индивидуально. Я вырыл через source code explorer too l, который опубликовал микросфт для отслеживания источника FileNotFoundException. Кажется, он исходит от системы \ security \ accesscontrol \ nativeobjectsecurity.cs. Этот класс наследует класс PipeSecurity, чтобы вызвать базовые методы для SetAccessRule и AddAccessRule.

ответ

1

При работе с именованными каналами вы должны рассмотреть несколько вещей:

Именование

Что касается наименования трубы, посмотрите здесь: 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 для трубы правильно установлен.


Основываясь на вашем описании проблемы, похоже, что ваши проблемы, вероятно, связаны с наименованием.

UPDATE

Вот некоторые примеры кода с сервера, я написал некоторое время назад:

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.. 
} 
+0

это было легко для меня, чтобы изменить формат имени на клиенте, когда он пытается подключения. тем не менее, по-прежнему вызывает ту же ошибку. Что касается безопасности, моя цель всегда будет запускаться с одного и того же сервера. Я также проверил, что конкретный именованный канал доступен для подключения, когда запущена служба Windows. только когда клиент подключается к тому, что служба выдает ошибку и останавливается. Удивительно, что в нем говорится, что исключение необработанно, и это не так, поскольку я включил try catch во все методы на сервере. – vaibinewbee

+0

@vaibinewbee, даже если вы запустите своего клиента на том же сервере - если именованный канал создается службой, весьма вероятно, что служба работает в другом процессе, который может выполняться с повышенными привилегиями. Вы должны будете убедиться, что клиент позволяет подключиться! –

+0

Хорошо. Я буду играть с материалами безопасности. Спасибо за ваши рекомендации. – vaibinewbee

Смежные вопросы