2012-05-24 6 views
4

J'essaie d'avoir une communication bidirectionnelle entre une application VC++ 6 et une application C#. J'utilise des pipes nommées. Dans mon code C++ je peux lire le message du client C# mais ensuite le serveur "meurt" et je dois le redémarrer à nouveau. Ce que je veux faire, c'est que l'application C# se connecte à l'application C++, demande un statut, et que l'application C++ s'éteigne et vérifie l'état, puis retourne "busy" ou "idle".Communication bidirectionnelle C++ vers C# utilisant des canaux nommés

Je ne peux rien écrire sur le client C# car il dit que la connexion a été fermée. Certaines choses que j'ai commentées sont des choses que j'ai déjà essayées.

code C++ (commencé comme un fil)

UINT CNamedPipe::StartNamedPipeServer() 
{ 
LPTSTR lpszPipename = "\\\\.\\pipe\\SAPipe"; 
    HANDLE hPipe; 
    BOOL flg; 
    DWORD dwWrite,dwRead; 
    char szServerUpdate[200]; 
    char szClientUpdate[200]; 

    hPipe = CreateNamedPipe ( lpszPipename, 
           PIPE_ACCESS_DUPLEX, 
           PIPE_TYPE_MESSAGE | 
           PIPE_READMODE_MESSAGE | 
           PIPE_NOWAIT,     //changed from nowait 
           PIPE_UNLIMITED_INSTANCES, // max. instances 
           BUFSIZE,     // output buffer size 
           BUFSIZE,     // input buffer size 
           PIPE_TIMEOUT,    // client time-out 
           NULL);      // no security attribute 

    if (hPipe == INVALID_HANDLE_VALUE) 
     return 0; 

    ConnectNamedPipe(hPipe, NULL); 

    while(m_bServerActive) //This seems to work well .... 
    { 

     //Read from client 
     flg = ReadFile(hPipe,szClientUpdate,strlen(szClientUpdate),&dwRead, NULL); 

     if(flg) //Read something from the client!!!! 
     { 
      CString csMsg,csTmp; 

      for(int i=0;i<dwRead;i++){ 
       csTmp.Format("%c",szClientUpdate[i]); 
       csMsg += csTmp; 
      } 


      AfxMessageBox("Client message: " + csMsg); 

      strcpy(szServerUpdate,"busy"); 

      //Write status to Client 
      flg = WriteFile(hPipe, szServerUpdate, strlen(szServerUpdate), &dwWrite, NULL); 

      EndServer(); 
      StartServer(); 
     } 

    } 

    return 0; 

}

C# Code:

public void ThreadStartClient(object obj) 
    { 
     // Ensure that we only start the client after the server has created the pipe 
     ManualResetEvent SyncClientServer = (ManualResetEvent)obj; 

     // Only continue after the server was created -- otherwise we just fail badly 
     // SyncClientServer.WaitOne(); 

     using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "SAPipe")) 
     { 
      // The connect function will indefinately wait for the pipe to become available 
      // If that is not acceptable specify a maximum waiting time (in ms) 
      pipeStream.Connect(); 

      //Write from client to server 
      using (StreamWriter sw = new StreamWriter(pipeStream)) 
      { 
       sw.WriteLine("What's your status?"); 
      } 

      //Read server reply 
      /*using (StreamReader sr = new StreamReader(pipeStream)) 
      { 
       string temp = ""; 
       temp = sr.ReadLine(); //Pipe is already closed here ... why? 

       MessageBox.Show(temp); 

      }*/ 

      //pipeStream.Close(); 

     } 
    } 
} 

Répondre

8

Mise au rebut d'un StreamWriter ou StreamReader fermera le flux sous-jacent. Vos instructions using seront donc à l'origine de la fermeture du flux.

public void ThreadStartClient(object obj) 
    { 
      // Ensure that we only start the client after the server has created the pipe 
      ManualResetEvent SyncClientServer = (ManualResetEvent)obj; 

      // Only continue after the server was created -- otherwise we just fail badly 
      // SyncClientServer.WaitOne(); 

      using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "SAPipe")) 
      { 
       // The connect function will indefinately wait for the pipe to become available 
       // If that is not acceptable specify a maximum waiting time (in ms) 
       pipeStream.Connect(); 


       //Write from client to server 
       StreamWriter sw = new StreamWriter(pipeStream)) 
       sw.WriteLine("What's your status?"); 

       //Read server reply 
       StreamReader sr = new StreamReader(pipeStream) 
       string temp = ""; 
       temp = sr.ReadLine(); //Pipe is already closed here ... why? 

       MessageBox.Show(temp); 
      } 
    } 

Il convient également de noter que, parce que vous enveloppez votre flux dans une déclaration à l'aide, la fonction en commentaire pipeStream.Close() n'est pas nécessaire.

+0

Merci, c'est une aide précieuse. Je vais changer mon code et voir ce qui se passe. Comme vous l'avez peut-être deviné, je suis nouveau à C#. –

+0

Pas de problème, n'oubliez pas d'appuyer sur le bouton sous les votes, de cette façon vous obtiendrez une meilleure note d'approbation! – Blam

3

Ok, ça marche pour mon application .... merci Blam!

Voici le serveur du C (exécuter ce à l'intérieur d'un fil):

UINT CNamedPipe::StartNamedPipeServer() 
{ 
    if(!m_bServerActive) 
     return 0; 

    LPTSTR lpszPipename = "\\\\.\\pipe\\MyPipe"; 
     HANDLE hPipe; 
     BOOL flg; 
     DWORD dwWrite,dwRead; 
     char szServerUpdate[200]; 
     char szClientUpdate[200]; 

     hPipe = CreateNamedPipe ( lpszPipename, 
            PIPE_ACCESS_DUPLEX, 
            PIPE_TYPE_MESSAGE | 
            PIPE_READMODE_MESSAGE | 
            PIPE_WAIT,     //HAS TO BE THIS 
            PIPE_UNLIMITED_INSTANCES, // max. instances 
            BUFSIZE,     // output buffer size 
            BUFSIZE,     // input buffer size 
            PIPE_TIMEOUT,    // client time-out 
            NULL);      // no security attribute 

     if (hPipe == INVALID_HANDLE_VALUE) 
      return 0; 

     ConnectNamedPipe(hPipe, NULL); 


     strcpy(szServerUpdate,"busy"); 

     //Write status to Client 
     flg = WriteFile(hPipe, szServerUpdate, strlen(szServerUpdate), &dwWrite, NULL); 

     EndServer(); 
     StartServer(); 

     return 0; 
} 

Et voici le client C#:

public void ThreadStartClient(object obj) 
     { 
      // Ensure that we only start the client after the server has created the pipe 
      ManualResetEvent SyncClientServer = (ManualResetEvent)obj; 

      using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "MyPipe", PipeDirection.InOut)) 
      { 

       // The connect function will indefinately wait for the pipe to become available 
       // If that is not acceptable specify a maximum waiting time (in ms) 
       pipeStream.Connect(); 

       if (!pipeStream.IsConnected) //It thinks it's connected but can't read anything .... 
       { 
        MessageBox.Show("Failed to connect ...."); 
        return; 
       } 

       //Read server reply 
       StreamReader sr = new StreamReader(pipeStream); 

       char[] c = new char[200]; 

       while (sr.Peek() >= 0) 
       { 
        sr.Read(c, 0, c.Length); 
       } 

       string s = new string(c); 
       MessageBox.Show(s); 
      } 
     } 

Je ne suis pas envoyer quoi que ce soit du client au serveur, car Je n'ai pas besoin de ... le point clé dans ceci était le paramètre PIPE_WAIT dans la fonction CreateNamedPipe(). Cela fait attendre le serveur pour une connexion client.

Questions connexes