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