Pesan memiliki bagian header dan badan pesan yang dipisahkan oleh baris kosong. Baris kosong SELALU diperlukan meskipun tidak ada badan pesan. Header dimulai dengan sebuah perintah dan memiliki baris tambahan dari pasangan nilai kunci yang dipisahkan oleh titik dua dan spasi. Jika ada badan pesan, bisa apa saja yang Anda inginkan.
Garis di header dan baris kosong di akhir header harus diakhiri dengan carraige return dan pasangan linefeed (lihat gaya jeda baris header HTTP ) jadi itulah mengapa baris tersebut memiliki \ r \ n di akhir.
URL memiliki bentuk http://host:port/path?query_string
Ada dua cara utama untuk mengirimkan permintaan ke situs web:
GET: String kueri bersifat opsional, tetapi jika ditentukan, harus cukup pendek. Karena itu, header hanya bisa menjadi perintah GET dan tidak ada yang lain. Contoh pesan dapat berupa:
GET /path?query_string HTTP/1.0\r\n
\r\n
POST: Apa yang biasanya ada di string kueri ada di badan pesan sebagai gantinya. Karena itu, header perlu menyertakan atribut Content-Type: dan Content-Length: serta perintah POST. Contoh pesan dapat berupa:
POST /path HTTP/1.0\r\n
Content-Type: text/plain\r\n
Content-Length: 12\r\n
\r\n
query_string
Jadi, untuk menjawab pertanyaan Anda: jika URL yang ingin Anda posting adalah http://api.somesite.com/apikey=ARG1&command=ARG2 maka tidak ada body atau query string dan, akibatnya, tidak ada alasan untuk POST karena ada tidak ada apa-apa untuk dimasukkan ke dalam badan pesan dan karenanya tidak ada yang harus dimasukkan ke dalam Jenis Konten: dan Panjang Konten:
Saya kira Anda bisa POST jika Anda benar-benar ingin. Dalam hal ini pesan Anda akan terlihat seperti:
POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n
Jadi untuk mengirim pesan, program C perlu:
- buat soket
- cari alamat IP
- buka soketnya
- kirim permintaan
- tunggu responnya
- tutup soketnya
Panggilan kirim dan terima tidak serta merta mengirim / menerima SEMUA data yang Anda berikan - mereka akan mengembalikan jumlah byte yang sebenarnya dikirim / diterima. Terserah Anda untuk memanggil mereka dalam satu lingkaran dan mengirim / menerima sisa pesan.
Apa yang tidak saya lakukan dalam contoh ini adalah pemeriksaan kesalahan nyata apa pun - ketika ada yang gagal, saya langsung keluar dari program. Beri tahu saya jika ini berhasil untuk Anda:
#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[])
{
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); }
sprintf(message,message_fmt,argv[1],argv[2]);
printf("Request:\n%s\n",message);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
server = gethostbyname(host);
if (server == NULL) error("ERROR, no such host");
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);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
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);
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(sockfd);
printf("Response:\n%s\n",response);
return 0;
}
Seperti jawaban lain yang ditunjukkan, 4096 byte bukanlah respons yang sangat besar. Saya memilih nomor itu secara acak dengan asumsi bahwa tanggapan atas permintaan Anda akan singkat. Jika bisa besar, Anda memiliki dua pilihan:
- baca header Content-Length: dari respons dan kemudian secara dinamis mengalokasikan cukup memori untuk menampung seluruh respons.
- tulis respons ke file saat potongan tiba
Informasi tambahan untuk menjawab pertanyaan yang diajukan di komentar:
Bagaimana jika Anda ingin POST data di badan pesan? Kemudian Anda perlu menyertakan header Content-Type: dan Content-Length:. Content-Length: adalah panjang sebenarnya dari segala sesuatu setelah baris kosong yang memisahkan header dari body.
Berikut adalah contoh yang mengambil argumen baris perintah berikut:
- tuan rumah
- Pelabuhan
- perintah (GET atau POST)
- jalur (tidak termasuk data kueri)
- data kueri (dimasukkan ke dalam string kueri untuk GET dan ke dalam tubuh untuk POST)
- daftar tajuk (Panjang Konten: otomatis jika menggunakan POST)
Jadi, untuk pertanyaan awal Anda akan menjalankan:
a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"
Dan untuk pertanyaan yang ditanyakan di komentar Anda akan menjalankan:
a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"
Ini kodenya:
#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;
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); }
message_size=0;
if(!strcmp(argv[3],"GET"))
{
message_size+=strlen("%s %s%s%s HTTP/1.0\r\n");
message_size+=strlen(argv[3]);
message_size+=strlen(argv[4]);
if(argc>5)
message_size+=strlen(argv[5]);
for(i=6;i<argc;i++)
message_size+=strlen(argv[i])+strlen("\r\n");
message_size+=strlen("\r\n");
}
else
{
message_size+=strlen("%s %s HTTP/1.0\r\n");
message_size+=strlen(argv[3]);
message_size+=strlen(argv[4]);
for(i=6;i<argc;i++)
message_size+=strlen(argv[i])+strlen("\r\n");
if(argc>5)
message_size+=strlen("Content-Length: %d\r\n")+10;
message_size+=strlen("\r\n");
if(argc>5)
message_size+=strlen(argv[5]);
}
message=malloc(message_size);
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",
strlen(argv[4])>0?argv[4]:"/",
strlen(argv[5])>0?"?":"",
strlen(argv[5])>0?argv[5]:"");
else
sprintf(message,"%s %s HTTP/1.0\r\n",
strlen(argv[3])>0?argv[3]:"GET",
strlen(argv[4])>0?argv[4]:"/");
for(i=6;i<argc;i++)
{strcat(message,argv[i]);strcat(message,"\r\n");}
strcat(message,"\r\n");
}
else
{
sprintf(message,"%s %s HTTP/1.0\r\n",
strlen(argv[3])>0?argv[3]:"POST",
strlen(argv[4])>0?argv[4]:"/");
for(i=6;i<argc;i++)
{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");
if(argc>5)
strcat(message,argv[5]);
}
printf("Request:\n%s\n",message);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket");
server = gethostbyname(host);
if (server == NULL) error("ERROR, no such host");
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);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
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);
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(sockfd);
printf("Response:\n%s\n",response);
free(message);
return 0;
}