Kapitel 11

Alle Codedateien dieses Kapitels herunterladen

11_1_1_Netzwerk.cpp

Datei herunterladen

#include <httplib.h>
#include <iostream>

int main()
{
  httplib::Client client("http://example.com");
  httplib::Result result = client.Get("/");
  if (result != nullptr)
  {
    // Server wurde erreicht
    std::cout << result->status << std::endl;
    std::cout << result->reason << std::endl;
  }
  else
  {
    // Server nicht erreicht
    std::cerr << "Verbindungsfehler" << std::endl;
  }
  return 0;
}

11_1_2_NetzwerkRedirect.cpp

Datei herunterladen

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <iostream>

int main()
{
  httplib::Client client("http://de.wikipedia.org");
  client.set_follow_location(true);
  httplib::Result result = client.Get("/");
  if (result != nullptr)
  {
    // Server wurde erreicht
    std::cout << result->status << std::endl;
    std::cout << result->reason << std::endl;
    std::cout << result->location << std::endl;
  }
  else
  {
    // Server nicht erreicht
    std::cerr << "Verbindungsfehler" << std::endl;
  }
  return 0;
}

11_2_1_NetzwerkAntworten.cpp

Datei herunterladen

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <string>
#include <iostream>

int main()
{
  // Mit dem deutschen Wikipedia-Server reden
  httplib::Client client("https://de.wikipedia.org");
  client.set_follow_location(true);

  // API-Optionen wählen, die einen kurzen Absatz liefern
  const std::string wikiApi = "/w/api.php?action=query&redirects=1"
    "&format=json&utf8=1&prop=extracts&explaintext=1&exsentences=2"
    "&titles=";
  // Das gewünschte Schlüsselwort anhängen
  std::string query = wikiApi + "C++";

  // Get-Anfrage abschicken. Die Methode verlangt leider
  // einen C-String, daher die Umwandlung mittels c_str()
  httplib::Result result = client.Get(query.c_str());
  if (result != nullptr)
  {
    // Server wurde erreicht
    if (result->status / 100 != 2)
    {
      std::cerr << "HTTP status: " << result->status
        << " - " << result->reason << std::endl;
      return 1;
    }
    std::cout << result->body << std::endl;
  }
  else
  {
    // Server nicht erreicht
    std::cerr << "Verbindungsfehler" << std::endl;
  }
  return 0;
}

11_2_2_NetzwerkAntwortenParsing.cpp

Datei herunterladen

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <string>
#include <iostream>

std::string stupidParser(const std::string& message,
  const std::string& key)
{
  // Der Schlüssel muss mit Anführungszeichen umgeben sein
  const std::string techKey = "\"" + key + "\":";
  size_t pos = message.find(techKey);
  if (pos == std::string::npos)
  {
    // Nicht gefunden
    return "";
  }
  // Das erste, öffnende Anführungszeichen nach dem Ende
  // des Schlüsselworts
  size_t first = message.find('\"', pos + techKey.size());
  if (first == std::string::npos)
  {
    std::cerr << "Ung\201ltiges JSON: " << message << std::endl;
    return "";
  }
  // Das zweite Anführungszeichen ist schon schwieriger,
  // denn es dürfte auch innerhalb des Textes auftauchen
  // und nicht nur am Ende. Da es in diesem Falle aber mit
  // einem Backslash codiert sein müsste, suchen Sie dann
  // weiter, wenn ein Backslash davor steht
  size_t second = message.find('\"', first + 1);
  while (second != std::string::npos
    && message.at(second - 1) == '\\')
  {
    // Ab dem gefundenen codierten Zeichen weitersuchen
    second = message.find('\"', second + 1);
  }
  if (second == std::string::npos)
  {
    std::cerr << "Ung\201ltiges JSON: " << message << std::endl;
    return "";
  }
  // Eins addieren, um das Anführungszeichen auszuschließen
  first++;
  // first und second sind Indizes. Daher erhalten Sie die
  // Länge des gewünschten Substrings, indem Sie sie
  // voneinander abziehen.
  return message.substr(first, second - first);
}

int main()
{
  // Mit dem deutschen Wikipedia-Server reden
  httplib::Client client("https://de.wikipedia.org");
  client.set_follow_location(true);

  // API-Optionen wählen, die einen kurzen Absatz liefern
  const std::string wikiApi = "/w/api.php?action=query&redirects=1"
    "&format=json&utf8=1&prop=extracts&explaintext=1&exsentences=2"
    "&titles=";
  // Das gewünschte Schlüsselwort anhängen
  std::string query = wikiApi + "C++";

  // Get-Anfrage abschicken. Die Methode verlangt leider
  // einen C-String, daher die Umwandlung mittels c_str()
  httplib::Result result = client.Get(query.c_str());
  if (result != nullptr)
  {
    // Server wurde erreicht
    if (result->status / 100 == 2)
    {
      std::cout << stupidParser(result->body, "extract")
        << std::endl;
    }
    else
    {
      std::cerr << "HTTP status: " << result->status
        << " - " << result->reason << std::endl;
    }
  }
  else
  {
    // Server nicht erreicht
    std::cerr << "Verbindungsfehler" << std::endl;
  }
  return 0;
}

11_3_JsonAntwort.cpp

Datei herunterladen

#include <json/json.h>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <string>
#include <iostream>

int main()
{
  // Mit dem deutschen Wikipedia-Server reden
  httplib::Client client("https://de.wikipedia.org");
  client.set_follow_location(true);

  // API-Optionen wählen, die einen kurzen Absatz liefern
  const std::string wikiApi = "/w/api.php?action=query&redirects=1"
    "&format=json&utf8=1&prop=extracts&explaintext=1&exsentences=2"
    "&titles=";
  // Das gewünschte Schlüsselwort anhängen
  std::string query = wikiApi + "C++";

  // Get-Anfrage abschicken. Die Methode verlangt leider
  // einen C-String, daher die Umwandlung mittels c_str()
  httplib::Result result = client.Get(query.c_str());
  if (result != nullptr)
  {
    // Server wurde erreicht
    if (result->status / 100 == 2)
    {
      Json::Value answer;
      // Der Reader liest den String in die Variable ein
      Json::Reader().parse(result->body, answer);
      // Zugriff auf Eigenschaften mit eckigen Klammern.
      // Bei Objekten innerhalb von Objekten (siehe #1)
      // können Sie die eckigen Klammern nacheinander
      // schreiben:
      Json::Value pages = answer["query"]["pages"];
      // Die nun folgende Eigenschaft hat keinen fest-
      // stehenden Schlüssel, sondern entspricht der
      // Page-ID (siehe #2). Daher müssen wir zuerst den
      // Schlüssel selbst abfragen.
      std::string pageName = pages.getMemberNames().at(0);
      // Der abgefragte Schlüssel kann nun in die eckigen
      // Klammern geschrieben werden. Danach folgt ein
      // weiteres Klammerpaar, in dem die Ziel-Eigenschaft,
      // der "extract", steht. Siehe #3
      Json::Value page = pages[pageName]["extract"];
      std::string extract = page.asString();
      std::cout << extract << std::endl;
    }
    else
    {
      std::cerr << "HTTP status: " << result->status
        << " - " << result->reason << std::endl;
    }
  }
  else
  {
    // Server nicht erreicht
    std::cerr << "Verbindungsfehler" << std::endl;
  }
  return 0;
}

11_4_1_NetzwerkGUI.cpp

Datei herunterladen

#include <json/json.h>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <string>
#include <iostream>
#include <nana/gui.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/textbox.hpp>
#include <nana/gui/widgets/button.hpp>

int main()
{
  // Ein Nana-Formular als Basis des Fensters anlegen
  nana::form window;
  window.caption("Wikipedia-Suche");

  // Die GUI-Elemente anlegen
  nana::label txt(window);
  txt.text_align(nana::align::center, nana::align_v::center);
  nana::textbox input(window);
  input.multi_lines(false);
  nana::button button(window, "Senden");

  // Das Label dem Layout hinzufügen
  window.div("vertical"
    "<txt margin=10>"
    "<height=30 <input><button fit>>");
  window["txt"] << txt;
  window["input"] << input;
  window["button"] << button;
  window.collocate();

  // Mit dem deutschen Wikipedia-Server reden
  httplib::Client client("https://de.wikipedia.org");
  client.set_follow_location(true);

  // API-Optionen wählen, die einen kurzen Absatz liefern
  const std::string wikiApi = "/w/api.php?action=query&redirects=1"
    "&format=json&utf8=1&prop=extracts&explaintext=1&exsentences=2"
    "&titles=";

  button.events().click([&]() {
    if (input.text().empty())
    {
      // Kein Suchtext vorhanden. Nichts machen
      return;
    }
    // Das gewünschte Schlüsselwort anhängen
    std::string query = wikiApi + input.text();

    // Get-Anfrage abschicken. Die Methode verlangt leider
    // einen C-String, daher die Umwandlung mittels c_str()
    httplib::Result result = client.Get(query.c_str());
    if (result != nullptr)
    {
      // Server wurde erreicht
      if (result->status / 100 == 2)
      {
        Json::Value answer;
        // Der Reader liest den String in die Variable ein
        Json::Reader().parse(result->body, answer);
        // Aufruf der gewünschten Eigenschaften
        Json::Value pages = answer["query"]["pages"];
        std::string pageName = pages.getMemberNames().at(0);
        Json::Value page = pages[pageName];
        std::string extract = page["extract"].asString();
        // Extract in das Textlabel geben
        txt.caption(extract);
      }
      else
      {
        std::cerr << "HTTP status: " << result->status
          << " - " << result->reason << std::endl;
      }
    }
    else
    {
      // Server nicht erreicht
      std::cerr << "Verbindungsfehler" << std::endl;
    }
  });

  // Fenster anzeigen und Nana starten
  window.show();
  nana::exec();
  return 0;
}

11_4_2_NetzwerkGUIBild.cpp

Datei herunterladen

#include <json/json.h>
#define CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#include <string>
#include <iostream>
#include <nana/gui.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/textbox.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/paint/image.hpp>
#include <nana/gui/widgets/picture.hpp>

std::pair<std::string, std::string> splitUrl(
  const std::string& url)
{
  size_t pos = url.find("//");
  if (pos == std::string::npos)
  {
    return { url, "" };
  }
  // Finde den ersten Slash nach dem Doppelslash
  pos = url.find('/', pos + 2);
  if (pos == std::string::npos)
  {
    return { url, "" };
  }
  return { url.substr(0, pos), url.substr(pos) };
}

nana::paint::image loadImage(const std::string& url)
{
  if (url.size() == 0)
  {
    // Nichts zum Herunterladen. Leeres Bild zurückgeben
    return nana::paint::image();
  }

  // Die URL muss in den Server und den Pfad
  // aufgetrennt werden.
  const auto urlParts = splitUrl(url);
  const std::string server = urlParts.first;
  const std::string path = urlParts.second;

  httplib::Client client(server.c_str());
  client.set_follow_location(true);
  httplib::Result result = client.Get(path.c_str());
  if (!result || result->status / 100 != 2)
  {
    // Abfrage fehlgeschlagen. Ein leeres Bild zurückgeben
    std::cerr << "HTTP status: " << result->status
      << " - " << result->reason << std::endl;
    return nana::paint::image();
  }
  // Das Bild aus der Serverantwort auslesen
  nana::paint::image image;
  image.open(result->body.c_str(), result->body.size());
  return image;
}

int main()
{
  // Ein Nana-Formular als Basis des Fensters anlegen
  nana::form window;
  window.caption("Wikipedia-Suche");

  // Die GUI-Elemente anlegen
  nana::label txt(window);
  txt.text_align(nana::align::center, nana::align_v::center);
  nana::textbox input(window);
  input.multi_lines(false);
  nana::button button(window, "Senden");
  nana::picture picture(window);
  picture.align(nana::align::center, nana::align_v::center);

  // Das Label dem Layout hinzufügen
  window.div("vertical"
    "<picture height=50>"
    "<txt margin=10>"
    "<height=30 <input><button fit>>");
  window["picture"] << picture;
  window["txt"] << txt;
  window["input"] << input;
  window["button"] << button;
  window.collocate();

  // Mit dem deutschen Wikipedia-Server reden
  httplib::Client client("https://de.wikipedia.org");
  client.set_follow_location(true);

  // API-Optionen wählen, die einen kurzen Absatz sowie
  // "pageimages" liefern.
  const std::string wikiApi = "/w/api.php?action=query&redirects=1"
    "&format=json&utf8=1&prop=extracts|pageimages&explaintext=1"
    "&exsentences=2&pilicense=any&titles=";

  button.events().click([&]() {
    if (input.text().empty())
    {
      // Kein Suchtext vorhanden. Nichts machen
      return;
    }
    // Das gewünschte Schlüsselwort anhängen
    std::string query = wikiApi + input.text();

    // Get-Anfrage abschicken. Die Methode verlangt leider
    // einen C-String, daher die Umwandlung mittels c_str()
    httplib::Result result = client.Get(query.c_str());
    if (result != nullptr)
    {
      // Server wurde erreicht
      if (result->status / 100 == 2)
      {
        Json::Value answer;
        // Der Reader liest den String in die Variable ein
        Json::Reader().parse(result->body, answer);
        // Aufruf der gewünschten Eigenschaften
        Json::Value pages = answer["query"]["pages"];
        std::string pageName = pages.getMemberNames().at(0);
        Json::Value page = pages[pageName];
        std::string extract = page["extract"].asString();
        // Extract in das Textlabel geben
        txt.caption(extract);

        // Artikelbild laden und anzeigen
        Json::Value thumbnail = page["thumbnail"]["source"];
        std::string thumbnailUrl = thumbnail.asString();
        picture.load(loadImage(thumbnailUrl));
      }
      else
      {
        std::cerr << "HTTP status: " << result->status
          << " - " << result->reason << std::endl;
      }
    }
    else
    {
      // Server nicht erreicht
      std::cerr << "Verbindungsfehler" << std::endl;
    }
  });

  // Fenster anzeigen und Nana starten
  window.show();
  nana::exec();
  return 0;
}

11_5_1_Serialisierung.cpp

Datei herunterladen

#include <json/json.h>
#include <iostream>
#include <string>

struct Question
{
  std::string question;
  std::string answer;
  int category = 0;
  void read(const std::string& str)
  {
    // Deserialisierung: Auslesen aus einem String
    Json::Value jsonObj;
    Json::Reader().parse(str, jsonObj);
    // Abruf der gewünschten Eigenschaften
    question = jsonObj["question"].asString();
    answer = jsonObj["answer"].asString();
    category = jsonObj["category"].asInt();
  }
  std::string write() const
  {
    // Serialisierung: Abspeichern in einem String
    Json::StreamWriterBuilder factory;
    Json::Value jsonObj;
    jsonObj["question"] = question;
    jsonObj["answer"] = answer;
    jsonObj["category"] = category;
    return Json::writeString(factory, jsonObj);
  }
};

int main()
{
  Question q1;
  q1.question = "Was macht es?";
  q1.answer = "Es leuchtet blau";
  q1.category = 2;
  std::cout << q1.write() << std::endl;
  Question q2;
  q2.read(q1.write());
  std::cout << q2.write() << std::endl;
  return 0;
}

11_5_2_SerialisierungAbstract.cpp

Datei herunterladen

#include <json/json.h>
#include <iostream>
#include <string>

struct SerializableType
{
  virtual std::string write() const = 0;
  virtual void read(const std::string& str) = 0;
};

struct Question : public SerializableType
{
  std::string question;
  std::string answer;
  int category = 0;
  void read(const std::string& str) override
  {
    // Deserialisierung: Auslesen aus einem String
    Json::Value jsonObj;
    Json::Reader().parse(str, jsonObj);
    // Abruf der gewünschten Eigenschaften
    question = jsonObj["question"].asString();
    answer = jsonObj["answer"].asString();
    category = jsonObj["category"].asInt();
  }
  std::string write() const override
  {
    // Serialisierung: Abspeichern in einem String
    Json::StreamWriterBuilder factory;
    Json::Value jsonObj;
    jsonObj["question"] = question;
    jsonObj["answer"] = answer;
    jsonObj["category"] = category;
    return Json::writeString(factory, jsonObj);
  }
};

struct User : public SerializableType
{
  std::string name;
  int id = 0;
  void read(const std::string& str)  override
  {
    Json::Value jsonObj;
    Json::Reader().parse(str, jsonObj);
    name = jsonObj["name"].asString();
    id = jsonObj["id"].asInt();
  }
  std::string write() const override
  {
    Json::StreamWriterBuilder factory;
    Json::Value jsonObj;
    jsonObj["name"] = name;
    jsonObj["id"] = id;
    return Json::writeString(factory, jsonObj);
  }
};

void printOnConsole(const SerializableType& type)
{
  std::cout << type.write() << std::endl;
}

int main()
{
  Question q1;
  q1.question = "Was macht es?";
  q1.answer = "Es leuchtet blau";
  q1.category = 2;
  std::cout << q1.write() << std::endl;
  Question q2;
  q2.read(q1.write());
  std::cout << q2.write() << std::endl;

  User user;
  user.name = "Manfred";
  user.id = 17;
  std::cout << user.write() << std::endl;

  printOnConsole(q1);
  printOnConsole(q2);
  printOnConsole(user);
  return 0;
}