2016-06-10 2 views
0

У меня есть служба Windows, а клиент слушает со следующим funcionality:Использование именованных каналов, как писать сообщения, клиент получает по очереди один за другим?

Win службы:

  1. Создает именованный канал
  2. Создает процесс клиента
  3. Уэйтс для подключения
  4. Записывает клиенту процесс
  5. Читает от клиента
  6. Записывает клиенту pr ocess
  7. Читает от клиента
  8. ...

    public static bool StartProcessAsCurrentUser() 
    { 
        var hUserToken = IntPtr.Zero; 
        var sInfo = new STARTUPINFO(); 
        var procInfo = new PROCESS_INFORMATION(); 
        var pEnv = IntPtr.Zero; 
        int iResultOfCreateProcessAsUser; 
        string cmdLine = "ClientNamedPipeForm.exe"; 
    
        sInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO)); 
        byte[] buffer = new byte[BUFSIZE]; 
    
        try 
        { 
         var tSecurity = new SECURITY_ATTRIBUTES(); 
         tSecurity.nLength = Marshal.SizeOf(tSecurity); 
         var pSecurity = new SECURITY_ATTRIBUTES(); 
         pSecurity.nLength = Marshal.SizeOf(pSecurity); 
         pSecurity.bInheritHandle = true; //For controling handles from child process 
    
         IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(pSecurity)); 
         Marshal.StructureToPtr(pSecurity, pointer, true); 
    
         PipeSecurity ps = new PipeSecurity(); 
         System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null); 
         PipeAccessRule par = new PipeAccessRule(sid, PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow); 
         ps.AddAccessRule(par); 
         NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.WriteThrough, 10, 10, ps); 
    
         StreamWriter sw = new StreamWriter(pipeServer); 
    
         if (!CreateProcessAsUser(hUserToken, 
          null, // Application Name 
          cmdLine, // Command Line 
          IntPtr.Zero, 
          IntPtr.Zero, 
          true, 
          dwCreationFlags, 
          pEnv, 
          null, // Working directory 
          ref sInfo, 
          out procInfo)) 
         { 
          throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.\n"); 
         } 
    
         try 
         { 
           pipeServer.WaitForConnection(); 
           sw.WriteLine("Waiting"); 
           sw.Flush(); 
           pipeServer.WaitForPipeDrain(); 
    
           Thread.Sleep(5000); 
           sw.WriteLine("Waiting2"); 
           sw.Flush(); 
           pipeServer.WaitForPipeDrain(); 
    
           Thread.Sleep(5000); 
           sw.WriteLine("Waiting32"); 
           sw.Flush(); 
           pipeServer.WaitForPipeDrain(); 
    
           Thread.Sleep(5000); 
           sw.WriteLine("QUIT"); 
           sw.Flush(); 
           pipeServer.WaitForPipeDrain(); 
         } 
         catch (Exception ex) { throw ex; } 
    
         finally 
         { 
           if (pipeServer.IsConnected) { pipeServer.Disconnect(); } 
         } 
        } 
        finally 
        { 
         //Closing things 
        } 
    
        return true; 
    } 
    

Клиент:

  1. Создает именованный канал
  2. Подключается
  3. Считывает из службы
  4. Пишет в форме
  5. Пишет обслуживать
  6. Считывает из службы
  7. Пишет в форме
  8. Пишет обслуживать
  9. ...

    private void Client() 
    { 
        try 
        { 
        IntPtr hPipe; 
        string dwWritten; 
        byte[] buffer = new byte[BUFSIZE]; 
    
        NamedPipeClientStream pipeClient = new NamedPipeClientStream(".","testpipe", PipeDirection.In, PipeOptions.WriteThrough); 
    
        if (pipeClient.IsConnected != true) { pipeClient.Connect(); } 
    
        StreamReader sr = new StreamReader(pipeClient); 
    
        string temp; 
        bool cont = true; 
        while (cont) 
        { 
         temp = ""; 
         temp = sr.ReadLine(); 
         if (temp != null) 
         { 
          listBox1.Items.Add(temp); 
          listBox1.Refresh(); 
         } 
         if (temp != "QUIT") 
         { 
          sw.WriteLine("Response"); 
          sw.Flush(); 
          pipeClient.WaitForPipeDrain(); 
         } 
         else 
         { 
          sw.WriteLine("Response"); 
          cont = false; 
         } 
        } 
        } 
        catch (Exception ex) 
        { 
         throw new Exception("Exception: " + ex.Message); 
        } 
    

появляется проблема написав до listbox1. Форма (и ее listbox1) появляется только на экране пользователя, когда весь процесс закончился, и он отображает сразу четыре сообщения. У меня есть Thread.Sleep(5000) на стороне обслуживания, чтобы показать, что каждое сообщение написано отдельно, но я не уверен, что процесс не дождался Thread, и я его неправильно тестирую, или форма отображается со всеми сообщениями по какой-то причине ...

ответ

1

Ваша проблема в цикле while, который блокирует текущий Thread, этот поток также используется для обновления пользовательского интерфейса.

1) Плохое решение вызывает DoEvents() внутри цикла while. Но было бы разумнее сделать больше исследований для реализации метода 2

2) Лучше создать класс, который создаст поток и инициирует событие, когда будет получено сообщение.

Например: (сочинительство онлайн так может содержать некоторые синтаксические/опечатки) Так что я буду называть его ПСЕВДО кодом ;-)

public class MessageEventArgs : EventArgs 
{ 
    public string Message { get; private set;} 

    public MessageEventArgs(string message) 
    { 
     Message = message; 
    } 
} 

public class MyReceiver : IDisposable 
{ 
    private Thread _thread; 
    private ManualResetEvent _terminating = new ManualResetEvent(false); 

    public void Start() 
    { 
     _thread = new Thread(() => 
     { 
      try 
      { 
       IntPtr hPipe; 
       string dwWritten; 
       byte[] buffer = new byte[BUFSIZE]; 

       NamedPipeClientStream pipeClient = new NamedPipeClientStream(".","testpipe", PipeDirection.In, PipeOptions.WriteThrough); 

       if (pipeClient.IsConnected != true) { pipeClient.Connect(); } 

       StreamReader sr = new StreamReader(pipeClient); 

       string temp; 

       while(!_terminating.WaitOne(0)) 
       { 
        temp = ""; 
        temp = sr.ReadLine(); 
        if (temp != null) 
        { 
         OnMessage?.Invoke(temp); 
        } 
        if (temp != "QUIT") 
        { 
         sw.WriteLine("Response"); 
         sw.Flush(); 
         pipeClient.WaitForPipeDrain(); 
        } 
        else 
        { 
         sw.WriteLine("Response"); 
         _terminating.Set(); 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new Exception("Exception: " + ex.Message); 
      }    

     }); 

     _thread.Start(); 
    } 

    public void Dispose() 
    { 
     _terminating.Set(); 
     _thread.Join(); 
    } 

    public event EventHandler<MessageEventArgs> OnMessage; 
} 

// Example of how to use the Receiver class. 
public class Form1: Form 
{ 
    MyReceiver _receiver; 

    public Form1() 
    { 
     InitializeComponent(); 
     this.FormClosed += FormClosed; 

     _receiver = new MyReceiver(); 
     _receiver.OnMessage += MessageReceived; 
     _receiver.Start(); 
    } 

    public void MessageReceived(object sender, MessageEventArgs e) 
    { 
     // You need to invoke this, because the event is run on other than the UI thread. 
     this.Invoke(new Action(() => 
     { 
      listBox1.Items.Add(e.Message); 
     }); 
    } 

    public void FormClosed(object sender, EventArgs e) 
    { 
     _receiver.Dispose(); 
    } 
} 
+0

спасибо миллиона. Великий псевдокод :). – AdSsa