Serverprogrammierung - Theorie?



  • Ich würde gerne die Serverprogrammierung unter C++ lernen. Fakt ist, dass ich noch nicht viel Erfahrung habe. Deswegen würde ich auch gerne auf Multithreading verzichten - das wird mir nur zu unübersichtlich. Welches Betriebssystem ich nehme weiss ich noch nicht genau. Wie man mit Sockets umgeht weiss ich schon, allerdings würde ich gerne wissen wie man den Code eines Servers strukturiert (Klassendesign etc.). Über Google finde ich nur Anleitungen, wie man Serversockets verwendet, aber das kenn ich schliesslich schon.
    Was Sicherheit angeht: Tipps wären da natürlich hilfreich, aber erstmal will ich meine Programme sowieso nicht ans Internet hängen.
    Gibt es eine Möglichkeit Server mit mehreren Verbindungen ohne Multithreading zu organisieren und wenn ja wie?

    Ob ich damit demnächst anfange weiss ich noch nicht, aber interessieren tut mich das Thema auf jeden Fall...


  • Mod

    Ich würde gerne Bergsteigen in den Alpen lernen. Fakt ist, dass ich noch nicht viel Erfahrung habe. Deswegen würde ich auch gerne auf Bergsteigerausrüstung verzichten - das wird mir nur zu unübersichtlich. Welchen Berg ich nehme weiss ich noch nicht genau. Wie man mit Straßen umgeht weiss ich schon, allerdings würde ich gerne wissen wie man den Weg auf einen Berg findet (Bergführer etc.). Über Google finde ich nur Anleitungen, wie man Straßenkarten verwendet, aber das kenn ich schliesslich schon.
    Was Sicherheit angeht: Tipps wären da natürlich hilfreich, aber erstmal will ich meinen Berg sowieso nicht ganz hinauf gehen.
    Gibt es eine Möglichkeit Berge mit steilen Abhängen ohne Bergsteigerausrüstung zu erklimmen und wenn ja wie?

    Ob ich damit demnächst anfange weiss ich noch nicht, aber interessieren tut mich das Thema auf jeden Fall...

    Wieso denken die Leute eigentlich immer, es wäre alles einfacher, wenn man es nur halbherzig und ohne die richtige Ausrüstung angeht? Wenn dich das Thema interessiert und du das wirklich machen möchtest, dann versuch es auch richtig zu machen. Wenn du schon Angst vor nützlichen Programmiermitteln hast, weil du sie noch nicht kennst, oder wenn du nicht die Motivation hast, dass das Endresultat benutzbar sein soll, dann ist das ein schlechter Anfang.



  • Du kannst mehrere Verbindungen mit select() "überwachen". Trotzdem würde ich Multithreading vorziehen. (Sowohl was Performance, als auch was den Aufwand angeht.) Viel "Interthreadkommunikation" hast du da ja nicht, insofern ist das kein Problem. Mit einem modernen Compiler kannst du sogar C++11 std::thread, std::future etc. nutzen, die sind wirklich leicht zu verwenden.



  • @cookie451 Danke, dass werde ich mir mal angucken. Es geht mir ja nicht um riesige RPG-Server, sonder eher um einen kleinen Pong-Server etc.



  • Sag ich ja. Wenn du wirklich Performance brauchst, willst du eine asynchrone API. 😉
    Multithreading ist schon ok. Relativ wenig Aufwand und trotzdem recht performant.



  • Epic 😃



  • cooky451 schrieb:

    Du kannst mehrere Verbindungen mit select() "überwachen". Trotzdem würde ich Multithreading vorziehen.

    Warum?

    cooky451 schrieb:

    (Sowohl was Performance, als auch was den Aufwand angeht.)

    Der Aufwand ist doch viel höher mit der ganzen Synchronisation. Und schneller wird das dadurch auch nicht automatisch.

    cooky451 schrieb:

    Viel "Interthreadkommunikation" hast du da ja nicht, insofern ist das kein Problem.

    Mehr davon als unbedingt nötig ist immer schlecht. Und hier hätte man sehr wohl nicht-triviale Synchronisation. Mal ganz abgesehen davon, dass man accept und recv nicht abbrechen kann, also kann so ein Programm schwer korrekt terminieren.

    cooky451 schrieb:

    Mit einem modernen Compiler kannst du sogar C++11 std::thread, std::future etc. nutzen, die sind wirklich leicht zu verwenden.

    NOT

    Wenn etwas dabei rauskommen soll, nimm die asynchronen Sockets von Boost.Asio. Und lass bloß die Finger von Threads.



  • TyRoXx schrieb:

    NOT

    Ja... 🙄



  • TyRoXx schrieb:

    Wenn etwas dabei rauskommen soll, nimm die asynchronen Sockets von Boost.Asio. Und lass bloß die Finger von Threads.

    👍

    Wobei ich jetzt nicht unbedingt gegen Threads bin. Aber sicherlich nicht 1 Thread pro Client, das ist Overkill.



  • Immer wieder schön die ganzen fundierten Antworten hier.
    Wo sind eigentlich die Evangelisten abgeblieben? Ich beginne die schon fast zu vermissen...



  • Threads sind reichlich low-level. Da nimmt man dann doch besser etwas höher angesiedelte Funktionalitäten. Leider hats nicht allzu vieles in den Standard geschafft, was darüber liegt. Bestenfalls wäre da noch std::async/std::future zu nennen. Ich denke mal, dass boost.asio ein guter Kompromiss ist, um noch PLattformunabhängig zu bleiben.



  • Also dein Rechner ist sozusagen ein Server. Du kannst ihn auch als Server verwenden nur der verbraucht dann mehr strom als herkömmliche Server. Es gibt auf Windows und Linux Bibliotheken die du verwenden kannst um Informationen zwischen Client und Server zu tauschen. z.B wenn du ein Chat programmierst ist das Chat Fenster der Client und wenn du z.B auf deinem Rechner ein Server aufbaust und dich mit dem Chat Fenster in dem Server verbindest und ein anderer Rechner sich auch mit dem Client in dem Server verbindet kannst du über den Server nachrichten versenden. Du programmierst den Client so das er eine Nachrichten versenden kann der Server muss dann eine Nachricht empfangen können und versendet die Nachricht dann an alle anderen Rechner die auch mit dem Server verbunden sind.

    Wenn ich ein Fehler drin hab bitte verbessern.

    Gruss



  • TyRoXx schrieb:

    Mal ganz abgesehen davon, dass man accept und recv nicht abbrechen kann, also kann so ein Programm schwer korrekt terminieren.

    Erstens könnte man die entsprechenden Sockets in non-blocking Modus versetzen. Aber das ist nicht mal erforderlich, denn zweitens kehren sowohl accept als auch recv zurück, wenn man die entsprechenden Sockets schließt.



  • Belli schrieb:

    TyRoXx schrieb:

    Mal ganz abgesehen davon, dass man accept und recv nicht abbrechen kann, also kann so ein Programm schwer korrekt terminieren.

    Erstens könnte man die entsprechenden Sockets in non-blocking Modus versetzen. Aber das ist nicht mal erforderlich, denn zweitens kehren sowohl accept als auch recv zurück, wenn man die entsprechenden Sockets schließt.

    Was accept oder recv macht, wenn man den Socket schließt, ist meines Wissens nicht spezifiziert. Besser ist es, tatsächlich mit non-blocking zu arbeiten und erst dann accept bzw. recv aufzurufen, wenn auch tatsächlich jemand anklopft.

    Die Entscheidung zwischen asynchron oder multithreaded kann man nicht so einfach beantworten, dass das eine einfacher und das andere schneller ist.

    Also von der Komplexität geben die 2 Modelle sich nicht viel. Beides ist nicht ganz trivial. Einen Server zu implementieren ist halt eben nicht trivial.

    Performancemässig hängt es von der Applikation ab. Wenn ein einzelner Request relativ viel Verarbeitung verursacht, ist es besser, den Request in einen separaten Thread zu verarbeiten, damit andere Verbindungen nicht blockiert werden. Bei wenig Verarbeitung ist in der Regel der asynchrone Ansatz schneller, da kein Kontextwechsel statt findet und keine Synchronisierung notwendig ist.



  • tntnet schrieb:

    Was accept oder recv macht, wenn man den Socket schließt, ist meines Wissens nicht spezifiziert. Besser ist es, tatsächlich mit non-blocking zu arbeiten und erst dann accept bzw. recv aufzurufen, wenn auch tatsächlich jemand anklopft.

    Da kann man auch gleich select nehmen. Oder funktioniert das ganz anders?



  • tntnet schrieb:

    Besser ist es, tatsächlich mit non-blocking zu arbeiten und erst dann accept bzw. recv aufzurufen, wenn auch tatsächlich jemand anklopft.

    Lieber select fragen.

    tntnet schrieb:

    Performancemässig hängt es von der Applikation ab.

    Nö. Asynchrone Modelle dürften immer schneller sein. Nur merkt man das eben erst ab einer ordentlichen Menge Clienten.

    tntnet schrieb:

    Also von der Komplexität geben die 2 Modelle sich nicht viel. Beides ist nicht ganz trivial. Einen Server zu implementieren ist halt eben nicht trivial.

    Doch, ein Pong Server ist extrem trivial. Und genau das ist das Problem. Wo will man bei einem trivialen Problem vernünftige Argumente für Lösungen finden.



  • Asynchrone Verarbeitung und Threads sind keine orthogonalen Konzepte. Man kann auch beides haben.



  • TyRoXx schrieb:

    tntnet schrieb:

    Was accept oder recv macht, wenn man den Socket schließt, ist meines Wissens nicht spezifiziert. Besser ist es, tatsächlich mit non-blocking zu arbeiten und erst dann accept bzw. recv aufzurufen, wenn auch tatsächlich jemand anklopft.

    Da kann man auch gleich select nehmen. Oder funktioniert das ganz anders?

    Das ist doch genau das, worauf ich hinaus wollte. Hätte ich vielleicht direkt darauf hinweisen sollen. Also Socket auf non-blocking und dann mit select warten, bis jemand anklopft. Und im select kann man dann noch eine pipe rein packen, womit ich den select geordnet wecken kann, wenn ich den Server runter fahren möchte.

    cooky451 schrieb:

    tntnet schrieb:

    Performancemässig hängt es von der Applikation ab.

    Nö. Asynchrone Modelle dürften immer schneller sein. Nur merkt man das eben erst ab einer ordentlichen Menge Clienten.

    Das stimmt so nicht. Wenn die Verarbeitung einer Antwort signifikant lange dauert, dann ist das besser, wenn er in einem separaten Thread verarbeitet wird. Ein rein asynchroner Thread läuft auf genau einem Core und wenn ein Request bearbeitet wird, müssen die anderen warten.

    Nehmen wir ein einfaches Rechenmodell: Ein Request kommt an und der Server braucht eine Sekunde, um die Antwort zu generieren. Während er die Antwort generiert, kann er im asynchronen Modell keine weiteren Requests verarbeiten. Er schafft also genau einen Request pro Sekunde. Wird der Request in einem Thread generiert, kann ein anderer Thread bereits den nächsten Request entgegennehmen und verarbeiten. Habe ich dann beispielsweise 8 Cores, kann der multithreaded Server halt 8 Requests pro Sekunde verarbeiten.



  • Man kann immer noch (meine Posts liest ja offenbar niemand) asynchrone IO mit beliebig vielen Threads verwenden. Dein Beispiel ist daher totaler Schwachsinn.



  • tntnet schrieb:

    Also Socket auf non-blocking und dann mit select warten, bis jemand anklopft.

    Genau, erst non-blocking machen, und dann zur Sicherheit noch mal select fragen, das ist ein Plan. 😃

    @threads Das hat dann aber nichts mehr mit I/O Performance zu tun.



  • Ich kapere den thread kurz mal für eine kleine Frage:

    Ich würde gerne einen minichat clienten basteln. Da ich die select variante doof finde, wrde ich gerne threads verwenden.
    Würde zwei threads, je einen für recv und send(main aktualisiert nur das chatfenster), verwenden.
    Kann ich den erstellten socket an die threads übergeben ohne das Fehler passieren? Laut dem was ich gelesen habe funktioniert direkte Übergabe per Referenz nicht, da sich durch die threads(gebe nur wieder was ich gelesen habe), die Speicheradresse(der socketvariable) ändert(oder ändern kann).


Anmelden zum Antworten