HTTP POST करने और प्रतिक्रिया का उपभोग करने का सरल C उदाहरण


90

मैं एक बहुत ही सरल सी एप्लिकेशन बनाना चाहता हूं जो एक HTTP पोस्ट करता है। यह कुछ मापदंडों को लेगा, और URL का निर्माण करने के लिए इनका उपयोग करेगा। मैं बस एक साधारण HTTP POST करना चाहता हूं और कर्ल के उपयोग के बिना प्रतिक्रिया प्राप्त करता हूं (लाइब्रेरी नहीं हैं और इसे चलाने के लिए आवश्यक मशीन पर स्थापित नहीं किया जाएगा)।

छद्म कोड:

  1. प्रक्रिया 2 आर्ग

  2. टेम्प्लेट URL में आर्ग्स डालें: http://api.somesite.com/apikey=ARG1&command=ARG2

  3. उत्पन्न URL पर POST करें

  4. प्रतिक्रिया का उपभोग करें

मेरे Google और SO खोजों ने इस मामले में कुछ भी हासिल नहीं किया है।


2
क्या आप किसी भी तरह के नेटवर्क ढांचे का उपयोग करते हैं? आप किस ओएस का उपयोग करते हैं?

यह सिर्फ एक बुनियादी फेडोरा या सेंट बॉक्स होगा। नेटवर्क फ्रेमवर्क सामान्य sys / socket, netdb, arpa / inet हैं। बस कामवासना नहीं है।
kmarks2

1
कामवासना नहीं। क्या आप किसी अन्य पुस्तकालय के साथ जाने के लिए तैयार हैं या क्या यह सभी POSIX होना चाहिए।
cnicutar

दुर्भाग्य से सभी POSIX। इसे किसी भी प्रणाली पर पूरी तरह से मुक्त होना होगा।
kmarks2

2
मेरे पास एक नमूना है जो मैंने आपके लिए बनाया है, लेकिन मुझे यह समझ में नहीं आता है कि यदि आप संदेश के लिए कोई निकाय नहीं हैं तो आप POST का उपयोग क्यों कर रहे हैं। यदि सभी पैरामीटर क्वेरी स्ट्रिंग में हैं तो आप GET क्यों नहीं करना चाहते हैं?
जेरी यिर्मयाह

जवाबों:


191

एक संदेश में एक हेडर भाग होता है और एक संदेश निकाय एक रिक्त रेखा द्वारा अलग होता है। संदेश लाइन नहीं होने पर भी रिक्त लाइन हमेशा आवश्यक होती है। हेडर एक कमांड के साथ शुरू होता है और इसमें एक कॉलोन और एक स्पेस द्वारा अलग किए गए कुंजी वैल्यू पेयर की अतिरिक्त लाइनें होती हैं। यदि कोई संदेश निकाय है, तो वह कुछ भी हो सकता है जिसे आप चाहते हैं।

हेडर में लाइनें और हेडर के अंत में रिक्त लाइन को कैराजी रिटर्न और लाइनफीड जोड़ी ( HTTP हेडर लाइन ब्रेक स्टाइल देखें ) के साथ समाप्त होना चाहिए, इसलिए अंत में उन लाइनों का \ r \ n है।

एक URL का रूप है http://host:port/path?query_string

वेबसाइट पर अनुरोध सबमिट करने के दो मुख्य तरीके हैं:

  • प्राप्त करें: क्वेरी स्ट्रिंग वैकल्पिक है, लेकिन यदि निर्दिष्ट किया गया है, तो यथोचित कम होना चाहिए। इस वजह से हेडर सिर्फ GET कमांड हो सकता है और कुछ नहीं। एक नमूना संदेश हो सकता है:

    GET /path?query_string HTTP/1.0\r\n
    \r\n
    
  • पोस्ट: आमतौर पर मैसेज की बॉडी में क्वेरी स्ट्रिंग में क्या होता है। इस वजह से हेडर को सामग्री-प्रकार: और सामग्री-लंबाई: विशेषताओं के साथ-साथ POST कमांड शामिल करने की आवश्यकता होती है। एक नमूना संदेश हो सकता है:

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

इसलिए, अपने प्रश्न का उत्तर देने के लिए: यदि आप जिस URL को POST करने में रुचि रखते हैं, वह है http://api.somesite.com/apikey=ARG1&command=ARG2 तो कोई बॉडी या क्वेरी स्ट्रिंग नहीं है और, परिणामस्वरूप, POST का कोई कारण नहीं है क्योंकि वहाँ संदेश के शरीर में डालने के लिए कुछ भी नहीं है और इसलिए सामग्री-प्रकार: और सामग्री-लंबाई में डालने के लिए कुछ भी नहीं है:

यदि आप वास्तव में चाहते हैं तो मुझे लगता है कि आप POST कर सकते हैं। उस स्थिति में आपका संदेश ऐसा दिखेगा:

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

तो संदेश भेजने के लिए सी कार्यक्रम की जरूरत है:

  • एक सॉकेट बनाएं
  • आईपी ​​पते की खोज
  • सॉकेट खोलें
  • अनुरोध भेजें
  • प्रतिक्रिया की प्रतीक्षा करें
  • सॉकेट बंद करें

भेजने और प्राप्त करने वाले कॉल आवश्यक रूप से आपके द्वारा दिए गए सभी डेटा को भेज / प्राप्त नहीं करेंगे - वे वास्तव में भेजे गए / प्राप्त किए गए बाइट्स की संख्या वापस कर देंगे। यह आप पर निर्भर है कि आप उन्हें लूप में बुलाते हैं और शेष संदेश भेजते / प्राप्त करते हैं।

इस नमूने में मैंने जो नहीं किया वह किसी भी प्रकार की वास्तविक त्रुटि जांच का है - जब कुछ विफल होता है तो मैं सिर्फ कार्यक्रम से बाहर निकलता हूं। अगर यह आप के लिए काम करता है तो मुझे बतलाएगा:

#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;
}

अन्य उत्तर की तरह, 4096 बाइट्स बहुत बड़ी प्रतिक्रिया नहीं है। मैंने उस संख्या को यादृच्छिक रूप से यह मानकर उठाया कि आपके अनुरोध की प्रतिक्रिया कम होगी। यदि यह बड़ा हो सकता है तो आपके पास दो विकल्प हैं:

  • सामग्री-लंबाई पढ़ें: प्रतिक्रिया से हेडर और फिर गतिशील रूप से पर्याप्त मेमोरी आवंटित करें ताकि पूरी प्रतिक्रिया पकड़ सके।
  • एक फाइल का जवाब लिखें जैसे ही टुकड़े आते हैं

टिप्पणियों में पूछे गए प्रश्न का उत्तर देने के लिए अतिरिक्त जानकारी:

यदि आप संदेश के मुख्य भाग में डेटा पोस्ट करना चाहते हैं तो क्या होगा? फिर आपको सामग्री-प्रकार: और सामग्री-लंबाई: शीर्षलेख शामिल करने की आवश्यकता है। कंटेंट-लेंथ: ब्लैंक लाइन के बाद हर चीज की वास्तविक लंबाई होती है जो हेडर को शरीर से अलग करती है।

यहाँ एक नमूना है जो निम्नलिखित कमांड लाइन तर्क लेता है:

  • मेज़बान
  • बंदरगाह
  • कमांड (GET या POST)
  • पथ (क्वेरी डेटा सहित नहीं)
  • क्वेरी डेटा (GST के लिए और POST के लिए निकाय में क्वेरी स्ट्रिंग में डालें)
  • हेडर की सूची (सामग्री-लंबाई: स्वचालित है यदि पोस्ट का उपयोग कर)

तो, मूल प्रश्न के लिए आप दौड़ेंगे:

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

और टिप्पणियों में पूछे गए प्रश्न के लिए आप दौड़ेंगे:

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

यहाँ कोड है:

#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;
}

क्या तर्क जब पारित किया जाना चाहिए?
सैंटियागो मार्टी ओल्ब्रिक

आपको कुछ पास करने की आवश्यकता है जो पहले पैरामीटर के रूप में एक एपिक के रूप में उपयोग किया जाएगा और दूसरे पैरामीटर में कुछ ऐसा होगा जो कमांड के रूप में उपयोग किया जाएगा। यदि आप पूरी तरह से अलग क्वेरी स्ट्रिंग का उपयोग करना चाहते हैं तो आपको प्रारूप स्ट्रिंग, मापदंडों की संख्या और उपयोग संदेश को बदलने की आवश्यकता है।
जेरी जेमियाह

2
यह कोड एक विकृत HTTP अनुरोध का उत्सर्जन करता है। HTTP निर्दिष्ट करता है कि अनुरोध लाइनों को कैरिज-रिटर्न / लाइन-फीड जोड़े ( \r\n) द्वारा समाप्त किया जाना चाहिए , लेकिन यह कोड नंगे लाइन फ़ीड का उपयोग करता है।
जॉन बोलिंजर

@ जॉनबोलिंगर यह बहुत सच है। इस पर ध्यान दिलाने के लिए धन्यवाद। उम्मीद है कि संपादित उत्तर बेहतर है।
जेरी यिर्मयाह

इस पोस्ट संदेश में क्या गलत है? "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"मैं नाम = रीज़ की तरह पोस्ट करना चाहता हूं। यह 400 बुरी रिक्वेस्ट का जवाब देता है
रिएज मुर्शिद

12

जेरी का जवाब बहुत अच्छा है। हालाँकि, यह बड़ी प्रतिक्रियाओं को नहीं संभालता है। इसे संभालने के लिए एक सरल परिवर्तन:

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); 

3
आप केवल मेरे उदाहरण में प्रतिक्रिया सरणी बड़ा कर सकते हैं। मैं मान रहा था कि वह कुछ जौन को वापस ले रहा था और एक बड़ी फाइल डाउनलोड नहीं कर रहा था, लेकिन निश्चित रूप से जसन भी मेगाबाइट हो सकता है जो कि क्वेरी पर निर्भर करता है ...
जेरी यिर्मयाह

1
मैं एक सी शुरुआत हूं और आपका जवाब सही हो सकता है। लेकिन क्या आप कृपया अपने उत्तर में स्पष्टीकरण जोड़ सकते हैं?
BOOP

2
यह वास्तव में स्वीकृत उत्तर पर केवल एक टिप्पणी है, और उत्तर देने के लिए एक अलग प्रयास के रूप में नहीं बनाया जाना चाहिए था।
माइकल गास्किल

1
यहां जोड़ने के लिए बस एक चीज, यह बहुत अच्छा काम करता है लेकिन आपको बफर के आकार को पढ़ना चाहिए - 1 बाइट्स। और इसे ठीक से देखने के लिए मैं उस प्रिंट स्टेटमेंट में एक नई पंक्ति का उपयोग नहीं करूंगा। इस तरह दिखना चाहिए:bytes = recv(sockfd, response, 1023, 0)
xjsc16x

11

हफ्तों के शोध के बाद। मैं निम्नलिखित कोड के साथ आया था। मेरा मानना ​​है कि वेब सर्वर पर एसएसएल के साथ सुरक्षित संबंध बनाने के लिए आवश्यक नंगे न्यूनतम है।

#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;
}

उपरोक्त कोड विवरण में बताएगा कि रिमोट सर्वर के साथ टीएलएस कनेक्शन कैसे स्थापित किया जाए।

महत्वपूर्ण नोट : यदि सार्वजनिक कुंजी पर एक वैध प्राधिकारी द्वारा हस्ताक्षर किए गए थे, तो यह कोड जांच नहीं करता है। मतलब मैं मान्यता के लिए रूट प्रमाणपत्र का उपयोग नहीं करता। इस चेक को लागू करना न भूलें अन्यथा आप नहीं जान पाएंगे कि आप सही वेबसाइट से जुड़ रहे हैं

जब खुद रिक्वेस्ट आती है। यह हाथ से HTTP अनुरोध लिखने के बाद और कुछ नहीं है।

आप इस लिंक के तहत यह भी जान सकते हैं कि आपके सिस्टम में ओपनएसएसएल को कैसे स्थापित किया जाए, और कोड को कैसे संकलित किया जाए ताकि यह सुरक्षित पुस्तकालय का उपयोग कर सके


2
अच्छा स्पष्टीकरण!
सत्यम कोयानी

नहीं, अगला चर बंदरगाह है, हम पहले से ही सही बंदरगाह से जुड़ रहे हैं।
डेविड गट्टी

3

जोड़ा गया।
होस्ट हेडर जोड़ा गया।
जोड़ा गया लिनक्स / विंडोज़ का समर्थन, परीक्षण किया हुआ (एक्सपी, विन 7)।
चेतावनी: त्रुटि: "विभाजन दोष" यदि कोई होस्ट, पथ या पोर्ट तर्क के रूप में नहीं है।

#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;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.