Socketklasse von istream und ostream ableiten?
-
Guten Abend,
Ich würde gerne eine Socketklasse von std::istream und std::ostream ableiten, damit ich den Socket ganz einfach als solchen verwenden kann. Das hat den Vorteil, dass ich Zwischen Tastatur/Bildschirm Files oder Netzwerk ganz einfach wechseln kann - zum Testen praktisch.
Meine Frage nun: Was muss ich dafür tun, damit der operator << / >> mit meinem Socket arbeitet?
-
Ich hab's zwar auch noch nicht praktisch gemacht, aber der Ansatzpunkt für dich dürfte der Stream-Buffer sein. Definier dir eine eigene von streambuf abgeleitete Klasse, die die Methoden overflow() (für die Ausgabe) und underflow() (für die Eingabe) auf die Socket-Funktionen umleiten. Dann kannst du normale Streams verwenden und diesen Puffer darunterhängen.
PS: Ist zwar nur recht kurz angerissen, aber in meinem Magazin-Artikel zu den Streams findest du zumindest einen Ansatzpunkt.
-
Okay, mir ist jetzt klar was ich tun muss. Allerdings erschließt sich mir das Wie nicht. Kann mir dabei jemand helfen?
-
Hab ich da irgendwas verpasst oder was spricht dagegen sich einfach eine Socket Klasse zu machen, << und >> für std::vector<char> zu überladen und dann immer bis zu max. vector.size() zu empfangen
(Dann kann man sich ja auch noch was für std::string basteln, und fertig.)
-
Dagegen spricht, dass es nicht einfach austauschbar ist gegen z.B. std::cin oder einen std::fstream.
-
314159265358979 schrieb:
Okay, mir ist jetzt klar was ich tun muss. Allerdings erschließt sich mir das Wie nicht. Kann mir dabei jemand helfen?
Was meinst du mit dem "wie"? Kommst du zufällig an das hier heran: The C++ Standard Library | ISBN: 0201379260
@cookie: Wenn du dich in die iostream-Hierarchie einklinkst, kannst du ohne weiteren Aufwand alles über's Netz schicken, was du auch durch eine Datei leiten kannst. Da steckt ein wenig mehr dahinter als nur ein paar Operatoren zu überladen
-
Mir ist nicht klar, was diese Methoden tun und wo ich denn die Daten sende/empfange. Zum Buch... leider nicht.
-
Der Stream kümmert sich als erstes um die Formatierung (unter Mithilfe der IO-Operatoren und Locales) und schickt die Ausgaben dann in Textform an den darunterliegenden Puffer. Dieser kann noch einen eigenen Zwischenspeicher definieren und wenn der voll ist, ruft er die Methode overflow() auf, die die Daten tatsächlich nach außen übergibt:
class outbuf : public streambuf { char out_buffer[BUFLEN]; public: //Konstruktor - setzt den internen Zwischenspeicher outbuf() { setp(out_buffer, out_buffer+BUFLEN-1); } virtual ~outbuf() { sync(); } protected: // die eigentliche Ausgabe-Funktion int flushBuffer() { int num = pptr()-pbase(); if( write(out_buffer,num)!=num ) //bzw. dein send-Aufruf return EOF pbump(-num); return num; } //overflow() - wird ausgelöst, wenn der Zwischenspeicher voll ist virtual int_type overflow(int_type c) { if(c!=EOF) { *pptr()=c; pbump(1); } if(flushBuffer()==EOF) return EOF; return c; } virtual int sync() { if(flushBuffer()==EOF) return -1; return 0; } };
(das habe ich jetzt aus dem Jossutis übernommen und bislang behandelt es nur die Ausgabe)
Die Eingabe funktioniert im Prinzip genau andersherum - der Buffer verwendet die Methode underflow(), um einen Zwischenspeicher zu füllen und liefert anschließend den Inhalt des Speichers an den Stream. Allerdings ist die Verwaltung dort ein wenig komplizierter, weil du auch mit ungetc() und ähnlichen Scherzen rechnen mußt.
-
Hier noch zwei existierende Implmenationen zum Thema:
http://socketstream.sourceforge.net/
http://members.aon.at/hstraub/linux/socket++/
-
Diese Implementierungen haben alle einen eigenen sockbuf und sockstream, wozu?
-
314159265358979 schrieb:
Diese Implementierungen haben alle einen eigenen sockbuf und sockstream, wozu?
Ich kenne die Implementierungen nicht, aber im Allgemeinen macht man das so aus dem selben Grund warum es einen std::ifstream oder std::ofstream gibt. Der sockbuf macht das eigentliche IO von einzelnen Zeichen und der sockstream ist ein std::istream (oder ein std::ostream oder beides) und nimmt lediglich den sockbuf als Member auf und stellt einen Konstruktor zur Verfügung, der dem Anwender das Leben etwas erleichtert.
Ein Beispiel findest Du hier in der Implementierung von OFStream.
Gruß
Werner
-
314159265358979 schrieb:
Ich würde gerne eine Socketklasse von std::istream und std::ostream ableiten,
314159265358979 schrieb:
Diese Implementierungen haben alle einen eigenen [...] sockstream, wozu?
Irgendwie frage ich mich nach den beiden Fragen, was du denn jetzt wirklich willst.
Den sockbuf braucht man, weil der streambuffer nunmal das Herz jeder Streamklasse ist. Die fstreams haben einen filebuf, stringstreams einen streambuf - und sockstreams einen sockbuf.Wenn du auch nicht an das oben genannte Buch rankommst, solltest du evtl. mal im Netz nach Literatur suchen, die dir erklärt, wie die Streams aufgebaut sind und arbeiten. Evtl auch mal in deinen Standard-Headern schmökern.
-
Ich möchte in meinem Programm etwas ähnlich diesem schreiben können:
int main() { std::istream input; // Kann eine File, stdin, ein Socket, etc sein std::ostream output; // same here // Tu was mit input und output }
Brauche ich dazu jetzt also auch einen sockstream oder reicht ein sockbuf?
-
314159265358979 schrieb:
Ich möchte in meinem Programm etwas ähnlich diesem schreiben können:
int main() { std::istream input; // Kann eine File, stdin, ein Socket, etc sein std::ostream output; // same here // Tu was mit input und output }
Brauche ich dazu jetzt also auch einen sockstream oder reicht ein sockbuf?
Äääh!
- hast Du meinen Beitrag nebst Link gelesen und hast Du noch Fragen dazu?
-
Gelesen. Und ich verstehe so gut wie gar nichts von dem Gedöns
-
314159265358979 schrieb:
Brauche ich dazu jetzt also auch einen sockstream oder reicht ein sockbuf?
Es reicht ein Stream-Buffer.
Die eigene Stream-Klasse bietet man meist zwecks Bequemlichkeit an, da man Stream und Stream-Buffer normalerweise gemeinsam erzeugt und entsorgt.
-
Nimm Boost.Iostreams.
Damit lassen sich sehr einfach STL-kompatible Streams schreiben.Alternativ könntest du gleich aus Boost.Asio boost::asio::ip::tcp::iostream verwenden, der exakt das macht was du möchtest.
-
Ethon schrieb:
Alternativ könntest du gleich aus Boost.Asio boost::asio::ip::tcp::iostream verwenden, der exakt das macht was du möchtest.
Danke, genau das, was ich gesucht habe
-
314159265358979 schrieb:
Danke, genau das, was ich gesucht habe
An wen ist das
jetzt gerichtet?
-
Naja, sonst wird hier auch immer direkt gesagt, dass man etwas versucht, das man anderes besser lösen könnte. Den direkten Hinweis auf die Klasse hab ich vermisst
Aber danke für die Hilfe, eigentlich gibts doch gar keinen Grund mehr, die "rohen" TCP Sockets zu verwenden, oder?