एक संदेश में एक हेडर भाग होता है और एक संदेश निकाय एक रिक्त रेखा द्वारा अलग होता है। संदेश लाइन नहीं होने पर भी रिक्त लाइन हमेशा आवश्यक होती है। हेडर एक कमांड के साथ शुरू होता है और इसमें एक कॉलोन और एक स्पेस द्वारा अलग किए गए कुंजी वैल्यू पेयर की अतिरिक्त लाइनें होती हैं। यदि कोई संदेश निकाय है, तो वह कुछ भी हो सकता है जिसे आप चाहते हैं।
हेडर में लाइनें और हेडर के अंत में रिक्त लाइन को कैराजी रिटर्न और लाइनफीड जोड़ी ( HTTP हेडर लाइन ब्रेक स्टाइल देखें ) के साथ समाप्त होना चाहिए, इसलिए अंत में उन लाइनों का \ r \ n है।
एक URL का रूप है http://host:port/path?query_string
वेबसाइट पर अनुरोध सबमिट करने के दो मुख्य तरीके हैं:
प्राप्त करें: क्वेरी स्ट्रिंग वैकल्पिक है, लेकिन यदि निर्दिष्ट किया गया है, तो यथोचित कम होना चाहिए। इस वजह से हेडर सिर्फ GET कमांड हो सकता है और कुछ नहीं। एक नमूना संदेश हो सकता है:
GET /path?query_string HTTP/1.0\r\n
\r\n
पोस्ट: आमतौर पर मैसेज की बॉडी में क्वेरी स्ट्रिंग में क्या होता है। इस वजह से हेडर को सामग्री-प्रकार: और सामग्री-लंबाई: विशेषताओं के साथ-साथ POST कमांड शामिल करने की आवश्यकता होती है। एक नमूना संदेश हो सकता है:
POST /path HTTP/1.0\r\n
Content-Type: text/plain\r\n
Content-Length: 12\r\n
\r\n
query_string
इसलिए, अपने प्रश्न का उत्तर देने के लिए: यदि आप जिस URL को POST करने में रुचि रखते हैं, वह है http://api.somesite.com/apikey=ARG1&command=ARG2 तो कोई बॉडी या क्वेरी स्ट्रिंग नहीं है और, परिणामस्वरूप, POST का कोई कारण नहीं है क्योंकि वहाँ संदेश के शरीर में डालने के लिए कुछ भी नहीं है और इसलिए सामग्री-प्रकार: और सामग्री-लंबाई में डालने के लिए कुछ भी नहीं है:
यदि आप वास्तव में चाहते हैं तो मुझे लगता है कि आप POST कर सकते हैं। उस स्थिति में आपका संदेश ऐसा दिखेगा:
POST /apikey=ARG1&command=ARG2 HTTP/1.0\r\n
\r\n
तो संदेश भेजने के लिए सी कार्यक्रम की जरूरत है:
- एक सॉकेट बनाएं
- आईपी पते की खोज
- सॉकेट खोलें
- अनुरोध भेजें
- प्रतिक्रिया की प्रतीक्षा करें
- सॉकेट बंद करें
भेजने और प्राप्त करने वाले कॉल आवश्यक रूप से आपके द्वारा दिए गए सभी डेटा को भेज / प्राप्त नहीं करेंगे - वे वास्तव में भेजे गए / प्राप्त किए गए बाइट्स की संख्या वापस कर देंगे। यह आप पर निर्भर है कि आप उन्हें लूप में बुलाते हैं और शेष संदेश भेजते / प्राप्त करते हैं।
इस नमूने में मैंने जो नहीं किया वह किसी भी प्रकार की वास्तविक त्रुटि जांच का है - जब कुछ विफल होता है तो मैं सिर्फ कार्यक्रम से बाहर निकलता हूं। अगर यह आप के लिए काम करता है तो मुझे बतलाएगा:
#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;
}
अन्य उत्तर की तरह, 4096 बाइट्स बहुत बड़ी प्रतिक्रिया नहीं है। मैंने उस संख्या को यादृच्छिक रूप से यह मानकर उठाया कि आपके अनुरोध की प्रतिक्रिया कम होगी। यदि यह बड़ा हो सकता है तो आपके पास दो विकल्प हैं:
- सामग्री-लंबाई पढ़ें: प्रतिक्रिया से हेडर और फिर गतिशील रूप से पर्याप्त मेमोरी आवंटित करें ताकि पूरी प्रतिक्रिया पकड़ सके।
- एक फाइल का जवाब लिखें जैसे ही टुकड़े आते हैं
टिप्पणियों में पूछे गए प्रश्न का उत्तर देने के लिए अतिरिक्त जानकारी:
यदि आप संदेश के मुख्य भाग में डेटा पोस्ट करना चाहते हैं तो क्या होगा? फिर आपको सामग्री-प्रकार: और सामग्री-लंबाई: शीर्षलेख शामिल करने की आवश्यकता है। कंटेंट-लेंथ: ब्लैंक लाइन के बाद हर चीज की वास्तविक लंबाई होती है जो हेडर को शरीर से अलग करती है।
यहाँ एक नमूना है जो निम्नलिखित कमांड लाइन तर्क लेता है:
- मेज़बान
- बंदरगाह
- कमांड (GET या POST)
- पथ (क्वेरी डेटा सहित नहीं)
- क्वेरी डेटा (GST के लिए और POST के लिए निकाय में क्वेरी स्ट्रिंग में डालें)
- हेडर की सूची (सामग्री-लंबाई: स्वचालित है यदि पोस्ट का उपयोग कर)
तो, मूल प्रश्न के लिए आप दौड़ेंगे:
a.out api.somesite.com 80 GET "/apikey=ARG1&command=ARG2"
और टिप्पणियों में पूछे गए प्रश्न के लिए आप दौड़ेंगे:
a.out api.somesite.com 80 POST / "name=ARG1&value=ARG2" "Content-Type: application/x-www-form-urlencoded"
यहाँ कोड है:
#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;
}