Dickes Problem mit Interprozesskommunikation



  • Hi,

    ich versuch einen MultiPipeServer zu schreiben für die Kommunikation zwischen einer Datenbankanwendung und explizit eingebundenen DLLs. Das ganze soll natürlich möglichst flexibel sein, man weiss ja nie, wie viele DLLs noch dazu kommen.
    Beim Schreiben des Servers habe ich mich, bis auf die Änderung zum Dynamischen, an das Beispiel in der MSDN 6.0a "named pipe server using overlapped io" gehalten. Das Erstellen der Pipes funktioniert so weit.

    Pipe->hPipe_Inst = CreateNamedPipe (Pipe_Name, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
          PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT,
          MaxInst, BufSize, BufSize, PIPE_TIMEOUT, NULL);
    
    /* BufSize entspricht der Größe meiner Structur, die "verschickt" werden soll.
     * PIPE_TIMEOUT = 1000 */
    

    Mit ConnectNamedPipe(..) zeigt der Server an, dass sich Client mit der Pipe verbinden soll. Die Stelle, an der der Client sich mit der erstellten Pipe verbindet, sieht folgender Maßen aus.

    HANDLE hPipe == INVALID_HANDLE_VALUE;
    for (int zaehler = 0; (zaehler < 10) && (hPipe == INVALID_HANDLE_VALUE); zaehler++)
    {
      hPipe = CreateFile (Pipe_Name, GENERIC_WRITE|GENERIC_READ, 0,
        NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
      int Error = GetLastError ();
    
      if (Error == ERROR_FILE_NOT_FOUND)
        Sleep (100);
      else //für den Fall, dass alle Pipes "busy" sind
        if (hPipe == INVALID_HANDLE_VALUE)
          WaitNamedPipe (Pipe_Name, 100);
    }
    

    Es sieht auch so, als würde alles funtionieren. Doch beim Schreiben in die Pipe (beim Client). Gibt GetLastError() zwei merkwürdige Werte zurück.

    Err1 = GetLastError(); //Err1 = ERROR_ALREADY_EXISTS (183)
      Success = WriteFile (hPipe, DLLMsg, PIPE_MSG_SIZE, &Bytes, &oStruct);
      Err2 = GetLastError(); //Err1 = ERROR_PIPE_NOT_CONNECTED (233)
    

    Dadurch kann das Lesen von der Pipe natürlich nicht funktionieren. Die Stelle sieht so aus.

    Err1 = GetLastError(); //Err1 = 0 (kein Fehler)
      Success = ReadFile (Pipe->hPipe_Inst, DLLMsg1,
        BufSize, &Bytes, (LPOVERLAPPED)&Pipe->oStruct);
      Err2 = GetLastError(); //Err2 = ERROR_INVALID_PARAMETER (87)
    

    So, das ist das Problem. Hat jemand Ideen. Danke für eure Zeit.

    Maffe



  • Siehst du an dem Code irgendetwas BCB-spezifisches?
    Ich auch nicht. 😉

    Verschoben nach "WinAPI".



  • ConnectNamedPipe ?! 🙄



  • Eigentlich hatte ich den Beitrag hier reingestellt, weil ich den BCB-Compiler für die Erstellung der Anwendung nutze, aber ihr werdet schon wissen, was ihr tut.



  • Was meinst du mit "ConnectNamedPipe?!"?



  • Bin mir nicht sicher, ob das das Richtige ist, aber ich meinte einfach nur die ConnectNamedPipe-Funktion 🕶
    So hatte ich eben den Fehlercode verstanden - ist denn der Serven noch connected? 🙄



  • Hi,

    ich bin mir immer noch nicht ganz sicher, was du meinst. Aber "bool ConnectNamedPipe (HANDLE /*hPipe*/, OVERLAPPED * /*oStruct*/)" ist eigentlich, dazu gedacht den Clients zu signalisieren, dass diese Pipe auf eine Verbindung wartet. Wenn man ohne "overlapped Struktur" arbeitet, also NULL, dann wartet der Prozeß die Zeitspanne, die man beim Erstellen der Pipe festgelegt hat, und liefert entweder "true" oder "false".

    Tja, mittler Weile bin ich so weit, dass ich rausgefunden habe, dass die "Beiden" sich miteinander verbinden. Allerdings trennt der Server aus irgend einem Grund die Verbindung wieder. Ich stell mal den gesamten Code drunter, wenn du willst, dann kannst du es dir anschauen, vielleicht siehst du ja den Grund.

    /* NewPipe legt eine neue Pipe an und signalisiert, dass die Pipe auf Verbindung wartet. */
    int TMPServer::NewPipe (char *Pipe_Name, char *PipeEvent_Name, int BufSize, int MaxInst)
    {
      int Error = NO_PIPE_ERROR;
      TPipeInst *Pipe = new TPipeInst;
      Pipe->hPipe_Inst = NULL;
    
      HANDLE hEvent = NULL;
      Pipe->hPipe_Inst = CreateNamedPipe (Pipe_Name, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
          PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT,
          MaxInst, BufSize, BufSize, PIPE_TIMEOUT, NULL);
      if (Pipe->hPipe_Inst == INVALID_HANDLE_VALUE)
      {
        char Msg[100];
        sprintf (Msg, "MPServer: Fehler beim Erstellen der Pipe! - [GetLastError = %d]", 
          GetLastError());
        Message (Msg);
        Error = UNABLE_CREATE_PIPE;
      }
      if (Error == NO_PIPE_ERROR)
      {
        Pipe->oStruct.hEvent = CreateEvent (NULL, false, false, PipeEvent_Name);
        hEvent = CreateEvent (NULL, false, false, PipeEvent_Name);
    
        if ((Pipe->oStruct.hEvent == NULL)||
            (hEvent == NULL))
        {
          char Msg[100];
          sprintf (Msg, "MPServer: Fehler beim Erstellen der Events! - [GetLastError = %d]", 
            GetLastError());
          Message (Msg);
          Error = UNABLE_CREATE_EVENT;
        }
      }
    
      if (Error == NO_PIPE_ERROR)
      {
        Pipe->PendingIO = ConnectToNewClient (Pipe->hPipe_Inst, &Pipe->oStruct);
        /*if (!Pipe->PendingIO)
          Error = CONNECTING_ERROR;*/
    
        Pipe->PipeStatus = Pipe->PendingIO ? CONNECTING_STATE : READING_STATE;
    
        Pipes->Add (Pipe);
        Events->Add (hEvent);
        Instances++;
      }
    
      ServerStatus = Error;
      return Error;
    } //TMPServer::NewPipe..
    
    //-------------------------------------------------------------------------------------------
    
    /* ConnectToNewClient signalisiert Verbindung und macht eine kurze Fehlerauswertung. */
    bool TMPServer::ConnectToNewClient (HANDLE hPipe, OVERLAPPED *oStruct)
    {
      bool Success, PendingIO = false;
      int Error = 0;
    
      Success = ConnectNamedPipe (hPipe, oStruct);
      //SetEvent (oStruct->hEvent);
    
      if (Success) //wenn alles ok, dann sollte "false" sein
        Message ("MPServer: Fehler beim Verbinden mit dem Client! Pipe schon belegt.");
    
      Error = GetLastError();
      switch (Error)
      {
        case ERROR_IO_PENDING:
          PendingIO = true;
          break;
    
        case ERROR_PIPE_CONNECTED:
          SetEvent (oStruct->hEvent);
          break;
    
        default:
          char Msg[100];
          sprintf (Msg, "MPServer: Unbekannter Fehler beim Verbinden mit dem Client! - 
            [GetLastError = %d]", Error);
          Message (Msg);
          break;
      }
      return PendingIO;
    } //TMPServer::ConnectToNewClient..
    
    //------------------------------------------------------------------------------------------------
    
    /* Trennt und verbindet neu.*/
    int TMPServer::DisAndReconnect (TPipeInst *Pipe)
    {
      int Error = NO_PIPE_ERROR;
      if (!DisconnectNamedPipe (Pipe->hPipe_Inst))
      {
        Error = DISCONNECTING_ERROR;
        Message ("MPServer: Fehler beim Trennen der Pipe!");
      }
    
      if (Error == NO_PIPE_ERROR)
      {
        Pipe->PendingIO = ConnectToNewClient (Pipe->hPipe_Inst, &Pipe->oStruct);
        Pipe->PipeStatus = Pipe->PendingIO ? CONNECTING_STATE : READING_STATE;
      }
      return Error;
    } //TMPServer::DisAndReconnect..
    
    //---------------------------------------------------------------------------------------------
    
    /* ReturnPacket liest das übermittelte Paket aus der entsprechenden Pipe. Bei bestimmten 
    Fehlern wird die Verbindung gekappt und neu signalisiert. */
    int TMPServer::ReturnPacket (int Index, int BufSize, TDLLPacket **DLLMsg)
    {
      SetLastError ((int) ERROR_SUCCESS); //muss gemacht werden, da sonst der letzte Fehler
      //die Operationen beeinflusst
      bool Success = false;
      DWORD Bytes = 0;
      int Error = NO_PIPE_ERROR;
    
      TPipeInst *Pipe = (TPipeInst *) Pipes->Items[Index];
    
      if (Pipe->PendingIO)
        Success = GetOverlappedResult (Pipe->hPipe_Inst, &Pipe->oStruct, &Bytes, false);
      switch (Pipe->PipeStatus)
      {
        case CONNECTING_STATE:
          if (!Success)
          {
            Message ("MPServer: Pipe ist immer noch nicht mit Client verbunden!");
            //Error = STILL_CONNECTING_ERROR;
          }
          Pipe->PipeStatus = READING_STATE;
          break;
    
        case READING_STATE:
          if ((!Success)||(Bytes == 0))
          {
            DisAndReconnect (Pipe);
            Error = DISANDRECONNECT;
          }
          else
            Pipe->PipeStatus = WRITING_STATE;
          break;
    
        case WRITING_STATE:
          if (!Success)
          {
            DisAndReconnect (Pipe);
            Error = DISANDRECONNECT;
          }
          else
            Pipe->PipeStatus = READING_STATE;
          break;
    
        default:
          Message ("MPServer: Unbekannter Pipezustand!!!");
          Error = UNKNOWN_ERROR;
      }
    
      bool Done = false;
      TDLLPacket *DLLMsg1 = new TDLLPacket;
      switch (Pipe->PipeStatus)
      {
        case READING_STATE:
    
          Success = ReadFile (Pipe->hPipe_Inst, DLLMsg1,
              BufSize, &Bytes, (LPOVERLAPPED)&Pipe->oStruct);
          if ((Success)&&(Bytes != 0))
          {
            Pipe->PendingIO = false;
            Pipe->PipeStatus = WRITING_STATE;
            Done = true;
          }
    
          if ((!Done)&&(!Success)&&(Err2 == ERROR_IO_PENDING))
          {
            Pipe->PendingIO = true;
            Done = true;
          }
    
          if (!Done)
            DisAndReconnect (Pipe);
          break;
    
        case WRITING_STATE:
          Pipe->PipeStatus = READING_STATE;
          break;
    
        default:
          Message ("MPServer: Unbekannter Pipezustand!!!");
          Error = UNKNOWN_ERROR;
          break;
      }
    
      ServerStatus = Error;
      return Error;
    } //TMPServer::ReturnPacket...
    

    Danke.


Log in to reply