boost::asio Problem
-
Hallo Gemeinde, ich habe ein Problem mit boost::asio. Ich möchte eine Client/Server Anwendung schreiben, diese soll eigenltich vorerst mal ganz simpel sein.
Client schickt ein "Hello Server" an den Server. Wenn der Server "Hello Server" empfangen hat, soll der Server "Hello Client" zurück schicken wenn alles geklappt hat, soll das Progamm beendet werde, ansonsten soll der Server nichts machen. Sprich er muss die übermittelten Daten Prüfen um daraud zu reagieren.
Main Problem ist allerdings, Das der Server "Hello Server" empfängt, jedoch Hello Client nicht zurück sendet. Da das ganze Asynchron läuft, habe ich vermutlich da einen Fehler, kann ihn aber nicht finde, vermutlich habe ich die Sache auch falsch angepackt. Anbei ist mein Client und der Server:
Client:
#include <boost/asio.hpp> #include <boost/array.hpp> #include <iostream> #include <string> boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::socket sock(io_service); boost::array<char, 512> buffer; void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) { if (!ec) { std::cout << std::string(buffer.data(), bytes_transferred) << std::endl; sock.async_read_some(boost::asio::buffer(buffer), read_handler); } } void connect_handler(const boost::system::error_code &ec) { if (!ec) { boost::asio::write(sock, boost::asio::buffer("Hello Server")); sock.async_read_some(boost::asio::buffer(buffer), read_handler); } } void resolve_handler(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator it) { if (!ec) { sock.async_connect(*it, connect_handler); } } int main() { boost::asio::ip::tcp::resolver::query query("localhost", "8080"); resolver.async_resolve(query, resolve_handler); io_service.run(); return 0; }Server:
#include <boost/asio.hpp> #include <boost/array.hpp> #include <iostream> #include <string> boost::asio::io_service io_service; boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 8080); boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint); boost::asio::ip::tcp::socket sock(io_service); std::string data = "Hello Client\n"; boost::array<char, 512> buffer; void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) { } void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) { if (!ec) { sock.async_read_some(boost::asio::buffer(buffer), read_handler); std::cout << std::string(buffer.data(), bytes_transferred) << std::endl; if (std::string(buffer.data(), bytes_transferred) == "Hello Server") { boost::asio::async_write(sock, boost::asio::buffer(data), write_handler); } } } void accept_handler(const boost::system::error_code &ec) { if (!ec) { sock.async_read_some(boost::asio::buffer(buffer), read_handler); } } int main() { acceptor.listen(); acceptor.async_accept(sock, accept_handler); io_service.run(); return 0; }Ich bin über jede Hilfe dankbar.
so long
jd
-
Ich bin jetzt zu faul alles genau durchzulesen, aber nur was mir auf die Schnelle aufgefallen ist:
Was passiert, wenn deine Übermittlung aufgestückelt wird? Also beim Server zum Beispiel zuerst ein "Hallo " und danach eine "Server" ankommt.read_handlerwird zweimal ausgeführt, und beide Male stimmt der String nicht überein.Grüssli
-
Ich verstehe worauf du hinaus willst, aber wie vergleiche ist das richtig?
std::cout << std::string(buffer.data(), bytes_transferred) << std::endl;Das steht immer in einer Zeile. Der read_handler ist ja so aufgebaut, das er solange ausgeführt wird, bis der buffer voll ist. Wie vergleiche ich das dann...
Ich habe das jetzt mal mit stringstream versucht:
stream << std::string(buffer.data(), bytes_transferred); if (stream.str() == "Hello Server") { boost::asio::async_write(sock, boost::asio::buffer(data), write_handler); }std::stringstream stream;ist außerhalb definiert, so das nichts überschrieben sondern hinzugefügt wird.
Leider funktioniert das auch nicht. Obwohl ja irgendwann mal alles im stream landen müsste.
if (buffer.data() == "Hello Server") { boost::asio::async_write(sock, boost::asio::buffer(data), write_handler); }klappt auch nicht

Wie kann ich das also richtig vergleichen?
so long
jd
-
Habe jetzt nochmal in der Doku nach gelesen, bin aber leider nicht fündig geworden, was mein Problem angeht, hat jemand von euch noch einen Einfall?
so long
jd
-
jd schrieb:
Habe jetzt nochmal in der Doku nach gelesen, bin aber leider nicht fündig geworden, was mein Problem angeht, hat jemand von euch noch einen Einfall?
So hatte nochmals Zeit, mir das ganze anzuschauen. Hätte fast aufgegeben, da die IDE völlig gesponnen hat, aber bin dem Fehler dann doch auf die Schliche gekommen.
Hier liegt dein Hauptfehler:
boost::asio::buffer("Hello Server")Was passiert hier? Hier wird eine solche Funktion aufgerufen:
template<typename PodType, std::size_t N> /* ... */ buffer(PodType const (&array)[N]) { /* ... */ }"Hello Server"hat den Typchar[13]. Also es wird aus einem C Array mit 13 Elementen ein Puffer erzeugt. Vielleicht wirst du jetzt schon hellhörig und denkst: "13? Das sind doch nur 12 Buchstaben!"
Jedes Stringliteral hat eine Nullterminierung, also eine abschliessende 0. Wenn du nun denstd::stringkonstruiert hast, dann hast du diese 0 mit reingeschoben:std::string(buffer.data(), bytes_transfered);Beim Vergleich mit dem Stringliteral wird diese Nullterminierung beim Literal ignoriert, beim
std::stringObjekt allerdings nicht. Also sind die beiden ungleich.Meinen ersten Tipp würde ich nicht wegwerfen. Du musst bei der Netzwerkprogrammierung extrem aufpassen, vor allem wenn man asynchron kommuniziert. Es ist nicht garantiert, dass immer die ganzen Puffer gleichzeitig ankommen. Die können auch zerstückelt werden, du musst sie also unbedingt vorher wieder zusammenflicken. Dies bedeutet dann auch, dass du ein sinnvolles und stabiles Protokoll definierst, über welches kommuniziert werden kann.
Aber abgesehen von all dem und mal ganz allgemein, der Code ist ziemlich hässlich. Globale variablen, x-fache Code Duplizierung, unnötige Variablen, usw. usf.
Auch deine Versuche den Fehler zu finden, sehen ziemlich nach C++ Anfänger aus und zwar blutiger Anfänger. Zum Beispiel auch das mitbuffer.data() == "Hello Server".
Wäre es vielleicht nicht klüger, wenn du zuerst richtig C++ lernst, bevor du dich an Bibliotheken wie Boost.Asio ranwagst?Grüssli