Frage zu boost::asio



  • hiho,

    ich arbeite mich gerade etwas in Boost::asio ein und hätte da zwei Fragen (das tut ist leider nicht so wirklich toll in der boost::doku)

    Der asynchrone Server aus einem der Bsp behandelt mehrere Clients:

    void handle_accept(tcp_connection::pointer new_connection,
          const boost::system::error_code& error)
      {
        if (!error)
        {
          new_connection->start();
          start_accept();
        }
      }
    

    In dem Start ist ein asynch_read drinne. Da wäre meine Frage eher netzwerktechnsicher Natur: Kann ein Server auf einem Socket, also einer Port-Nr, einfach so mehrere Clients händeln? Durch das asynch_write kehrt ja das start sofort zurück. Was ist also, wenn der read noch nicht alle ist, aber durh das start_accept der Server auf dem Port, wo noch geschrieben wird, schon neue eingehende Verbindungen erwartet?

    Zweite Frage ist das Lesen: bei größeren Sachen macht das irgendwie Probs. Jetzt habe ich in Socket-Tuts gelesen, dass die recv-Funktion nru maximal 1KB empfangen kann am Stück. Gilt das auch für asio?

    MfG Pellaeon



  • Es gibt ein Listen Socket, welches die Verbindungen akzeptieren kann.
    Wenn dann eine Verbindung akzeptiert wurde, wird ein neues Socket erzeugt, das Client Socket.

    Simon

    Edit:

    Zweite Frage ist das Lesen: bei größeren Sachen macht das irgendwie Probs. Jetzt habe ich in Socket-Tuts gelesen, dass die recv-Funktion nru maximal 1KB empfangen kann am Stück. Gilt das auch für asio?

    Das 1kb ist ungefähr die MTU (welche bei TCP bei ca. 1500Bytes liegt). Das heisst aber nicht, dass recv(..) oder die boost Funktionen nur soviel empfangen können.

    [Sorry, war vorher etwas unklar.]



  • Pellaeon schrieb:

    hiho,

    ich arbeite mich gerade etwas in Boost::asio ein und hätte da zwei Fragen (das tut ist leider nicht so wirklich toll in der boost::doku)

    Der asynchrone Server aus einem der Bsp behandelt mehrere Clients:

    void handle_accept(tcp_connection::pointer new_connection,
          const boost::system::error_code& error)
      {
        if (!error)
        {
          new_connection->start();
          start_accept();
        }
      }
    

    In dem Start ist ein asynch_read drinne. Da wäre meine Frage eher netzwerktechnsicher Natur: Kann ein Server auf einem Socket, also einer Port-Nr, einfach so mehrere Clients händeln?

    TCP abstrahiert eine 1:1-Verbindung, also nein. In Deinem Beispiel von oben sollte aber das new_connection -Objekt einen neuen Socket angelegen.

    Pellaeon schrieb:

    Durch das asynch_write kehrt ja das start sofort zurück. Was ist also, wenn der read noch nicht alle ist, aber durh das start_accept der Server auf dem Port, wo noch geschrieben wird, schon neue eingehende Verbindungen erwartet?

    Das hängt davon ab, was Du treibst. Bei einem io_service werden die Handler garantiert sequentiell ausgeführt.
    Wenn ich mich recht entsinne, musste man aber für solche Sachen wie Threadpools Strands benutzen.

    Pellaeon schrieb:

    Zweite Frage ist das Lesen: bei größeren Sachen macht das irgendwie Probs. Jetzt habe ich in Socket-Tuts gelesen, dass die recv-Funktion nru maximal 1KB empfangen kann am Stück. Gilt das auch für asio?

    Da solltest Du Dir keine Gedanken drüber machen. async_read packt die eingehenden Daten in die übergebenen Puffer, bis diese entweder voll sind, oder ein Fehler auftritt. Ob das an irgendeiner Stelle häpchenweise passiert, ist für den Benutzer normalerweise irrelevent. Aus seiner Sicht kommt ein kontinuierlicher Strom von Bytes (bei TCP).



  • Hiho,

    das Bsp oben ist der asynchrone Daytime_client aus dem Boost-Tut.

    In dem new_connection->start steht folgendes:

    boost::asio::async_write(socket_, boost::asio::buffer(message_),
            boost::bind(&tcp_connection::handle_write, shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred));
    

    Da wird nirgendwo ein neuer Socket angelegt oder eine neue Portnummer vergeben, außer das passiert intern.

    TCP abstrahiert eine 1:1-Verbindung

    Joar das dachte ich ja auch, in dem Unix-Socket-Tut wurde aber nur die Funktion fork() aufgerufen, wodurch ein neuer Thread gestartet wurde, welcher die eingehende Verbindung weiter abhandelt. Der Hauptprozess hat dann weiter auf der alten Portnummer nach neuen Verbindungen gelauscht. Der Kindprozess arbeitete aber auch weiter auf derselben Portnummer. Ich nehem an, unter Windows gibts dann ein äquivalten zu fork().
    Also scheint der intern doch irgendwie auf derselben Port-Nr mehrere Verbindungen zu verwalten und unterscheidet diese dann anhand der anderen eingehenden Adresse? So zumindest mein Eindruck.

    MfG Pellaeon



  • Pellaeon schrieb:

    MfG Pellaeon

    Wo kommt denn socket_ her? Ich bin mir recht sicher, dass ist ein Member einer Klasse connection oder ähnlich. Und davon wird ziemlich sicher für jedes accept eine neue Instanz angelegt (in start_accept evtl.). Also hast Du für jede akzeptierte Verbindung eine neue Instanz von connection und damit auch einen eigenen Socket.
    Und auch unter Unix wird mit eigentlich Kindprozesse geforkt, die jeweils einen eigenen Socket benutzen. Der Listenport (ich denke, den meinst Du) bleibt aber immer der gleiche. Wenn ein Accept abgehandelt wurde, wird aber der Client an den Kindprozess und dessen Socket abgegeben.



  • Tachyon schrieb:

    Wo kommt denn socket_ her? Ich bin mir recht sicher, dass ist ein Member einer Klasse connection oder ähnlich. Und davon wird ziemlich sicher für jedes accept eine neue Instanz angelegt (in start_accept evtl.). Also hast Du für jede akzeptierte Verbindung eine neue Instanz von connection und damit auch einen eigenen Socket.

    OK stimmmt, das habe ich übersehen. Da aber alle Sockets an das acceptor_.async_accept gehen, und bei diesem sich nicht die Port-Nr. ändert, bedeutet das doch, dass alles Sockets auf derselben Server-Port-Nr arbeiten? Denn an dem Acceptor-Objekt ändert sich nix.



  • Pellaeon schrieb:

    Tachyon schrieb:

    Wo kommt denn socket_ her? Ich bin mir recht sicher, dass ist ein Member einer Klasse connection oder ähnlich. Und davon wird ziemlich sicher für jedes accept eine neue Instanz angelegt (in start_accept evtl.). Also hast Du für jede akzeptierte Verbindung eine neue Instanz von connection und damit auch einen eigenen Socket.

    OK stimmmt, das habe ich übersehen. Da aber alle Sockets an das acceptor_.async_accept gehen, und bei diesem sich nicht die Port-Nr. ändert, bedeutet das doch, dass alles Sockets auf derselben Server-Port-Nr arbeiten? Denn an dem Acceptor-Objekt ändert sich nix.

    Siehe meine letze Änderung (sorry, für das viele Rumeditieren).
    Das Annehmen der Verbindungen passiert immer auf dem gleichen (und den Clients bekannten) Socket (okay, den Clients ist Port und IP bekannt, aber darüber definiert sich ja der Socket). Nach der Annahme werden die Verbindungen dann an die zuständigen Sockets abgegeben, und der Acceptor-Port ist wieder frei für neue eingehende Verbindungen.
    Hier gibt es das mal grafisch dargestellt.



  • Hiho,

    erstmal danke für deine Mühe. Also das grundlegende Prinzip, dass der die Verbindung weiterreicht, ist mir ja soweit klar. Mich interessiert halt, wie das dann mit den Ports ist. Ich glaube nicht, dass der neue Socket, den der Server erstellt, eine andere Portnummer hat. Dann bräuchte man ja keine Firewall mehr, sobald so ein Multiclient-Server läuft, weil der beliebig neue Ports für seine Clients öffnet.
    Wenn ich mit dem Debugger reinschaue, ändert sich auch der gesetzte Port beim Server nicht. Also der scheint das echt irgendwie über eine Portnummer zu machen. Was aber wieder meiner mir bekannten Definition von Sockets und TCP/IP widersspricht, siehe oben die 1:1 Verbindung für eine IP:Port-Adresse

    Naja ich such mal noch ein bisschen rum, was ich dazu noch so finde.

    MfG Pellaeon



  • Benutze doch mal TcpView (Sysinternals), ev. wirds klarer.
    Simon


Anmelden zum Antworten