Jodocus :: eine kleine Windows-Library



  • Hallo!

    Ich möchte hier mein kleines Hobbyprojekt vorstellen: eine Library mit dem Namen Jodocus. Bis jetzt ist sie auf Windows beschränkt und umfasst folgende Bereiche:

    • Multithreading und Synchronisation
    • Asynchrone Netzwerkprogrammierung
    • Audio Ein-/Ausgabe mit PCM

    Ich habe sie in so viel Template-C++0x programmiert, wie Visual Studio 2010 hergibt. Sie untersützt Unicode natürlich komplett. Am meisten Mühe habe ich mir mit dem Socket-Teil gegeben, dort sind I/O-Completionports gewrapped, die auf Overlapped I/O-Basis arbeiten mit dual stack Sockets (also IPv6-Sockets, die mit IPv4 kommunizieren können). Ferner noch ist der dortige acceptor() mit einer Burst-Detection ausgestattet, sodass ein Server automatisch mehr accept()-Aufrufe bereitstellt, wenn der Ansturm groß wird.

    Leider konnte ich noch keine kleinen Beispiel-Codes schreiben, da ich mit der Doku beschäftigt bin.
    Wer sich interessiert:
    **Download
    Dokumentation auf Englisch
    **

    Installation: Einfach das Projekt mit VS 2010 öffnen und kompilieren. Im Debug/Release-Ordner liegt dann eine jodocus.lib. Die muss dann zum eigenen Projekt dazugelinkt werden. Die nötigen Header (jodocus.hpp, net/net.hpp, audio/sound.hpp) finden sich ebenfalls im Projektordner.

    Über ein Feedback würde ich mich sehr freuen. 🤡

    Edit: Mist, um die Uhrzeit hab ich das richige Forum nicht getroffen. Wie peinlich.



  • Hier ein erstes, kleines Beispiel (nur kompilierbar, wenn jodocus.lib dazugelinkt wird und Standard-Includepfade festgelegt wurden).

    #include <jodocus/net/het.hpp>
    #include <iostream>
    #include <string>
    #define THREADED	// used to show that a procedure is called in a separate thread
    
    typedef jodocus::net::ip::tcp tcp;
    
    // declare the connect handler
    void THREADED on_connect(unsigned, unsigned);
    
    int main(int argc, char** argv) {
    	if(argc < 3) {
    		std::cout << "Usage: program <servername> <port>" << std::endl;
    		return 0;
    	}
    
    	try {
    		// Step 1: Create a listener object and initialise worker threads, one per CPU
    		jodocus::net::listener listener(jodocus::system().num_cpu);
    
    		// Step 2: Create a socket and associate it with the listener
    		tcp::socket socket(listener);
    
    		// Step 3: Create a resolver and associate it with the listener
    		tcp::resolver resolver(listener);
    
    		// Step 4: Resolve the address
    		auto iterator = resolver.resolve(argv[1], argv[2]);
    
    		// Step 5: Prepare the message
    		jodocus::buffer message(std::string("Hello, Server!"));
    
    		// Step 6: Connect to the selected host
    		socket.connect(*iterator, on_connect, message);
    
    		// Step 7: Keep the program running
    		std::cin.get();
    
    		// Step 8: Perform a graceful shutdown
    		socket.disconnect([] (unsigned, unsigned) { });
    	}
    	catch(const jodocus::net::net_error& error) {
    		std::cerr << "An network error occured! Message: " << error.what() << '\n';
    	}
    	catch(const std::exception& error) {
    		std::cerr << "A general error occured! Message: " << error.what() << '\n';
    	}
    }
    
    // Connect Handler
    void THREADED on_connect(unsigned error, unsigned bytes_transferred) {
    	if(error) {
    		std::cout << "Could not connect to the host!\n";
    		return;
    	}
    	std::cout << "Connection established!\n";
    }
    

    Das ist ein simpler TCP-Client, der sich zu einem angegebenen Server verbindet.


  • Administrator

    Wo ist der Vorteil gegenüber Boost.Asio und Boost.Thread?

    Grüssli



  • Dravere schrieb:

    Wo ist der Vorteil gegenüber Boost.Asio und Boost.Thread?

    Grüssli

    Die Frage stelle ich mir auch gerade...
    Da nutze ich lieber boost::asio direkt. Und habe noch SSL Unterstützung.



  • Dravere schrieb:

    Wo ist der Vorteil gegenüber Boost.Asio und Boost.Thread?

    Vor allem wenn die Lib ein Thread pro Verbindung hat, was man ja heutzutage nicht mehr haben will, da es nicht richtig skaliert. Boost.Asio macht es richtig mit epoll/kqueue/completionports.



  • Vor allem wenn die Lib ein Thread pro Verbindung hat

    Hat sie aber nicht.



  • Mit boost::asio habe ich mich noch nicht so viel beschäftigt, meine Library ist natürlich viel beschränkter.

    Der Accept-Mechanismus z.B. ist bei mir aber etwas anders:

    typedef jodocus::net::ip::tcp tcp;
    
    void accept_handler(unsigned error, unsigned bytes_transferred, std::shared_ptr<tcp::socket> socket_ptr, jodocus::buffer buffer) {
       // mach was
    }
    
    jodocus::net::listener listener(jodocus::system().num_cpu);
    tcp::acceptor acceptor(listener, *tcp::localhost());
    acceptor.start(accept_handler);
    
    ...
    
    acceptor.stop();
    

    Es wird die Verbindung z.B. auf Wunsch erst dann angenommen, sobald mindestens 1 Byte gesendet wurde. Außerdem muss man nicht dauernd selber neue Accept-Aufrufe machen, die machen sich im Hintergrund selbst. Und durch eine Burst-Messung werden eben intern automatisch die Kapazitäten erweitert oder reduziert, um Engpässe zu vermeiden.
    Nutzt asio per default dual-stack Sockets? In meiner Bibliothek ist es verbindlich und abstrahiert IPv4 auf IPv6, es gibt quasi nur IPv6.

    Das Resolving sieht bei asio auch irgendwie umständlich aus mit queries und so. Bei mir ist das irgendwie etwas einfacher (siehe oben). Hat aber bestimmt irgendwo einen Vorteil, sonst wär's vermutlich nicht so organisiert.



  • Ich hab schon öfters mit boost::asio gearbeitet, deine Library sieht aber auch gut aus; ordentlich, das gefällt mir. Werd's mal ausprobieren.


Anmelden zum Antworten