Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: TCP serveri ja clientti

Sivun loppuun

Linkku [27.05.2004 18:18:36]

#

Esimerkki miten TCP-socketteja voi yksinkertaisimmillaan käyttää.

Clienttiin kirjoitettu viesti siirretään serverille, joka tulostaa sen ja lähettää takaisin ja clientti tarkistaa onko data sama mikä lähetettiin.

[EDIT] Nyt toimii kaikilla kun ei ole conio.h käytössä.
Ainakin Dev-C++:n käyttäjien pitää lisätä projektin asetuksista linkkeriin rivi "-lwsock32", jotta socketit toimisivat.

// server.cpp

#include <winsock2.h>
#include <iostream>

using std::cout;
using std::endl;

int VastOtaViesti( SOCKET, void*, size_t );
int Vastaa( SOCKET, const void*, size_t );

int main( )
{
    WSADATA ws;
    SOCKET TCP;
    BOOL opt = TRUE;

    // Otetaan käyttöön winsocket 2.2
    if( WSAStartup( MAKEWORD(2,2), &ws ) != 0 ) {
        cout << "Ei tukea winsocket 2.2:lle";
        WSACleanup();
        return 2;
    }

    // luodaan socket
    if( (TCP = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) == INVALID_SOCKET ) {
        cout << "Ei voi luoda sockettia! Error: " << WSAGetLastError();
        WSACleanup();
        return 3;
    }

    servent* pent;
    if( (pent = getservbyname( "echo", 0 )) == 0 ) {
        cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 4;
    }

    struct sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_port = pent-> s_port;
    sa.sin_addr.s_addr = htonl(INADDR_ANY); // sallitaan yhteys keneltä tahansa

    if( bind( TCP, (sockaddr*) &sa, sizeof(sockaddr_in) ) == SOCKET_ERROR ) {
        cout  << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 5;
    }

    if( setsockopt( TCP, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(BOOL) ) == SOCKET_ERROR )
    {
        cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 6;
    }
    if( listen( TCP, 0 ) == SOCKET_ERROR )
    {
        cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 7;
    }

    SOCKET TCPC;
    sockaddr_in srcaddr;

    int srcaddrlen = sizeof(sockaddr_in);
    cout << "Linkku's %sber TCP server. ", "\x81\x81";
    cout << "Odotetaan yhteytt\x84...\n";

    // Sallitaan sisään tuleva yhteys accept:lla
    if( (TCPC = accept( TCP, (sockaddr*) &srcaddr, &srcaddrlen )) == INVALID_SOCKET )
    {
        cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 8;
    }
    cout << "Yhteys avattu!\n" << "<" << inet_ntoa( srcaddr.sin_addr ) << ">" << endl;


    int iNum = 1, iPit;
    char cBuf[1024];

    while(1)
    {
        // vastaanotetaan viestit
        if( (iPit = VastOtaViesti( TCPC, cBuf, sizeof(cBuf) )) == SOCKET_ERROR ) {
            cout << endl << iNum-1 << " viesti\x84 vastaanotettu!";
            getchar();
            return 9;
        }

        cBuf[iPit] = '\0';
        cout << iNum++ << ": " << iPit << " - " << cBuf << endl;

        if( Vastaa( TCPC, cBuf, iPit ) == SOCKET_ERROR ) {
            cout << "Ei voi vastata viestiin! Error: " << WSAGetLastError();
            WSACleanup();
            getchar();
            return -1;
        }

    }

    getchar();
    // vapautetaan resurssit
    WSACleanup();
    return 0;
}

int VastOtaViesti( SOCKET S, void* cBuf, size_t Palautus )
{
    long expect;
    Palautus = recv( S, (char*) &expect, sizeof(long), 0 );
    expect = ntohl( expect );

    Palautus = recv( S, (char*) cBuf, (size_t) expect, 0 );
    return Palautus;
}

int Vastaa( SOCKET S, const void* cBuffer, size_t iSize )
{
    long len = htonl( (long) iSize );
    send( S, (const char*) &len, sizeof(long), 0 );
    send( S, (const char*) cBuffer, iSize, 0 );
    return 0;
}
// client.cpp


#include <winsock2.h>
#include <iostream>

using std::cout;
using std::endl;
using std::cin;

int Vastaus( SOCKET, void*, size_t );
int LahetaViesti( SOCKET, const void*, size_t );

int main( int ac, char* av[] )
{
    unsigned long N = 0;
    BOOL opt = TRUE;
    HOSTENT* Hostent;
    WSADATA ws;
    SOCKET TCP;

    // Otetaan käyttöön winsocket 2.2
    if(WSAStartup(MAKEWORD(2,2), &ws )!= 0 ) {
        std::cout << "Ei tukea winsocket 2.2:lle!";
        WSACleanup();
        getchar();
        return 2;
    }

    // luodaan TCP socket
    if( (TCP = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) == INVALID_SOCKET ) {
        std::cout << "Ei voi luoda sockettia! Error: " << WSAGetLastError();
        WSACleanup();
        return 3;
    }

    struct sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_port = 0; // otetaan nollasta seuraava vapaa portti
    sa.sin_addr.s_addr = htonl(INADDR_ANY);
    if( bind( TCP, (sockaddr*) &sa, sizeof(sockaddr_in) ) == SOCKET_ERROR ) {
        std::cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 4;
    }
    // Säädetään asetukset
    if( setsockopt( TCP, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(BOOL) ) == SOCKET_ERROR )
    {
        std::cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 5;
    }

    servent* dd;
    if( (dd = getservbyname( "echo", 0 )) == 0 ) {
        std::cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 6;
    }

    sockaddr_in srvaddr;
    srvaddr.sin_family = AF_INET;
    srvaddr.sin_port = dd-> s_port;

    if( (Hostent = gethostbyname("localhost")) != 0 )
        srvaddr.sin_addr.s_addr = *(long*) Hostent-> h_addr;
    else if( (srvaddr.sin_addr.s_addr = inet_addr( av[1] )) == INADDR_NONE ) {
        std::cout << "Socket error: " << WSAGetLastError() ;
        WSACleanup();
        return 7;
    }

    cout << "Linkku's %sber TCP client. ", "\x81\x81";
    cout << "Yhdistet\x84\x84n...\n";

    // Yritetään etsiä serveri
    if( connect( TCP, (sockaddr*) &srvaddr, sizeof(srvaddr) ) == SOCKET_ERROR ) {
        std::cout << "Ei voi yhdist\x84\x84 palvelimeen [palvelin ei ehk\x84 k\x84ynniss\x84]\nError: ";
        std::cout << WSAGetLastError();
        WSACleanup();
        getchar();
        return 8;
    }
    std::cout << "Yhdistetty!\n";
    int iKor = 3;
    while(1)
    {
        char cBuf[1024];
        cout << "\n> " ;
        cin.getline( cBuf, sizeof(cBuf));

        size_t iPit = strlen(cBuf);

        if( iPit==0 ) {
          break;
        }
        N++;

        // siirretään viesti
        if( LahetaViesti( TCP, cBuf, iPit ) == SOCKET_ERROR ) {
            cout << "Ei voi l\x84hett\x84\x84 viesti\x84! Error: " << WSAGetLastError() ;
            WSACleanup();
            getchar();
            return 9;
        }

        char cVBuf[sizeof(cBuf)] = " ";
        size_t rlen = SOCKET_ERROR;
        size_t tlen = strlen(cBuf);

        // odotetaan vastausta
        if( (rlen = Vastaus( TCP, cVBuf, sizeof(cVBuf) )) == SOCKET_ERROR )
        {
            std::cout << "Ei saatu vastausta palvelimelta! Error: " << WSAGetLastError();
            getchar();
            WSACleanup();
            return -1;
        }
        cout << cVBuf << endl;

        // tarkistetaan serverin lähettämä data
        // ei kuitenkaan mikään übervarma tarkistus
        if( rlen != tlen || memcmp( cVBuf, cBuf, rlen ) ) {
            cout << "\nViesti korruptoitunut!\n" ;
        }

    }


    std::cout << "\n\n" << N << " viesti\x84 l\x84hetetty";

    // vapautetaan resurssit
    getchar();
    WSACleanup();
    return 0;
}


int LahetaViesti( SOCKET S, const void* cBuffer, size_t iSize )
{
    long len = htonl( (long) iSize );
    send( S, (const char*) &len, sizeof(long), 0 );
    send( S, (const char*) cBuffer, iSize, 0 );
    return 0;
}

int Vastaus( SOCKET S, void* cBuffer, size_t Palautus )
{
    long expect;
    Palautus = recv( S, (char*) &expect, sizeof(long), 0 );
    expect = ntohl( expect );

    Palautus = recv( S, (char*) cBuffer, (size_t) expect, 0 );
    return Palautus;
}

Heikki [28.05.2004 07:01:03]

#

Mukavan oloinen koodi... Varmasti hyötyä monelle.

kaviaari [28.05.2004 08:05:16]

#

Tosiaan koodi on selkeetä, ja hyötyä löytyy varmasti.

sooda [28.05.2004 16:46:24]

#

Hieno on. Sitten kun tartten c++:ssa winsockia niin käytän varmana tätä apuna. Linkku, oot taitava!

Meitzi [30.05.2004 11:25:23]

#

Arvelin kyllä että ku C:llä kirjotettu että koodia olisi vieläkin enemmän. Ihan mukava pakettihan tuo on.

Koodi taittaa oottaa aina yhteyden localhostiin, tuo muuten aikalailla lisää hasteetta kun tehdään yhteys hitaan yhteyden yli ;)

Linkku, eikös tuossa kannattaisi yhdistää nuo koodit ja ohjelma kysyisi käynnistyksen yhteydessä että onko serveri vai client?

Linkku [30.05.2004 11:38:53]

#

lainaus:

Koodi taittaa oottaa aina yhteyden localhostiin, tuo muuten aikalailla lisää hasteetta kun tehdään yhteys hitaan yhteyden yli ;)

Yhteys otetaan localhostiin ja portista 0 seuraava vapaa portti mulla oli ainakin 7, eli se yhdisti sen kautta.

lainaus:

Linkku, eikös tuossa kannattaisi yhdistää nuo koodit ja ohjelma kysyisi käynnistyksen yhteydessä että onko serveri vai client?

Tämä kävi kyllä mielessä, mutta päädyin nyt tähän.

AdeRide [28.06.2004 01:04:12]

#

Miten WinSocketissa voi määrittää IP:n ja PORTin??? Voisiko joku kirjoittaa pienen esimerkki koodin???? Olisin erittäin kiitollinen siitä!!!!

AdeRide [28.06.2004 03:04:07]

#

Linkku!!! Yritin kääntää ton Serverin, niin kääntäjä itki jotain tuosta gotoxy -lauseesta.

Tarkalleen ottaen se sanoi:

C:\Documents and Settings\Jussi\C++ Testit\systeemi.cpp(99) : error C2065: 'gotoxy' : undeclared identifier

Mistä johtunee??????

Olisi mukava saada vastaus.

Linkku [02.12.2004 08:33:13]

#

AdeRide: Nyt toimii ja ip haetaan tuossa "gethostbyname("localhost")"

AdeRide [02.12.2004 19:41:35]

#

Voiko tuohon serveriin ottaa useampi clientti yhteyden yhtäaikaa, ilman, että serveri sekoaa täysin? Vai onko mahdollista avata yhteys vain yhdelle clientille?

Linkku [04.12.2004 17:38:06]

#

AdeRide: Tähän versioon voi yhdistää vain yksi klientti kerralla. Kehitteillä on toinenkin versio mihin voi yhdistää useampi klientti. Ehkä vielä jonain päivänä postaan sen tänne :)

Touho [08.02.2005 11:21:59]

#

Mulla MSVC++ ärähtää:
Console Source.obj : error LNK2001: unresolved external symbol __imp__WSAGetLastError@0
Console Source.obj : error LNK2001: unresolved external symbol __imp__socket@12
Console Source.obj : error LNK2001: unresolved external symbol __imp__WSACleanup@0
Console Source.obj : error LNK2001: unresolved external symbol __imp__WSAStartup@8
Console Source.obj : error LNK2001: unresolved external symbol __imp__ntohl@4
ja vielä vähän enemmän. Mitä pitäis tehdä?

Linkku [08.02.2005 15:07:19]

#

Linkku kirjoitti:

Ainakin Dev-C++:n käyttäjien pitää lisätä projektin asetuksista linkkeriin rivi "-lwsock32", jotta socketit toimisivat.

teppu [22.07.2005 15:19:19]

#

Toimiiko tuo borlandin c++:lla.

hyyppä [29.11.2005 19:03:13]

#

tuo serveri valittaa jotain "Socket error 11004"

ZcMander [29.05.2006 21:44:10]

#

ei ei ei, ennen recv kannattee käyttää selectiä, entä jos palautusta ei tulekkaan, recv jää blokkaamaan iäisyyksiin.

Jtm [14.06.2007 20:00:36]

#

Socket error 10004 - Interrupted function call
Socket error 10013 - Permission denied
Socket error 10014 - Bad address
Socket error 10022 - Invalid argument
Socket error 10024 - Too many open files
Socket error 10035 - Resource temporarily unavailable
Socket error 10036 - Operation now in progress
Socket error 10037 - Operation already in progress
Socket error 10038 - Socket operation on non-socket
Socket error 10039 - Destination address required
Socket error 10040 - Message too long
Socket error 10041 - Protocol wrong type for socket
Socket error 10042 - Bad protocol option
Socket error 10043 - Protocol not supported
Socket error 10044 - Socket type not supported
Socket error 10045 - Operation not supported
Socket error 10046 - Protocol family not supported
Socket error 10047 - Address family not supported by protocol family
Socket error 10048 - Address already in use
Socket error 10049 - Cannot assign requested address
Socket error 10050 - Network is down
Socket error 10051 - Network is unreachable
Socket error 10052 - Network dropped connection on reset
Socket error 10053 - Software caused connection abort
Socket error 10054 - Connection reset by peer
Socket error 10055 - No buffer space available
Socket error 10056 - Socket is already connected
Socket error 10057 - Socket is not connected
Socket error 10058 - Cannot send after socket shutdown
Socket error 10060 - Connection timed out
Socket error 10061 - Connection refused
Socket error 10064 - Host is down
Socket error 10065 - No route to host
Socket error 10067 - Too many processes
Socket error 10091 - Network subsystem is unavailable
Socket error 10092 - WINSOCK.DLL version out of range
Socket error 10093 - Successful WSAStartup not yet performed
Socket error 10094 - Graceful shutdown in progress
Socket error 11001 - Host not found
Socket error 11002 - Non-authoritative host not found
Socket error 11003 - This is a non-recoverable error
Socket error 11004 - Valid name, no data record of requested type

EDIT:
Vastasinkin näköjään puolitoista vuotta myöhässä :P

neutrian [24.11.2007 15:54:20]

#

Toimiiko tämä esimerkki internetin kautta ?
En itse saanut sitä toimimaan kun pelkästään lanissa.
Eli en oikeen osannut tuosta koodista avata porttia...

Mutta toimiiko toi internetin välityksellä tuo ohjelma ?

DrDeath [30.09.2008 22:14:39]

#

sa.sin_addr.s_addr = htonl(INADDR_ANY);

^^ Eik tuon kuuluisi olla htons? Minulla se toimi ainoastaan näin.

Wusakko [19.04.2010 10:25:39]

#

Voisiko joku laitella esimerkkiä monen clientin käytöstä yhellä serverillä? :)


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta