Streams und Asynchrone Sockets



  • Hallo!
    Ich bin gerade dabei, eine kleine Socket-Library für Windows zu bauen. Dabei wollte ich diese ein wenig an die iostreams anlehnen. Da ich die Library nach dem Interface orientiere und aufbauen will, stelle ich es mal für einen Echo-Server vor und würde mich über Kritik freuen.

    class slot {
    public:
    	void accept(net::sockbuf& io) {
    		io.receive(); // Starte asynchrones Empfangen
    	}
    };
    
    struct slot_receive {
    	// Daten wurden empfangen
    	void operator()(net::netstream& nio) {
    		std::string msg;
    		nio >> msg; // ließ aus Stream heraus
    		nio << msg << std::flush; // sende zurück
    	}
    };
    
    void slot_send(net::netstream& nio) {
    	nio.disconnect(); // Verbindung trennen, wenn Übertragung fertig
    }
    
    int main(int argc, char** argv) {
    	net::netport port(30052, net::address::all); // Erstelle Netport auf Port 30052 und akzeptiere jede Verbindung
    
    	// Lege Slots für Verbindungs- und Nachrichtenempfang fest
    	port::signal::accept.connect(std::fun_ptr(&slot::accept));
    	port::signal::receive.connect(slot_receive());
    	port::signal::send.connect(slot_send);
    
    	port.execute(); // Starte den Port
    }
    


  • Gibt es noch mehr zu sehen? Mir ist die Funktionsweise von netport nicht klar. Woher wissen die connect -Aufrufe etwas vom benutzten Port ( netport port ) und wie erfährt man zum Beispiel, von wo man etwas empfangen hat?
    Für etwas mehr Übersicht könnte man das Empfangen auch so machen:

    struct slot_receive {
        // Daten wurden empfangen
        void operator()(net::sockbuf& io) {
            std::string msg;
    
    		net::istream in(io.inbuf());
            in >> msg; // lies aus Stream heraus
    
    		net::ostream out(io.outbuf());
            out << msg << std::flush; // sende zurück
        }
    };
    


  • Hm ja, ist eine Idee. Allerdings werde ich die Unterteilung in in/outbuf nicht noch einmal extra benötigen, denke ich. Der Netport soll einen IO-Completion-Port abstrahieren, der mit mehreren Workerthreads arbeitet. Einen treffenderen Namen suche ich für ihn noch. Er ist sozusagen dafür verantwortlich, die sockbufs asynchron füllen zu lassen, ihnen die Informationen der Verbindung (z.B. IP-Addresse) zu übergeben und die signals auf zu rufen. Ich kann es ja noch einmal genauer fassen:

    class slot {
    public:
        void accept(net::sockbuf& io) {
            io.receive(); // Starte asynchrones Empfangen, das gefällt mir aber noch nicht
            // etwas wie das:
            /*
            std::string msg;
            std::istream nin(&io);
            nin >> msg
            */ 
            // ist leider nicht möglich, da der Operator >> nicht blockieren darf
        }
    };
    
    struct slot_receive {
        // Daten wurden empfangen, liegen also im gegebenen Puffer
        void operator()(net::sockbuf& buf) {
            std::ostream nout(&buf);
            nout.sync(); // leere Puffer = Senden, was angekommen ist, Vorteil: Umschaufeln in Puffer/String erspart
            // alternativ: nout << std::flush
        }
    };
    
    // Die Nachricht wurde endgültig versand
    void slot_send(net::sockbuf& buf) {
        std::stringstream sstr("Der Server verabschieded sich. Tschuess, ");
        sstr << buf.ip() << "!\n";
        // Schiebe Text in den Puffer, Destruktor von buf flusht den Puffer
        buf.xsputn(sstr().str().c_str(), sstr().str().c_str().length());
        buf.disconnect(); // Verbindung trennen, wenn Übertragung fertig
    }
    
    int main(int argc, char** argv) {
        net::netport port(30052, net::address::all); // Erstelle Überwachungsport auf Port 30052 und akzeptiere jede Verbindung
    
        // Lege Slots für Verbindungs- und Nachrichtenempfang fest
        port::signal::accept.connect(std::fun_ptr(&slot::accept));
        port::signal::receive.connect(slot_receive());
        port::signal::send.connect(slot_send);
    
        port.execute(); // Starte den Port in einem Thread, Programmfluss geht weiter
    }
    

Anmelden zum Antworten