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; }
Mukavan oloinen koodi... Varmasti hyötyä monelle.
Tosiaan koodi on selkeetä, ja hyötyä löytyy varmasti.
Hieno on. Sitten kun tartten c++:ssa winsockia niin käytän varmana tätä apuna. Linkku, oot taitava!
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?
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.
Miten WinSocketissa voi määrittää IP:n ja PORTin??? Voisiko joku kirjoittaa pienen esimerkki koodin???? Olisin erittäin kiitollinen siitä!!!!
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.
AdeRide: Nyt toimii ja ip haetaan tuossa "gethostbyname("localhost")"
Voiko tuohon serveriin ottaa useampi clientti yhteyden yhtäaikaa, ilman, että serveri sekoaa täysin? Vai onko mahdollista avata yhteys vain yhdelle clientille?
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 :)
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 kirjoitti:
Ainakin Dev-C++:n käyttäjien pitää lisätä projektin asetuksista linkkeriin rivi "-lwsock32", jotta socketit toimisivat.
Toimiiko tuo borlandin c++:lla.
tuo serveri valittaa jotain "Socket error 11004"
ei ei ei, ennen recv kannattee käyttää selectiä, entä jos palautusta ei tulekkaan, recv jää blokkaamaan iäisyyksiin.
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
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 ?
sa.sin_addr.s_addr = htonl(INADDR_ANY);
^^ Eik tuon kuuluisi olla htons? Minulla se toimi ainoastaan näin.
Voisiko joku laitella esimerkkiä monen clientin käytöstä yhellä serverillä? :)
Aihe on jo aika vanha, joten et voi enää vastata siihen.