C++ Netwerk programmeren

  • Onderwerp starter Onderwerp starter Dinux
  • Startdatum Startdatum
Status
Niet open voor verdere reacties.

Dinux

Gebruiker
Lid geworden
20 jan 2010
Berichten
420
Hallo Allemaal,

Ik ben al een klein tijdje bezig met c++. Ik vind het een erg interrestante taal maar ik snap nog lang niet alles. Nu wil ik een connectie maken met een webserver en gewoon de html enzo terug krijgen. Ik heb al veel geprobeerd en gecopieerd van internet maar niets lijkt te werken. Ik gebruik Dev-C++ om mijn scripten in te schrijven en te compileren. Ik heb ook al iets gelezen over het toevoegen van verschillende bestanden aan de compiler maar ik weet dus niet of dat ook echt nodig is en hoe dat moet. Wat ik dus eigenlijk wil is een simpele connectie met een server, bijvoorbeeld een webserver.

Dinux
 
Om verbinding te maken met een webserver kan je gebruik maken van sockets.
Hieronder een link naar tutorial:
http://beej.us/guide/bgnet/

Ook kan een library als libcurl of libwww gebruikt worden.
Hieronder een link naar info over libcurl:
http://curl.haxx.se
Om libcurl of libwww te gebruiken zal je eerst de library moeten downloaden, tenzij je hem al hebt.

Als je problemen hebt met code post dan de code dan kunnen wij ernaar kijken.
 
Bedankt voor je reactie maar ik ben er nog lang niet uit. Ik heb nu winsock.h geinclude maar WSAStartup lijkt het niet te doen. Dit is mijn code nu:
Code:
#include <winsock.h>
#include <stdio.h>

int main()
{
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0){
        printf("WSAStartup failed.\n");
        exit(1);
    }
    return 0;
}
en dit is de compiler fout:
Code:
[Linker error] undefined reference to `WSAStartup@8'
ld returned 1 exit status 
C:\Dev-Cpp\Projects\Makefile.win [Build Error]  ["Project] Error 1

Verder vraag ik me ook af wat het verschil is tussen winsock en winsock2. En is het nodig om verschillende bestanden te linken aan de compiler, zoja hoe doe je dat in Dev-C++?

Dinux
 
Je zal de winsock library libws2_32.a moeten meelinken.
Ik weet niet hoe dat precies gaat in DevCpp

Waarschijnlijk in de project opties.
Dus in het menu Project -> Project Options
In het veld waar je linker opties kan meegeven voeg je toe: -lws2_32
Hierdoor wordt het bestand libws2_32.a meegelinkt.

EDIT:
Even googlen levert dit op:
http://www.infoqu.com/dev/c-programming/dev-c--loading-winsock-api-55464-1/
winsock2 is de nieuwe/herschreven versie voor het gebruik van sockets met meer mogelijkheden.
winsock.h voor gebruik met libwsock32.a
winsock2.h voor gebruik met libws2_32.a
 
Laatst bewerkt:
Ok ik heb nu gelinkt en dit is mijn code nu:
Code:
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

int __cdecl main(int argc, char **argv) 
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;
    
    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Error at socket(): %ld\n", WSAGetLastError());
            freeaddrinfo(result);
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}
Alleen hoe bouw ik dit nu om zodat ik html van een webiste binnen krijg? Het lijkt er namelijk op dat de output het in de commandline niet goed doet. Iemand een idee?
 
Websites maken gebruik van http op poort 80.
i.p.v. "27015" kan je "http" of "80" gebruiken
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
=>
iResult = getaddrinfo(argv[1], "80", &hints, &result);

Ook zal een geldig http-request gestuurd moeten worden.
char *sendbuf = "this is a test";
=>
char *sendbuf = "GET / HTTP/1.0\r\n\r\n";
 
Ok ik heb nu de code aangepast zoals je voorstelde. Als ik de code compileer krijg ik geen fouten. Vervolgens vul ik dit in in de commandline:
Code:
C:\projects>"project1.exe" sidn.nl
Als ik nu in de netwerk sniffer kijk zie ik inderdaad een request naar dat ip adres. Maar ik krijg geen antwoord terug in de commandline. Ik zie alleen een lege regel, terwijl ik zeker weet dat er iets binnenkomt. Hoe krijg ik de response van de server nu in de commandline als output?
 
Ik krijg wel wat binnen met sidn.nl.
Ik denk dat je dan iets verkeerd stuurt of heel misschien
met een andere server verbonden bent.

Zou je hints.ai_family = AF_UNSPEC;
(tijdelijk) kunnen veranderen in
hints.ai_family = AF_INET.

Kan je de volgende code toevoegen onder printf("Bytes Sent: %ld\n", iResult);
Code:
    if(1){
        int i;
        for( i = 0; i< iResult; i++)
             printf("%3d ",(unsigned char)sendbuf[i]);
        printf("\n");
        fwrite(sendbuf, 1, iResult, stdout);
        printf("\n\n");
    }


De output bij mij op de commandline is dan:
D:\zhelpsock>sock sidn.nl
Bytes Sent: 18
71 69 84 32 47 32 72 84 84 80 47 49 46 48 13 10 13 10
GET / HTTP/1.0



Bytes received: 512
Bytes received: 512
Bytes received: 498
Bytes received: 29
Connection closed


Wat krijg jij als output?
 
Ik heb de code aangepast op de punten die je zij. De code ziet er nu zo uit:
Code:
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "80"

int __cdecl main(int argc, char **argv) 
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    char *sendbuf = "GET / HTTP/1.1\r\nAccept: */*\r\n\r\n";
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;
    
    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s server-name\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address until one succeeds
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Error at socket(): %ld\n", WSAGetLastError());
            freeaddrinfo(result);
            WSACleanup();
            return 1;
        }

        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            continue;
        }
        break;
    }

    freeaddrinfo(result);

    if (ConnectSocket == INVALID_SOCKET) {
        printf("Unable to connect to server!\n");
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);
    
    if(1){
        int i;
        for( i = 0; i< iResult; i++)
             printf("%3d ",(unsigned char)sendbuf[i]);
        printf("\n");
        fwrite(sendbuf, 1, iResult, stdout);
        printf("\n\n");
    }
    
    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());

    } while( iResult > 0 );
     

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

Compileren geeft geen fouten. Als ik vervolgens de cmd op en dit in vul:
Code:
E:>sock sidn.nl
krijg ik gelijk weer een volgende opdracht regel. Kan het niet aan de compiler liggen? Ik gebruik namelijk geen VC++ wat iedereen dus wel doet. Raar dat hij het wel bij jou doet.
 
Dit ligt waarschijnlijk aan een compiler-switch.
Zou het kunnen dat je voor een GUI-applicatie compileert.
Dan krijg je geen console. Dit kan je zien aan de commandline van de compiler.

Ook kan je in de applicatie zelf iets doen als (niet getest)
Code:
HANDLE h;
h = GetStdHandle(STD_OUTPUT_HANDLE);
if( h==INVALID_HANDLE_VALUE  ) MessageBox( 0, 0, "geen stdout", MB_SETFOREGROUND);

ook kan je de stdout redirecten op de commandline naar een tekst-bestand
iets als
E:>sock sidn.nl > output.txt
en dan output.txt bekijken in iets als notepad

Post de commandline van de compiler als je wilt.
Ikzelf gebruik gcc. Met gcc kan ik het wel zien.
 
Laatst bewerkt:
Misschien dat je jou geompileerde file even in een zipje hierbij doet want dan kan ik echt vaststellen waar het aan ligt. Toch blijft het raar want ik gebruik Dev-C++ die gebruikt de MinGW complier gebruikt. Maar ik dacht dat MinGW een onderdeel was vaan gcc die jij gebruikt. Waarschijnlijk instaleer ik gewoon VC++ en kijk of het daar wel mee werkt.
 
Ik raad je toch inderdaad aan om over te gaan op een wat nieuwere IDE/Compiler.
Dev C++ is verouderd en wordt niet meer geupdate..
 
DevC++ maakt inderdaad gebruik van mingw/gcc. Vandaar dat ik ook om een compile-log vraag.
Als jou versie van Dev-C++ een "compile-log" heeft (vanaf versie 4.0 dacht ik)
kan je dan de compile-log posten? Het is de linker tab onder in Dev-C++.
 
Laatst bewerkt:
Kan de log helaas niet vinden. Maar wat raden jullie dan aan? Ik heb VC++ 2010 maar dat lijkt voor geen meter te werken, als ik geen goed programma compileer krijg ik 100 fouten. Doe ik nu iets verkeerd of werkt het gewoon niet? Tips zijn welkom want ik wil graag verder.
 
Als je het nog met gcc wil proberen kan je via de commandline compileren.
Eerst ga je naar de directory waar je programma staat. Stel het heet sock.c dan tik je in op de commandline:
gcc sock.c -o sock.exe -lws32_2
En kijk of de exe die je dan krijgt het wel doet. (mocht je errors krijgen post die dan)

Als je verder wil met VC++ 2010 geef dan de eerste 5 errors die je krijgt.
De mensen die verstand hebben van VC++ zullen je dan evt. wel verder helpen.
 
Ik heb inmiddels Code::Blocks geinstaleerd en daar werkt het allemaal prima. Nu vraag ik me alleen nog af hoe ik de raw html krijg en niet het aantal verzonden bytes. Is er ook een plugin voor het maken van formulieren enzo wat ook in VC++ kan?
 
Daarom het Visual C++ ook VISUAL.
Oftwel je kan dingen slepen/plakken plaatsen en VC++ zet het om naar code. :\

Maar mischien is het er wel.. maar als laatste optie kun je het ook eerst in VC++ maken en dan de code kopieren naar Code::Blocks
 
Het project is inmiddels al lang achter de rug en heeft goed gewerkt.
 
Topic is dan ook al meer dan een jaar oud en is niet nodig om deze dan nog omhoog te schoppen.;)
slotje.gif
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan