Bir iletinin bir başlık bölümü ve boş bir satırla ayrılmış bir ileti gövdesi vardır. Mesaj gövdesi olmasa bile boş satır HER ZAMAN gereklidir. Başlık bir komutla başlar ve iki nokta üst üste ve boşlukla ayrılmış ek anahtar değer çiftleri satırlarına sahiptir. Bir mesaj gövdesi varsa, olmasını istediğiniz herhangi bir şey olabilir.
Başlıktaki satırlar ve başlığın sonundaki boş satır, bir carraige dönüş ve satır besleme çifti ile bitmelidir (bkz. HTTP başlık satırı kesme stili ), bu nedenle bu satırların sonunda \ r \ n bulunur.
Bir URL şu şekildedir: http://host:port/path?query_string
Bir web sitesine istek göndermenin iki ana yolu vardır:
GET: Sorgu dizesi isteğe bağlıdır, ancak belirtilirse makul ölçüde kısa olmalıdır. Bu nedenle başlık sadece GET komutu olabilir ve başka bir şey olamaz. Örnek bir mesaj şöyle olabilir:
GET /path?query_string HTTP/1.0\r\n
\r\n
POST: Normalde sorgu dizesinde olan şey bunun yerine mesajın gövdesindedir. Bu nedenle, başlığın Content-Type: ve Content-Length: özniteliklerinin yanı sıra POST komutunu da içermesi gerekir. Örnek bir mesaj şöyle olabilir:
POST /path HTTP/1.0\r\n
Content-Type: text/plain\r\n
Content-Length: 12\r\n
\r\n
query_string
Öyleyse, sorunuzu yanıtlamak için: POST ile ilgilendiğiniz URL http://api.somesite.com/apikey=ARG1&command=ARG2 ise, gövde veya sorgu dizesi yoktur ve sonuç olarak, POST için bir neden yoktur çünkü mesajın gövdesine konulacak bir şey değildir ve bu nedenle Content-Type: ve Content-Length'e hiçbir şey konulamaz:
Sanırım gerçekten istersen POST yapabilirsin. Bu durumda mesajınız şöyle görünür:
POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n
Yani C programının ihtiyacı olan mesajı göndermek için:
- bir soket oluştur
- IP adresini ara
- soketi aç
- isteği gönder
- cevabı bekle
- soketi kapat
Gönderme ve alma çağrıları, onlara verdiğiniz TÜM verileri mutlaka göndermez / almaz - gerçekte gönderilen / alınan bayt sayısını döndürür. Onları bir döngü içinde aramak ve mesajın geri kalanını göndermek / almak size kalmıştır.
Bu örnekte yapmadığım şey herhangi bir tür gerçek hata kontrolüdür - bir şey başarısız olduğunda programdan çıkıyorum. Sizin için işe yarayıp yaramadığını bana bildirin:
#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;
}
Diğer yanıtın işaret ettiği gibi, 4096 bayt çok büyük bir yanıt değildir. İsteğinize verilen yanıtın kısa olacağını varsayarak bu sayıyı rastgele seçtim. Büyük olabilirse iki seçeneğiniz vardır:
- yanıttan Content-Length: başlığını okuyun ve ardından tüm yanıtı tutmak için yeterli belleği dinamik olarak ayırın.
- Parçalar geldikçe yanıtı bir dosyaya yazın
Yorumlarda sorulan soruyu cevaplamak için ek bilgiler:
Mesajın gövdesindeki verileri POST yapmak isterseniz ne olur? Ardından, Content-Type: ve Content-Length: başlıklarını eklemeniz gerekir. İçerik Uzunluğu: Başlığı gövdeden ayıran boş satırdan sonraki her şeyin gerçek uzunluğudur.
İşte aşağıdaki komut satırı bağımsız değişkenlerini alan bir örnek:
- ev sahibi
- Liman
- komut (GET veya POST)
- yol (sorgu verileri dahil değil)
- sorgu verileri (GET için sorgu dizesine ve POST için gövdeye yerleştirin)
- üstbilgi listesi (Content-Length: POST kullanılıyorsa otomatiktir)
Öyleyse, orijinal soru için koşarsınız:
a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"
Ve yorumlarda sorulan soru için:
a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"
İşte kod:
#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;
}