2012-06-26 12 views
26

के बिना सी का उपयोग करने का अनुरोध प्राप्त करें मैं किसी भी बाहरी पुस्तकालयों का उपयोग किये बिना एक अनुरोध प्राप्त करने के लिए एक सी प्रोग्राम लिखना चाहता हूं। क्या यह सॉकेट का उपयोग करके केवल सी पुस्तकालयों का उपयोग कर संभव है? मैं एक http पैकेट क्राफ्टिंग (उचित स्वरूपण का उपयोग करके) और इसे सर्वर पर भेज रहा हूं। क्या यह एकमात्र संभव तरीका है या क्या कोई बेहतर तरीका है?HTTP को libCurl

+0

नहीं। इसके बाद आप मैन्युअल रूप से एक साथ सभी कच्चे डेटा पैक, बीएसडी सॉकेट API प्रथम सीखना चाहिए। –

उत्तर

22

बीएसडी सॉकेट का उपयोग करना या यदि आप कुछ सीमित हैं, तो कहें कि आपके पास कुछ आरटीओएस है, कुछ आसान टीसीपी स्टैक, जैसे कि एलडब्ल्यूआईपी, आप जीईटी/पोस्ट अनुरोध बना सकते हैं।

कई खुले स्रोत कार्यान्वयन हैं। नमूना के रूप में "happyhttp" देखें (http://scumways.com/happyhttp/happyhttp.html)। मुझे पता है, यह सी ++ है, सी नहीं, लेकिन एकमात्र चीज जो "सी ++ - आश्रित" है, वहां एक स्ट्रिंग/सरणी प्रबंधन है, इसलिए इसे आसानी से शुद्ध सी

सावधान रहें, कोई "पैकेट" नहीं है , चूंकि HTTP आमतौर पर टीसीपी कनेक्शन पर स्थानांतरित होता है, इसलिए तकनीकी रूप से आरएफसी प्रारूप में केवल प्रतीकों की एक धारा होती है। चूंकि http अनुरोध आमतौर पर कनेक्ट-प्रेषण-डिस्कनेक्ट तरीके से किए जाते हैं, इसलिए कोई वास्तव में इसे "पैकेट" कह सकता है।

मूल रूप से, एक बार आप एक खुले सॉकेट (sockfd) है "सभी" आप क्या करना है

char sendline[MAXLINE + 1], recvline[MAXLINE + 1]; 
char* ptr; 

size_t n; 

/// Form request 
snprintf(sendline, MAXSUB, 
    "GET %s HTTP/1.0\r\n" // POST or GET, both tested and works. Both HTTP 1.0 HTTP 1.1 works, but sometimes 
    "Host: %s\r\n"  // but sometimes HTTP 1.0 works better in localhost type 
    "Content-type: application/x-www-form-urlencoded\r\n" 
    "Content-length: %d\r\n\r\n" 
    "%s\r\n", page, host, (unsigned int)strlen(poststr), poststr); 

/// Write the request 
if (write(sockfd, sendline, strlen(sendline))>= 0) 
{ 
    /// Read the response 
    while ((n = read(sockfd, recvline, MAXLINE)) > 0) 
    { 
     recvline[n] = '\0'; 

     if(fputs(recvline,stdout) == EOF) { cout << ("fputs erros"); } 
     /// Remove the trailing chars 
     ptr = strstr(recvline, "\r\n\r\n"); 

     // check len for OutResponse here ? 
     snprintf(OutResponse, MAXRESPONSE,"%s", ptr); 
    }   
} 
+0

धन्यवाद! ऐसा करने के लिए मुझे यह करने की ज़रूरत थी! – asudhak

+3

@asudhak - यह तब तक बढ़िया काम करता है जब तक कि इस कोड को कॉर्पोरेट कार्य वातावरण में नहीं चलाना पड़े, जहां केवल इंटरनेट का उपयोग प्रॉक्सी सर्वर के माध्यम से होता है। HTTP प्रॉक्सी के माध्यम से यूआरएल लाने के लिए प्रोटोकॉल प्रत्यक्ष टीसीपी से थोड़ा अलग है। – selbie

+0

@selbie - निश्चित रूप से, कोड 300 (रीडायरेक्शन) और प्रॉक्सी सामान के साथ HTTP प्रतिसाद वास्तव में चीजें हैं जो HTTP को कठिन बनाते हैं। तो विविध क्रिप्टो से संबंधित सामान को बाहर करने के लिए libCurl tayloring हाथ से तैयार HTTP अनुरोध के बजाय जाने का तरीका हो सकता है। –

3

की तरह कुछ "किसी भी बाहरी पुस्तकालयों के बिना" है कड़ाई से, साथ ही libc बहिष्कृत कर देगा बोल ताकि आप चाहते खुद को सभी सिस्को लिखना है। मुझे संदेह है कि इसका मतलब है कि यह सख्त है, यद्यपि। यदि आप किसी अन्य लाइब्रेरी से लिंक नहीं करना चाहते हैं, और स्रोत कोड को किसी अन्य लाइब्रेरी से अपने एप्लिकेशन में कॉपी नहीं करना चाहते हैं, तो सॉकेट एपीआई का उपयोग कर सीधे टीसीपी स्ट्रीम से निपटना आपका सबसे अच्छा तरीका है।

HTTP अनुरोध बनाना और इसे TCP socket connection पर भेजना उत्तर पढ़ने जैसा आसान है। यह उस जवाब को पार्स कर रहा है जो वास्तविक मुश्किल होने जा रहा है, खासकर यदि आप मानक के एक बड़े हिस्से का समर्थन करना चाहते हैं। अगर आप मनमानी वेब सर्वर से बात कर रहे हैं तो त्रुटि पृष्ठों, रीडायरेक्ट, सामग्री वार्ता आदि जैसी चीजें हमारे जीवन को काफी कठिन बना सकती हैं। यदि दूसरी तरफ सर्वर को अच्छी तरह से व्यवहार किया जाता है, और किसी भी अप्रत्याशित सर्वर प्रतिक्रिया के लिए एक साधारण त्रुटि संदेश ठीक है, तो यह भी काफी सरल है।

7

POSIX 7 न्यूनतम runnable उदाहरण

#define _XOPEN_SOURCE 700 

#include <assert.h> 
#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <arpa/inet.h> 
#include <netdb.h> /* getprotobyname */ 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <unistd.h> 

int main(int argc, char** argv) { 
    char buffer[BUFSIZ]; 
    enum CONSTEXPR { MAX_REQUEST_LEN = 1024}; 
    char request[MAX_REQUEST_LEN]; 
    char request_template[] = "GET/HTTP/1.1\r\nHost: %s\r\n\r\n"; 
    struct protoent *protoent; 
    char *hostname = "example.com"; 
    in_addr_t in_addr; 
    int request_len; 
    int socket_file_descriptor; 
    ssize_t nbytes_total, nbytes_last; 
    struct hostent *hostent; 
    struct sockaddr_in sockaddr_in; 
    unsigned short server_port = 80; 

    if (argc > 1) 
     hostname = argv[1]; 
    if (argc > 2) 
     server_port = strtoul(argv[2], NULL, 10); 

    request_len = snprintf(request, MAX_REQUEST_LEN, request_template, hostname); 
    if (request_len >= MAX_REQUEST_LEN) { 
     fprintf(stderr, "request length large: %d\n", request_len); 
     exit(EXIT_FAILURE); 
    } 

    /* Build the socket. */ 
    protoent = getprotobyname("tcp"); 
    if (protoent == NULL) { 
     perror("getprotobyname"); 
     exit(EXIT_FAILURE); 
    } 
    socket_file_descriptor = socket(AF_INET, SOCK_STREAM, protoent->p_proto); 
    if (socket_file_descriptor == -1) { 
     perror("socket"); 
     exit(EXIT_FAILURE); 
    } 

    /* Build the address. */ 
    hostent = gethostbyname(hostname); 
    if (hostent == NULL) { 
     fprintf(stderr, "error: gethostbyname(\"%s\")\n", hostname); 
     exit(EXIT_FAILURE); 
    } 
    in_addr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list))); 
    if (in_addr == (in_addr_t)-1) { 
     fprintf(stderr, "error: inet_addr(\"%s\")\n", *(hostent->h_addr_list)); 
     exit(EXIT_FAILURE); 
    } 
    sockaddr_in.sin_addr.s_addr = in_addr; 
    sockaddr_in.sin_family = AF_INET; 
    sockaddr_in.sin_port = htons(server_port); 

    /* Actually connect. */ 
    if (connect(socket_file_descriptor, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)) == -1) { 
     perror("connect"); 
     exit(EXIT_FAILURE); 
    } 

    /* Send HTTP request. */ 
    nbytes_total = 0; 
    while (nbytes_total < request_len) { 
     nbytes_last = write(socket_file_descriptor, request + nbytes_total, request_len - nbytes_total); 
     if (nbytes_last == -1) { 
      perror("write"); 
      exit(EXIT_FAILURE); 
     } 
     nbytes_total += nbytes_last; 
    } 

    /* Read the response. 
    * 
    * The second read hangs for a few seconds, until the server times out. 
    * 
    * Either server or client has to close the connection. 
    * 
    * We are not doing it, and neither is the server, likely to make serving the page faster 
    * to allow fetching HTML, CSS, Javascript and images in a single connection. 
    * 
    * The solution is to parse Content-Length to see if the HTTP response is over, 
    * and close it then. 
    * 
    * http://stackoverflow.com/a/25586633/895245 says that if Content-Length 
    * is not sent, the server can just close to determine length. 
    **/ 
    fprintf(stderr, "debug: before first read\n"); 
    while ((nbytes_total = read(socket_file_descriptor, buffer, BUFSIZ)) > 0) { 
     fprintf(stderr, "debug: after a read\n"); 
     write(STDOUT_FILENO, buffer, nbytes_total); 
    } 
    fprintf(stderr, "debug: after last read\n"); 
    if (nbytes_total == -1) { 
     perror("read"); 
     exit(EXIT_FAILURE); 
    } 

    close(socket_file_descriptor); 
    exit(EXIT_SUCCESS); 
} 

प्रयोग

संकलित:

:

gcc -o wget wget.c 

stdout में http://example.com और आउटपुट प्राप्त करें

आईपी:

./wget 104.16.118.182 

टाइमआउट जब तक कि अधिकांश सर्वरों के लिए यह आदेश रुक जाता है, और कहा कि उम्मीद है:

  • या तो सर्वर या क्लाइंट कनेक्शन
  • सबसे HTTP सर्वर कनेक्शन को बंद करना होगा छोड़ आगे के अनुरोधों की अपेक्षा करते समय एक टाइमआउट तक खुला, उदाहरण के लिएजावास्क्रिप्ट, सीएसएस और छवियों एक HTML पृष्ठ
  • हम प्रतिसाद पार्स सकता है, और करीब जब सामग्री-लंबाई बाइट्स पढ़ रहे हैं, लेकिन हम सादगी

उबंटू 15.10 पर परीक्षण किया गया के लिए नहीं किया गया था।

पर एक सर्वर साइड उदाहरण: Send and Receive a file in socket programming in Linux with C/C++ (GCC/G++)

GitHub नदी के ऊपर: https://github.com/cirosantilli/cpp-cheat/blob/88d0c30681114647cce456c2e17aa2c5b31abcd0/posix/socket/wget.c

+0

कोड 'read (socket_file_descriptor, बफर, BUFSIZ)' पर लटका हुआ है। – CroCo

+0

@ क्रोको स्रोत टिप्पणी देखें: "दूसरा पाठ कुछ सेकंड के लिए लटकता है। [...]"। या तो सर्वर या क्लाइंट कनेक्शन बंद करना होगा। हम बंद नहीं कर रहे हैं, इसलिए न तो सर्वर है। यह एक कनेक्शन में किए गए कई HTTP अनुरोधों को अनुकूलित करने की संभावना है, जो एक आम मामला है (HTML प्राप्त करें, सीएसएस प्राप्त करें, छवियां प्राप्त करें)। ग्राहकों को आमतौर पर आउटपुट को पार्स करना पड़ता है और जांच करता है कि HTTP के मामले में 'सामग्री-लंबाई:' का उपयोग करके प्रतिक्रिया खत्म हो गई है और बंद है, लेकिन मैं इस सरल उदाहरण में HTTP को पार्स नहीं करना चाहता था। –

संबंधित मुद्दे