Einfaches C-Beispiel für die Durchführung eines HTTP-POST und die Verwendung der Antwort

85

Ich möchte eine sehr einfache C-Anwendung erstellen, die einen HTTP-Beitrag erstellt. Es werden einige Parameter benötigt, mit denen eine URL erstellt wird. Ich möchte nur einen einfachen HTTP-POST durchführen und die Antwort ohne Verwendung von Curl erhalten (die Bibliotheken sind nicht und werden nicht auf dem Computer installiert, der ausgeführt werden muss).

Pseudocode:

  1. Prozess 2 Argumente

  2. Fügen Sie Argumente in die URL der Vorlage ein: http://api.somesite.com/apikey=ARG1&command=ARG2

  3. POST für generierte URL

  4. Antwort verbrauchen

Meine Google- und SO-Suche hat diesbezüglich nichts ergeben.

kmarks2
quelle
2
Verwenden Sie ein Netzwerk-Framework? Welches Betriebssystem verwenden Sie?
Cnicutar
Es wird nur eine einfache Fedora- oder Cent-Box sein. Die Netzwerk-Frameworks sind die üblichen sys / socket, netdb, arpa / inet. Nur nicht libcurl.
kmarks2
1
Nicht libcurl. Sind Sie bereit, mit einer anderen Bibliothek zu arbeiten, oder muss es sich um All-POSIX handeln?
Cnicutar
Alle POSIX leider. Es muss auf jedem System völlig freistehend sein.
kmarks2
2
Ich habe ein Beispiel, das ich für Sie erstellt habe, aber ich verstehe nicht, warum Sie POST verwenden, wenn es keinen Text für die Nachricht gibt. Wenn sich alle Parameter in der Abfragezeichenfolge befinden, warum möchten Sie dann kein GET durchführen?
Jerry Jeremiah

Antworten:

188

Eine Nachricht besteht aus einem Kopfteil und einem Nachrichtentext, die durch eine Leerzeile getrennt sind. Die leere Zeile wird IMMER benötigt, auch wenn kein Nachrichtentext vorhanden ist. Der Header beginnt mit einem Befehl und enthält zusätzliche Zeilen mit Schlüsselwertpaaren, die durch einen Doppelpunkt und ein Leerzeichen getrennt sind. Wenn es einen Nachrichtentext gibt, kann es alles sein, was Sie möchten.

Zeilen in der Kopfzeile und die leere Zeile am Ende der Kopfzeile müssen mit einem Carraige-Return- und Zeilenvorschubpaar enden (siehe Zeilenumbruchstil für HTTP-Kopfzeilen ). Deshalb haben diese Zeilen am Ende \ r \ n.

Eine URL hat die Form http://host:port/path?query_string

Es gibt zwei Möglichkeiten, eine Anfrage an eine Website zu senden:

  • GET: Die Abfragezeichenfolge ist optional, muss jedoch, falls angegeben, relativ kurz sein. Aus diesem Grund könnte der Header nur der Befehl GET sein und sonst nichts. Eine Beispielnachricht könnte sein:

    GET /path?query_string HTTP/1.0\r\n
    \r\n
    
  • POST: Was normalerweise in der Abfragezeichenfolge enthalten ist, befindet sich stattdessen im Nachrichtentext. Aus diesem Grund muss der Header die Attribute Content-Type: und Content-Length: sowie den Befehl POST enthalten. Eine Beispielnachricht könnte sein:

    POST /path HTTP/1.0\r\n
    Content-Type: text/plain\r\n
    Content-Length: 12\r\n
    \r\n
    query_string
    

Um Ihre Frage zu beantworten: Wenn die URL, an die Sie POSTEN möchten, http://api.somesite.com/apikey=ARG1&command=ARG2 lautet, gibt es keinen Text oder eine Abfragezeichenfolge und folglich keinen Grund für POST, da dort ist nichts, was in den Nachrichtentext eingefügt werden soll, und daher nichts, was in den Inhaltstyp: und die Inhaltslänge: eingefügt werden muss.

Ich denke, Sie könnten POSTEN, wenn Sie wirklich wollten. In diesem Fall würde Ihre Nachricht folgendermaßen aussehen:

POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n

Um die Nachricht zu senden, muss das C-Programm:

  • Erstellen Sie einen Socket
  • Suchen Sie die IP-Adresse
  • Öffnen Sie die Steckdose
  • Senden Sie die Anfrage
  • Warten Sie auf die Antwort
  • Schließen Sie die Steckdose

Die Sende- und Empfangsanrufe senden / empfangen nicht unbedingt ALLE Daten, die Sie ihnen geben - sie geben die Anzahl der tatsächlich gesendeten / empfangenen Bytes zurück. Es liegt an Ihnen, sie in einer Schleife aufzurufen und den Rest der Nachricht zu senden / empfangen.

Was ich in diesem Beispiel nicht getan habe, ist eine echte Fehlerprüfung - wenn etwas fehlschlägt, beende ich einfach das Programm. Lassen Sie mich wissen, ob es für Sie funktioniert:

#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */

void error(const char *msg) { perror(msg); exit(0); }

int main(int argc,char *argv[])
{
    /* first what are we going to send and where are we going to send it? */
    int portno =        80;
    char *host =        "api.somesite.com";
    char *message_fmt = "POST /apikey=%s&command=%s HTTP/1.0\r\n\r\n";

    struct hostent *server;
    struct sockaddr_in serv_addr;
    int sockfd, bytes, sent, received, total;
    char message[1024],response[4096];

    if (argc < 3) { puts("Parameters: <apikey> <command>"); exit(0); }

    /* fill in the parameters */
    sprintf(message,message_fmt,argv[1],argv[2]);
    printf("Request:\n%s\n",message);

    /* create the socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    /* lookup the ip address */
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");

    /* fill in the structure */
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

    /* connect the socket */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

    /* send the request */
    total = strlen(message);
    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);

    /* receive the response */
    memset(response,0,sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    do {
        bytes = read(sockfd,response+received,total-received);
        if (bytes < 0)
            error("ERROR reading response from socket");
        if (bytes == 0)
            break;
        received+=bytes;
    } while (received < total);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);

    /* process response */
    printf("Response:\n%s\n",response);

    return 0;
}

Wie die andere Antwort gezeigt hat, sind 4096 Bytes keine sehr große Antwort. Ich habe diese Zahl zufällig ausgewählt, unter der Annahme, dass die Antwort auf Ihre Anfrage kurz sein würde. Wenn es groß sein kann, haben Sie zwei Möglichkeiten:

  • Lesen Sie den Content-Length: -Header aus der Antwort und weisen Sie dann dynamisch genügend Speicher zu, um die gesamte Antwort aufzunehmen.
  • Schreiben Sie die Antwort in eine Datei, sobald die Teile eintreffen

Zusätzliche Informationen zur Beantwortung der in den Kommentaren gestellten Frage:

Was ist, wenn Sie Daten im Nachrichtentext POSTEN möchten? Dann müssen Sie die Überschriften Content-Type: und Content-Length: einfügen. Die Inhaltslänge: ist die tatsächliche Länge von allem nach der Leerzeile, die den Header vom Body trennt.

Hier ist ein Beispiel, das die folgenden Befehlszeilenargumente verwendet:

  • Gastgeber
  • Hafen
  • Befehl (GET oder POST)
  • Pfad (ohne die Abfragedaten)
  • Abfragedaten (in die Abfragezeichenfolge für GET und in den Text für POST einfügen)
  • Liste der Header (Inhaltslänge: ist automatisch, wenn POST verwendet wird)

Für die ursprüngliche Frage würden Sie also Folgendes ausführen:

a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"

Und für die Frage in den Kommentaren, die Sie ausführen würden:

a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"

Hier ist der Code:

#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit, atoi, malloc, free */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */

void error(const char *msg) { perror(msg); exit(0); }

int main(int argc,char *argv[])
{
    int i;

    /* first where are we going to send it? */
    int portno = atoi(argv[2])>0?atoi(argv[2]):80;
    char *host = strlen(argv[1])>0?argv[1]:"localhost";

    struct hostent *server;
    struct sockaddr_in serv_addr;
    int sockfd, bytes, sent, received, total, message_size;
    char *message, response[4096];

    if (argc < 5) { puts("Parameters: <host> <port> <method> <path> [<data> [<headers>]]"); exit(0); }

    /* How big is the message? */
    message_size=0;
    if(!strcmp(argv[3],"GET"))
    {
        message_size+=strlen("%s %s%s%s HTTP/1.0\r\n");        /* method         */
        message_size+=strlen(argv[3]);                         /* path           */
        message_size+=strlen(argv[4]);                         /* headers        */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* query string   */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        message_size+=strlen("\r\n");                          /* blank line     */
    }
    else
    {
        message_size+=strlen("%s %s HTTP/1.0\r\n");
        message_size+=strlen(argv[3]);                         /* method         */
        message_size+=strlen(argv[4]);                         /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        if(argc>5)
            message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */
        message_size+=strlen("\r\n");                          /* blank line     */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* body           */
    }

    /* allocate space for the message */
    message=malloc(message_size);

    /* fill in the parameters */
    if(!strcmp(argv[3],"GET"))
    {
        if(argc>5)
            sprintf(message,"%s %s%s%s HTTP/1.0\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                strlen(argv[4])>0?argv[4]:"/",                 /* path           */
                strlen(argv[5])>0?"?":"",                      /* ?              */
                strlen(argv[5])>0?argv[5]:"");                 /* query string   */
        else
            sprintf(message,"%s %s HTTP/1.0\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                strlen(argv[4])>0?argv[4]:"/");                /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        strcat(message,"\r\n");                                /* blank line     */
    }
    else
    {
        sprintf(message,"%s %s HTTP/1.0\r\n",
            strlen(argv[3])>0?argv[3]:"POST",                  /* method         */
            strlen(argv[4])>0?argv[4]:"/");                    /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        if(argc>5)
            sprintf(message+strlen(message),"Content-Length: %d\r\n",strlen(argv[5]));
        strcat(message,"\r\n");                                /* blank line     */
        if(argc>5)
            strcat(message,argv[5]);                           /* body           */
    }

    /* What are we going to send? */
    printf("Request:\n%s\n",message);

    /* create the socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    /* lookup the ip address */
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");

    /* fill in the structure */
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

    /* connect the socket */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

    /* send the request */
    total = strlen(message);
    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);

    /* receive the response */
    memset(response,0,sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    do {
        bytes = read(sockfd,response+received,total-received);
        if (bytes < 0)
            error("ERROR reading response from socket");
        if (bytes == 0)
            break;
        received+=bytes;
    } while (received < total);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);

    /* process response */
    printf("Response:\n%s\n",response);

    free(message);
    return 0;
}
Jerry Jeremiah
quelle
Welche Argumente sollten beim Aufruf übergeben werden?
Santiago Martí Olbrich
Sie müssen etwas übergeben, das als Apikey als erster Parameter verwendet wird, und etwas im zweiten Parameter, das als Befehl verwendet wird. Wenn Sie eine völlig andere Abfragezeichenfolge verwenden möchten, müssen Sie die Formatzeichenfolge, die Anzahl der Parameter und die Verwendungsnachricht ändern.
Jerry Jeremiah
2
Dieser Code gibt eine fehlerhafte HTTP-Anforderung aus. HTTP gibt an, dass Anforderungszeilen durch Wagenrücklauf- / Zeilenvorschubpaare ( \r\n) beendet werden müssen, dieser Code verwendet jedoch reine Zeilenvorschübe .
John Bollinger
@ JohnBollinger Das stimmt sehr. Vielen Dank für den Hinweis. Hoffentlich ist die bearbeitete Antwort besser.
Jerry Jeremiah
Was ist los mit dieser Post-Nachricht? "POST /variableName=%s&value=%s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\n\r\n\r\n"Ich möchte wie name = reaz posten. Es antwortet 400 Bad Request
Reaz Murshed
12

Jerrys Antwort ist großartig. Es werden jedoch keine großen Antworten verarbeitet. Eine einfache Änderung, um damit umzugehen:

memset(response, 0, sizeof(response));
total = sizeof(response)-1;
received = 0;
do {
    printf("RESPONSE: %s\n", response);
    // HANDLE RESPONSE CHUCK HERE BY, FOR EXAMPLE, SAVING TO A FILE.
    memset(response, 0, sizeof(response));
    bytes = recv(sockfd, response, 1024, 0);
    if (bytes < 0)
        printf("ERROR reading response from socket");
    if (bytes == 0)
        break;
    received+=bytes;
} while (1); 
Peter Washington
quelle
3
Sie können das Antwortarray in meinem Beispiel einfach vergrößern. Ich nahm an, dass er gerade etwas json zurückbekam und keine riesige Datei herunterlud, aber natürlich kann sogar json je nach Abfrage Megabyte betragen ...
Jerry Jeremiah
1
Ich bin ein C-Anfänger und Ihre Antwort könnte richtig sein. Aber können Sie Ihrer Antwort bitte eine Erklärung hinzufügen?
Boop
2
Dies ist wirklich nur ein Kommentar zur akzeptierten Antwort und sollte nicht als separater Antwortversuch erfolgen.
Michael Gaskill
1
Nur eine Sache, die hier hinzugefügt werden muss. Dies funktioniert hervorragend. Sie sollten jedoch die Größe des Puffers ablesen - 1 Byte. Und um es richtig anzuzeigen, würde ich in dieser Druckanweisung keinen Zeilenumbruch verwenden. Sollte so aussehen:bytes = recv(sockfd, response, 1023, 0)
xjsc16x
10

Nach wochenlanger Forschung. Ich habe mir den folgenden Code ausgedacht. Ich glaube, dies ist das absolute Minimum, um eine sichere Verbindung mit SSL zu einem Webserver herzustellen.

#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>

#define APIKEY "YOUR_API_KEY"
#define HOST "YOUR_WEB_SERVER_URI"
#define PORT "443"

int main() {

    //
    //  Initialize the variables
    //
    BIO* bio;
    SSL* ssl;
    SSL_CTX* ctx;

    //
    //   Registers the SSL/TLS ciphers and digests.
    //
    //   Basically start the security layer.
    //
    SSL_library_init();

    //
    //  Creates a new SSL_CTX object as a framework to establish TLS/SSL
    //  or DTLS enabled connections
    //
    ctx = SSL_CTX_new(SSLv23_client_method());

    //
    //  -> Error check
    //
    if (ctx == NULL)
    {
        printf("Ctx is null\n");
    }

    //
    //   Creates a new BIO chain consisting of an SSL BIO
    //
    bio = BIO_new_ssl_connect(ctx);

    //
    //  Use the variable from the beginning of the file to create a 
    //  string that contains the URL to the site that you want to connect
    //  to while also specifying the port.
    //
    BIO_set_conn_hostname(bio, HOST ":" PORT);

    //
    //   Attempts to connect the supplied BIO
    //
    if(BIO_do_connect(bio) <= 0)
    {
        printf("Failed connection\n");
        return 1;
    }
    else
    {
        printf("Connected\n");
    }

    //
    //  The bare minimum to make a HTTP request.
    //
    char* write_buf = "POST / HTTP/1.1\r\n"
                      "Host: " HOST "\r\n"
                      "Authorization: Basic " APIKEY "\r\n"
                      "Connection: close\r\n"
                      "\r\n";

    //
    //   Attempts to write len bytes from buf to BIO
    //
    if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0)
    {
        //
        //  Handle failed writes here
        //
        if(!BIO_should_retry(bio))
        {
            // Not worth implementing, but worth knowing.
        }

        //
        //  -> Let us know about the failed writes
        //
        printf("Failed write\n");
    }

    //
    //  Variables used to read the response from the server
    //
    int size;
    char buf[1024];

    //
    //  Read the response message
    //
    for(;;)
    {
        //
        //  Get chunks of the response 1023 at the time.
        //
        size = BIO_read(bio, buf, 1023);

        //
        //  If no more data, then exit the loop
        //
        if(size <= 0)
        {
            break;
        }

        //
        //  Terminate the string with a 0, to let know C when the string 
        //  ends.
        //
        buf[size] = 0;

        //
        //  ->  Print out the response
        //
        printf("%s", buf);
    }

    //
    //  Clean after ourselves
    //
    BIO_free_all(bio);
    SSL_CTX_free(ctx);

    return 0;
}

Der obige Code erklärt ausführlich, wie eine TLS-Verbindung mit einem Remote-Server hergestellt wird.

Wichtiger Hinweis : Dieser Code prüft nicht, ob der öffentliche Schlüssel von einer gültigen Behörde signiert wurde. Das heißt, ich verwende keine Stammzertifikate zur Validierung. Vergessen Sie nicht, diese Prüfung durchzuführen, da Sie sonst nicht wissen, ob Sie die richtige Website verbinden

Wenn es um die Anfrage selbst geht. Es ist nichts weiter als das Schreiben der HTTP-Anfrage von Hand.

Unter diesem Link finden Sie auch eine Erklärung zum Installieren von openSSL in Ihrem System und zum Kompilieren des Codes, damit die sichere Bibliothek verwendet wird .

David Gatti
quelle
2
Schöne Erklärung!
Satyam Koyani
Nein, die nächste Variable ist der Port. Wir stellen bereits eine Verbindung zum richtigen Port her.
David Gatti
3

Griff hinzugefügt.
Host-Header hinzugefügt.
Linux / Windows-Unterstützung hinzugefügt, getestet (XP, WIN7).
WARNUNG: FEHLER: "Segmentierungsfehler", wenn kein Host, Pfad oder Port als Argument vorhanden ist.

#include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* exit, atoi, malloc, free */
#include <unistd.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#ifdef __linux__ 
    #include <sys/socket.h> /* socket, connect */
    #include <netdb.h> /* struct hostent, gethostbyname */
    #include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#elif _WIN32
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <windows.h>
    #pragma comment(lib,"ws2_32.lib") //Winsock Library

#else

#endif

void error(const char *msg) { perror(msg); exit(0); }

int main(int argc,char *argv[])
{

    int i;
    struct hostent *server;
    struct sockaddr_in serv_addr;
    int bytes, sent, received, total, message_size;
    char *message, response[4096];
    int portno = atoi(argv[2])>0?atoi(argv[2]):80;
    char *host = strlen(argv[1])>0?argv[1]:"localhost";
    char *path = strlen(argv[4])>0?argv[4]:"/";
    if (argc < 5) { puts("Parameters: <host> <port> <method> <path> [<data> [<headers>]]"); exit(0); }
    /* How big is the message? */
    message_size=0;
    if(!strcmp(argv[3],"GET"))
    {
                printf("Process 1\n");
        message_size+=strlen("%s %s%s%s HTTP/1.0\r\nHost: %s\r\n");        /* method         */
        message_size+=strlen(argv[3]);                         /* path           */
        message_size+=strlen(path);                         /* headers        */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* query string   */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        message_size+=strlen("\r\n");                          /* blank line     */
    }
    else
    {
                printf("Process 2\n");
        message_size+=strlen("%s %s HTTP/1.0\r\nHost: %s\r\n");
        message_size+=strlen(argv[3]);                         /* method         */
        message_size+=strlen(path);                            /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            message_size+=strlen(argv[i])+strlen("\r\n");
        if(argc>5)
            message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */
        message_size+=strlen("\r\n");                          /* blank line     */
        if(argc>5)
            message_size+=strlen(argv[5]);                     /* body           */
    }
            printf("Allocating...\n");
    /* allocate space for the message */
    message=malloc(message_size);

    /* fill in the parameters */
    if(!strcmp(argv[3],"GET"))
    {
        if(argc>5)
            sprintf(message,"%s %s%s%s HTTP/1.0\r\nHost: %s\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                path,                                          /* path           */
                strlen(argv[5])>0?"?":"",                      /* ?              */
                strlen(argv[5])>0?argv[5]:"",host);            /* query string   */
        else
            sprintf(message,"%s %s HTTP/1.0\r\nHost: %s\r\n",
                strlen(argv[3])>0?argv[3]:"GET",               /* method         */
                path,host);                                    /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        strcat(message,"\r\n");                                /* blank line     */
    }
    else
    {
        sprintf(message,"%s %s HTTP/1.0\r\nHost: %s\r\n",
            strlen(argv[3])>0?argv[3]:"POST",                  /* method         */
            path,host);                                        /* path           */
        for(i=6;i<argc;i++)                                    /* headers        */
            {strcat(message,argv[i]);strcat(message,"\r\n");}
        if(argc>5)
            sprintf(message+strlen(message),"Content-Length: %d\r\n",(int)strlen(argv[5]));
        strcat(message,"\r\n");                                /* blank line     */
        if(argc>5)
            strcat(message,argv[5]);                           /* body           */
    }
    printf("Processed\n");
    /* What are we going to send? */
    printf("Request:\n%s\n",message);
        /* lookup the ip address */

    total = strlen(message);
    /* create the socket */
    #ifdef _WIN32
WSADATA wsa;
SOCKET s;

printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
    printf("Failed. Error Code : %d",WSAGetLastError());
    return 1;
}

printf("Initialised.\n");

//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
    printf("Could not create socket : %d" , WSAGetLastError());
}

printf("Socket created.\n");

server = gethostbyname(host);
serv_addr.sin_addr.s_addr = inet_addr(server->h_addr);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
//Connect to remote server
if (connect(s , (struct sockaddr *)&serv_addr , sizeof(serv_addr)) < 0)
{
    printf("connect failed with error code : %d" , WSAGetLastError());
    return 1;
}

puts("Connected");
if( send(s , message , strlen(message) , 0) < 0)
{
    printf("Send failed with error code : %d" , WSAGetLastError());
    return 1;
}
puts("Data Send\n");

//Receive a reply from the server
if((received = recv(s , response , 2000 , 0)) == SOCKET_ERROR)
{
    printf("recv failed with error code : %d" , WSAGetLastError());
}

puts("Reply received\n");

//Add a NULL terminating character to make it a proper string before printing
response[received] = '\0';
puts(response);

closesocket(s);
WSACleanup();
    #endif
    #ifdef __linux__ 
    int sockfd;
    server = gethostbyname(host);
    if (server == NULL) error("ERROR, no such host");
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) error("ERROR opening socket");
        /* fill in the structure */
        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(portno);
        memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
                /* connect the socket */
        if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
            error("ERROR connecting");
                /* send the request */

    sent = 0;
    do {
        bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total);
    /* receive the response */
    memset(response, 0, sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    printf("Response: \n");
    do {
       printf("%s", response);
       memset(response, 0, sizeof(response));
       bytes = recv(sockfd, response, 1024, 0);
        if (bytes < 0)
           printf("ERROR reading response from socket");
       if (bytes == 0)
           break;
       received+=bytes;
    } while (1);

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);
    #endif


    free(message);

    return 0;
}
William Desportes
quelle