C++ Academy · Oppitunti

TCP-kaikupalvelimen rakentaminen

Tutustu täydellisen TCP-kaikupalvelimen toteutukseen vaihe vaiheelta.

Oppitunti 2/414 vaihetta

TCP-kaikupalvelimen rakentaminen on ilmainen C++ Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu C++ Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C++ Academy-kurssilla on yhteensä 4 oppituntia.

Tavoite

Rakentakaa minimaalinen TCP-palvelin, joka hyväksyy yhteyden, lukee tavuja ja kirjoittaa ne takaisin. Tämä on verkko-ohjelmoinnin "Hello World".

Palvelimen runko

Palvelimen toimintaketju on seuraava: luokaa socket, sitokaa se osoitteeseen, alkakaa kuunnella, hyväksykää yhteys ja käsitelkää se. Toistakaa tätä loputtomasti.

int srv = socket(AF_INET, SOCK_STREAM, 0);
bind(srv, (sockaddr*)&addr, sizeof(addr));
listen(srv, 10);
while (true) {
    int client = accept(srv, nullptr, nullptr);
    handle(client);
    close(client);
}

Osoitteen uudelleenkäyttöasetus

Asettakaa SO_REUSEADDR, jotta palvelin voi käynnistyä uudelleen heti ilman, että käyttöjärjestelmän portin vapauttamista tarvitsee odottaa.

int yes = 1;
setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

Kaikusilmukka

Lukekaa data puskuriin ja kirjoittakaa samat tavut takaisin. Lopettakaa, kun asiakas sulkee yhteyden.

void handle(int client) {
    char buf[1024];
    while (true) {
        ssize_t n = recv(client, buf, sizeof(buf), 0);
        if (n <= 0) break;          // closed or error
        send(client, buf, n, 0);
    }
}

Osittaiset luku- ja kirjoitusoperaatiot

Sekä recv että send voivat siirtää pyydettyä määrää vähemmän tavuja. Suoratoistopohjaisessa protokollassa jatkakaa silmukassa, kunnes kaikki on käsitelty.

ssize_t total = 0;
while (total < n) {
    ssize_t s = send(client, buf + total, n - total, 0);
    if (s <= 0) break;
    total += s;
}

Useiden asiakkaiden käsittely

Yksinkertaisin lähestymistapa on luoda jokaiselle yhteydelle uusi säie. Se toimii sadoilla asiakkailla, mutta alkaa takellella tuhansien asiakkaiden kohdalla.

while (true) {
    int client = accept(srv, nullptr, nullptr);
    std::thread([client]{ handle(client); close(client); }).detach();
}

Parempi ratkaisu: säiepooli

Säikeen luominen jokaista yhteyttä varten tuhlaa resursseja suuressa mittakaavassa. Kiinteä säiepooli ja työjono skaalautuvat paremmin.

Hallittu sammutus

Käsitelkää SIGTERM- ja SIGINT-signaalit, jotta kuunteleva socket voidaan sulkea siististi. RAII auttaa varmistamaan, että myös kaikki asiakkaiden socketit suljetaan.

Virheenkäsittely

Käsitelkää virheet odotettuina tilanteina: asiakkaat katkaisevat yhteyksiä, verkossa esiintyy häiriöitä ja käyttöjärjestelmän rajat tulevat vastaan. Kirjatkaa virhe ja jatkakaa — älkää kaatako palvelinta virheellisen asiakkaan vuoksi.

Jokaisen asiakkaan kirjaaminen

Kirjatkaa etäosoite järjestelmän havainnoitavuutta varten.

sockaddr_in remote{};
socklen_t len = sizeof(remote);
int client = accept(srv, (sockaddr*)&remote, &len);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &remote.sin_addr, ip, sizeof(ip));
std::cout << "client " << ip << ":" << ntohs(remote.sin_port);

Testaus netcatilla

Testatkaa kaikupalvelinta vuorovaikutteisesti komennolla nc.

nc 127.0.0.1 8080
hello
hello       # echoed back

Kaikua pidemmälle

Kaikupalvelusta voi laajentaa esimerkiksi seuraaviin käyttötarkoituksiin:

  • Rivipohjaiset protokollat (HTTP:n kaltaiset)
  • Kehystetyt binääriprotokollat (pituuden sisältävä etuliite)
  • JSON- tai Protobuf-viestit

Pikatarkistus

Mikä on socket-asetuksen SO_REUSEADDR tarkoitus?

Kertaus

Minimaalinen TCP-kaikupalvelin koostuu seuraavista vaiheista: socket, setsockopt SO_REUSEADDR, bind sekä kuuntelu ja accept silmukassa. Useita asiakkaita varten luokaa säikeitä tai käyttäkää säiepoolia. Suurissa kuormissa siirtykää asynkroniseen I/O:hon (seuraava oppitunti).

Aloita maksutta

Opi C++ tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
51
Oppitunnit
203

Usein kysytyt kysymykset

Onko oppitunti ”TCP-kaikupalvelimen rakentaminen” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa C++ Academy-oppimispolun 3 oppituntia, myös oppitunnin “TCP-kaikupalvelimen rakentaminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. C++ Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”TCP-kaikupalvelimen rakentaminen”?

Tutustu täydellisen TCP-kaikupalvelimen toteutukseen vaihe vaiheelta. Harjoittelet C++ Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni C++ Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin C++ Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”TCP-kaikupalvelimen rakentaminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä C++ Academy-oppitunnilla?

Kyllä. Jokainen C++ Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. BSD Sockets API C++:ssa
  2. TCP-kaikupalvelimen rakentaminen
  3. Asynkroninen I/O epollilla ja kqueuella
  4. Boost Asion käyttö nykyaikaiseen asynkroniseen I/O:hon
← Takaisin: C++ Academy