Εποπτεία εισόδου/εξόδου

Ένα αποτελεσματικό γνώρισμα του Glib (μια από τις βιβλιοθήκες που υπόκεινται στην gtkmm) είναι η ικανότητα να ελέγχουν για δεδομένα σε έναν περιγραφέα αρχείου για σας. Αυτό είναι ιδιαίτερα χρήσιμο για εφαρμογές δικτύωσης. Η παρακάτω μέθοδος χρησιμοποιείται για να κάνετε αυτό:

sigc::connection Glib::SignalIO::connect(const sigc::slot<bool,Glib::IOCondition>& slot,
                                 int fd, Glib::IOCondition condition,
                                 int priority = Glib::PRIORITY_DEFAULT);

Το πρώτο όρισμα είναι μια σχισμή που θέλετε να κληθεί όταν το συγκεκριμένο συμβάν (δείτε όρισμα 3) συμβαίνει στον περιγραφέα του αρχείου που ορίσατε χρησιμοποιώντας το όρισμα δύο. Το όρισμα τρία μπορεί να είναι ένα ή περισσότερα (χρησιμοποιώντας |) των:

  • Glib::IO_IN - Κλήση της μεθόδου σας όταν υπάρχουν δεδομένα έτοιμα για ανάγνωση στον περιγραφέα αρχείου σας.
  • Glib::IO_OUT - Κλήση της μεθόδου σας όταν ο περιγραφέας αρχείου είναι έτοιμος για εγγραφή.
  • Glib::IO_PRI - Κλήση της μεθόδου σας όταν ο περιγραφέας αρχείου έχει επείγοντα δεδομένα για ανάγνωση.
  • Glib::IO_ERR - Κλήση της μεθόδου σας όταν ένα σφάλμα προκύψει στον περιγραφέα αρχείου.
  • Glib::IO_HUP - Κλήση της μεθόδου σας όταν διακόψει (η σύνδεση έχει διακοπεί συνήθως για διοχετεύσεις και υποδοχές).

Η τιμή επιστροφής είναι μια sigc::connection που μπορεί να χρησιμοποιηθεί για να σταματήσει την παρακολούθηση αυτού του περιγραφέα αρχείου χρησιμοποιώντας τη μέθοδό του disconnect(). Ο χειριστής σήματος slot πρέπει να δηλωθεί ως εξής:

bool input_callback(Glib::IOCondition condition);

όπου η condition ορίζεται όπως παραπάνω. Ως συνήθως, η υποδοχή δημιουργείται με την sigc::mem_fun() (για μια μέθοδο μέλους ενός αντικειμένου.), ή sigc::ptr_fun() (για μια συνάρτηση).

Ένα μικρό παράδειγμα ακολουθεί. Για τη χρήση του παραδείγματος εκτελέστε το απλά από ένα τερματικό· δεν δημιουργεί παράθυρο. Θα δημιουργήσει μια διοχέτευση με όνομα testfifo στον τρέχοντα κατάλογο. Έπειτα ξεκινήστε ένα άλλο κέλυφος και εκτελέστε την echo "Hello" > testfifo. Το παράδειγμα θα εκτυπώσει κάθε γραμμή που εισάγετε μέχρι την εκτέλεση της echo "Q" > testfifo.

Source Code

File: main.cc (For use with gtkmm 3, not gtkmm 2)

#include <build/config.h>
#include <gtkmm/application.h>
#include <glibmm/main.h>
#include <glibmm/iochannel.h>
#include <fcntl.h>
#include <iostream>

#include <unistd.h> //The SUN Forte compiler puts F_OK here.

//The SUN Forte compiler needs these for mkfifo:
#include <sys/types.h>
#include <sys/stat.h>

Glib::RefPtr<Gtk::Application> app;

int read_fd;
Glib::RefPtr<Glib::IOChannel> iochannel;

/*
  send to the fifo with:
  echo "Hello" > testfifo

  quit the program with:
  echo "Q" > testfifo
*/

// this will be our signal handler for read operations
// it will print out the message sent to the fifo
// and quit the program if the message was 'Q'.
bool MyCallback(Glib::IOCondition io_condition)
{
  if ((io_condition & Glib::IO_IN) == 0) {
    std::cerr << "Invalid fifo response" << std::endl;
  }
  else {
   Glib::ustring buf;

   iochannel->read_line(buf);
   std::cout << buf;
   if (buf == "Q\n")
     app->quit();

  }
  return true;
}


int main(int argc, char *argv[])
{
  app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

  if (access("testfifo", F_OK) == -1) {
    // fifo doesn't exist - create it
    #ifdef HAVE_MKFIFO
    if (mkfifo("testfifo", 0666) != 0) {
      std::cerr << "error creating fifo" << std::endl;
      return -1;
    }
    #else
      std::cerr << "error creating fifo: This platform does not have mkfifo()"
          << std::endl;
    #endif //HAVE_MKFIFO
  }

  read_fd = open("testfifo", O_RDONLY);
  if (read_fd == -1)
  {
    std::cerr << "error opening fifo" << std::endl;
    return -1;
  }

  // connect the signal handler
  Glib::signal_io().connect(sigc::ptr_fun(MyCallback), read_fd, Glib::IO_IN);

  // Creates a iochannel from the file descriptor
  iochannel = Glib::IOChannel::create_from_fd(read_fd);

  // and last but not least - run the application main loop
  app->hold(); // keep the application running without a window
  app->run();

  // now remove the temporary fifo
  if(unlink("testfifo"))
    std::cerr << "error removing fifo" << std::endl;

  return 0;
}