Desidero scrivere un programma C per generare una richiesta di ricezione senza utilizzare alcuna libreria esterna. È possibile utilizzare solo le librerie C, usando le prese? Sto pensando di creare un pacchetto http (usando una formattazione corretta) e inviarlo al server. È questo l'unico modo possibile o c'è un modo migliore?HTTP get Richiesta utilizzando C WITHOUT libCurl
risposta
Utilizzando socket BSD o, se si è un po 'limitati, dire di avere qualche RTOS, un semplice stack TCP, come lwIP, si può formare la richiesta GET/POST.
Esistono numerose implementazioni open source. Vedere "happyhttp" come esempio (http://scumways.com/happyhttp/happyhttp.html). Lo so, è C++, non C, ma l'unica cosa che è "C++ - dipendente" esiste una gestione stringa/array, quindi è facilmente trasferibile su C. puro
Attenzione, non ci sono "pacchetti" , dal momento che HTTP viene solitamente trasferito sulla connessione TCP, quindi tecnicamente c'è solo un flusso di simboli nel formato RFC. Poiché le richieste HTTP vengono solitamente eseguite in modalità connect-send-disconnect, si potrebbe effettivamente chiamare "pacchetto".
In sostanza, una volta che hai una presa aperta (sockfd) "tutto" quello che dovete fare è qualcosa di simile
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);
}
}
Grazie! Questo ha fatto ciò che dovevo fare! – asudhak
@asudhak - Funziona alla grande, fino a quando questo codice non deve essere eseguito in un ambiente di lavoro aziendale in cui l'unico accesso a Internet avviene tramite un server proxy. Il protocollo per il recupero dell'URL tramite un proxy HTTP è leggermente diverso rispetto al TCP diretto. – selbie
@selbie: certo, le risposte HTTP con codice 300 (reindirizzamenti) e roba proxy sono esattamente ciò che rende difficile l'HTTP. Quindi la distribuzione di libCurl per escludere misc royp-related stuff può essere la via da seguire invece di una richiesta HTTP fatta a mano. –
“Senza librerie esterne” in senso stretto escluderebbe libc come pure, in modo che ci devi scrivere tutte le syscall te stesso. Dubito che tu lo intenda così severo, però. Se non si desidera collegarsi a un'altra libreria e non si desidera copiare il codice sorgente da un'altra libreria nell'applicazione, quindi trattare direttamente con il flusso TCP utilizzando l'API socket è l'approccio migliore.
Creare la richiesta HTTP e inviarlo su un TCP socket connection è facile, come sta leggendo la risposta. Sta analizzando la risposta che sarà davvero complicata, in particolare se si mira a supportare una parte ragionevolmente ampia dello standard. Cose come le pagine di errore, i reindirizzamenti, la negoziazione dei contenuti e così via possono rendere la nostra vita piuttosto difficile se stai parlando con server web arbitrari. Se, d'altra parte, il server è noto per essere ben educato e un semplice messaggio di errore va bene per qualsiasi risposta imprevista del server, allora è anche abbastanza semplice.
POSIX 7 minimale esempio eseguibile
#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);
}
Uso
compilazione:
gcc -o wget wget.c
garantita http://example.com e allo standard output:
./wget example.com
IP:
./wget 104.16.118.182
Questo comando si blocca per la maggior parte dei server, fino timeout, e che ci si aspetta:
- sia server o client deve chiudere la connessione
- maggior parte dei server HTTP lasciare la connessione aperto fino a un timeout in attesa di ulteriori richieste, ad esJavaScript, CSS e immagini a seguito di una pagina HTML
- potremmo analizzare la risposta, e si chiudono quando byte Content-Length vengono letti, ma non l'abbiamo fatto per semplicità
testato su Ubuntu 15.10.
Un esempio lato server in: Send and Receive a file in socket programming in Linux with C/C++ (GCC/G++)
GitHub monte: https://github.com/cirosantilli/cpp-cheat/blob/88d0c30681114647cce456c2e17aa2c5b31abcd0/posix/socket/wget.c
Il codice si blocca su 'read (socket_file_descriptor, buffer, BUFSIZ)'. – CroCo
@CroCo vedere il commento di origine: "la seconda lettura si blocca per alcuni secondi. [...]". Sia il server che il client devono chiudere la connessione. Non stiamo chiudendo, quindi nemmeno il server. È probabile che questo ottimizzi più richieste HTTP eseguite in un'unica connessione, il che è un caso comune (ottenere HTML, ottenere CSS, ottenere immagini). I client generalmente devono analizzare l'output e controllare che la risposta sia chiusa e chiusa usando 'Content-Length:' nel caso di HTTP, ma non volevo analizzare HTTP in questo semplice esempio. –
- 1. C++ - come inviare una richiesta di post HTTP utilizzando Curlpp o libcurl
- 2. Richiesta GET HTTP e risposta XML
- 3. Come rendere HTTP GET richiesta in Android
- 4. HttpURLConnection Richiesta GET con http-header "Accetta"
- 5. Ambito in TypeScript/angularJS Richiesta HTTP GET
- 6. Obiettivo semplice-c Richiesta GET
- 7. utilizzando libcurl senza dll
- 8. libcurl Richiesta HTTP per il salvataggio della risposta in variabile - C++
- 9. Richiesta API esterna GET() utilizzando jQuery
- 10. Come utilizzare libcurl per il post HTTP?
- 11. Invia richiesta HTTP e ricevi risposta HTTP utilizzando javascript
- 12. angolare $ HTTP GET richiesta con autorizzazione intestazione Token
- 13. parametri passando HTTP GET utilizzando angolare 2
- 14. Utilizzo di LibCURL C++
- 15. Come visualizzare l'ultima richiesta HTTP GET in JavaScript
- 16. Richiesta POST HTTP vuota o richiesta GET per generare un valore casuale tramite un'API HTTP
- 17. C#: come eseguire una richiesta HTTP utilizzando i socket?
- 18. Richiesta HTTP multipla in C#
- 19. Invia intestazione HTTP vuota con libcurl
- 20. Invia stringa nella richiesta PUT con libcurl
- 21. Caricamento su Amazon S3 utilizzando cURL/libcurl
- 22. C# Richiesta e analisi GET JSON
- 23. Genera ricerca SQL da HTTP Parametri richiesta GET
- 24. La risorsa richiesta non supporta il metodo HTTP 'GET'
- 25. Trasmissione dinamica rapida non riuscita con richiesta HTTP GET
- 26. Annulla una richiesta HTTP GET dall'estensione di Firefox
- 27. node.js richiesta http 'get' con parametri stringa di query
- 28. AngularJS - imposta l'intestazione HTTP per la richiesta GET
- 29. Come effettuare la richiesta HTTP GET + POST in Goniometro
- 30. Ottieni i parametri HTTP GET dalla richiesta di Restlet
No. devono imparare API presa BSD, poi imballare manualmente insieme tutti i dati grezzi. –