C++:C語言實現HTTP的GET和POST請求
HTTP請求和IP/TCP
所謂的HTTP協議是基於IP/TCP協議的, 所以要獲取遠端的html數據只要創建socket對象就足夠了;
HTTP是基於IP/TCP加上了網絡請求的固定格式, 比如:
運行下面代碼
method URL Content-host Content-Type Content-Length
實現GET請求
把組合成的數據按照固定的格式發送給服務器, 服務器解析相應的格式, 然后返回服務器數據:
運行下面代碼
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define IPSTR "42.121.252.58" //服務器IP地址;
#define PORT 80
#define BUFSIZE 1024
int main(int argc, char **argv)
{
int sockfd, ret, i, h;
struct sockaddr_in servaddr;
char str1[4096], str2[4096], buf[BUFSIZE], *str;
socklen_t len;
fd_set t_set1;
struct timeval tv;
//創建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("創建網絡連接失敗,本線程即將終止---socket error!\n");
exit(0);
};
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, IPSTR, &servaddr.sin_addr) <= 0 ){
printf("創建網絡連接失敗,本線程即將終止--inet_pton error!\n");
exit(0);
};
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
printf("連接到服務器失敗,connect error!\n");
exit(0);
}
printf("與遠端建立了連接\n");
memset(str2, 0, 4096);
strcat(str2, "theDataToPost");
str=(char *)malloc(128);
len = strlen(str2);
sprintf(str, "%d", len);
memset(str1, 0, 4096);
strcat(str1, "GET /ymnets/p/6255674.html HTTP/1.1\n");
strcat(str1, "Host: www.cnblogs.com\n");
strcat(str1, "Content-Type: text/html\n");
strcat(str1, "Content-Length: ");
strcat(str1, str);
strcat(str1, "\n\n");
strcat(str1, str2);
strcat(str1, "\r\n\r\n");
printf("%s\n",str1);
ret = write(sockfd,str1,strlen(str1));
if (ret < 0) {
printf("發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n",errno, strerror(errno));
exit(0);
}else{
printf("消息發送成功,共發送了%d個字節!\n\n", ret);
}
FD_ZERO(&t_set1);
FD_SET(sockfd, &t_set1);
while(1){
sleep(2);
tv.tv_sec= 0;
tv.tv_usec= 0;
h= 0;
printf("--------------->1");
h= select(sockfd +1, &t_set1, NULL, NULL, &tv);
printf("--------------->2");
//if (h == 0) continue;
if (h < 0) {
close(sockfd);
printf("在讀取數據報文時SELECT檢測到異常,該異常導致線程終止!\n");
return -1;
};
if (h > 0){
memset(buf, 0, 4096);
i= read(sockfd, buf, 4095);
if (i==0){
close(sockfd);
printf("讀取數據報文時發現遠端關閉,該線程終止!\n");
return -1;
}
printf("%s\n", buf);
}
}
close(sockfd);
return 0;
}
實現POST請求:
C實現POST請求參考代碼, 只要把請求類型從GET改為POST, 然后把請求的數據代入到請求頭中即可:
運行下面代碼
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define IPSTR "61.147.124.120"
#define PORT 80
#define BUFSIZE 1024
int main(int argc, char **argv)
{
int sockfd, ret, i, h;
struct sockaddr_in servaddr;
char str1[4096], str2[4096], buf[BUFSIZE], *str;
socklen_t len;
fd_set t_set1;
struct timeval tv;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("創建網絡連接失敗,本線程即將終止---socket error!\n");
exit(0);
};
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
if (inet_pton(AF_INET, IPSTR, &servaddr.sin_addr) <= 0 ){
printf("創建網絡連接失敗,本線程即將終止--inet_pton error!\n");
exit(0);
};
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
printf("連接到服務器失敗,connect error!\n");
exit(0);
}
printf("與遠端建立了連接\n");
memset(str2, 0, 4096);
strcat(str2, "qqCode=287101329");
str=(char *)malloc(128);
len = strlen(str2);
sprintf(str, "%d", len);
memset(str1, 0, 4096);
strcat(str1, "POST /webservices/qqOnlineWebService.asmx/qqCheckOnline HTTP/1.1\n");
strcat(str1, "Host: www.webxml.com.cn\n");
strcat(str1, "Content-Type: application/x-www-form-urlencoded\n");
strcat(str1, "Content-Length: ");
strcat(str1, str);
strcat(str1, "\n\n");
//str2的值為post的數據
strcat(str1, str2);
strcat(str1, "\r\n\r\n");
printf("%s\n",str1);
ret = write(sockfd,str1,strlen(str1));
if (ret < 0) {
printf("發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n",errno, strerror(errno));
exit(0);
}else{
printf("消息發送成功,共發送了%d個字節!\n\n", ret);
}
FD_ZERO(&t_set1);
FD_SET(sockfd, &t_set1);
while(1){
sleep(2);
tv.tv_sec= 0;
tv.tv_usec= 0;
h= 0;
printf("--------------->1");
h= select(sockfd +1, &t_set1, NULL, NULL, &tv);
printf("--------------->2");
//if (h == 0) continue;
if (h < 0) {
close(sockfd);
printf("在讀取數據報文時SELECT檢測到異常,該異常導致線程終止!\n");
return -1;
};
if (h > 0){
memset(buf, 0, 4096);
i= read(sockfd, buf, 4095);
if (i==0){
close(sockfd);
printf("讀取數據報文時發現遠端關閉,該線程終止!\n");
return -1;
}
printf("%s\n", buf);
}
}
close(sockfd);
return 0;
}
POST請求的方式可以再改改:
運行下面代碼
View Code
請求一個HTTP服務器的數據, 接收一個參數為請求的服務器IP:
運行下面代碼
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
int main(int argc, char *argv[]){
if(argc!=2){
printf("error usage %s ip\n",argv[0]);
return 1;
}
int sockfd;
int len;
struct sockaddr_in address;
int result;
char httpstring[100];
sprintf(httpstring,"GET / HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: Close\r\n\r\n",argv[1]);
char ch;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(argv[1]);
address.sin_port = htons(80);
len = sizeof(address);
result = connect(sockfd,(struct sockaddr *)&address,len);
if(result == -1){
perror("oops: client");
return 1;
}
write(sockfd,httpstring,strlen(httpstring));
while(read(sockfd,&ch,1)){
printf("%c", ch);
}
close(sockfd);
printf("\n");
return 0;
}
使用gcc編譯以后執行: sudo ./req 42.121.252.58


