织梦CMS - 轻松建站从此开始!

罗索

C编程实现http协议

jackyhwei 发布于 2011-09-05 22:51 点击:次 
要实现HTTP下载功能也并不难,只要按照HTTP协议发送request,然后对接收到的数据进行分析,如果页面上还有href之类的链接指向标志就可以进行深一层的下载了。HTTP协议目前用的最多的是1.1版本,要全面透彻地搞懂它就参考RFC2616文档吧。
TAG:

大家都很熟悉HTTP协议的应用,因为每天都在网络上浏览着不少东西,也都知道是HTTP协议是相当简单的。每次用thunder之类的下载软件下载网页,当用到那个“用thunder下载全部链接”时总觉得很神奇。
后来想想,其实要实现这些下载功能也并不难,只要按照HTTP协议发送request,然后对接收到的数据进行分析,如果页面上还有href之类的链接指向标志就可以进行深一层的下载了。HTTP协议目前用的最多的是1.1版本,要全面透彻地搞懂它就参考RFC2616文档吧。我是怕rfc文档了的,要看自己去看吧^_^
源代码如下:
/******* http客户端程序 httpclient.c ************/

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <string.h> 
  4. #include <sys/types.h> 
  5. #include <sys/socket.h> 
  6. #include <errno.h> 
  7. #include <unistd.h> 
  8. #include <netinet/in.h> 
  9. #include <limits.h> 
  10. #include <netdb.h> 
  11. #include <arpa/inet.h> 
  12. #include <ctype.h> 
  13.  
  14. /******************************************** 
  15. 功能:搜索字符串右边起的第一个匹配字符 
  16. ********************************************/ 
  17. char * Rstrchr(char * s, char x) { 
  18.   int i = strlen(s); 
  19.   if(!(*s)) return 0; 
  20.   while(s[i-1]) if(strchr(s + (i - 1), x)) return (s + (i - 1)); else i--; 
  21.   return 0; 
  22.  
  23. /******************************************** 
  24. 功能:把字符串转换为全小写 
  25. ********************************************/ 
  26. void ToLowerCase(char * s) { 
  27.   while(s && *s) {*s=tolower(*s);s++;} 
  28.  
  29. /************************************************************** 
  30. 功能:从字符串src中分析出网站地址和端口,并得到用户要下载的文件 
  31. ***************************************************************/ 
  32. void GetHost(char * src, char * web, char * file, int * port) { 
  33.   char * pA; 
  34.   char * pB; 
  35.   memset(web, 0, sizeof(web)); 
  36.   memset(file, 0, sizeof(file)); 
  37.   *port = 0; 
  38.   if(!(*src)) return
  39.    pA = src; 
  40.   if(!strncmp(pA, "http://", strlen("http://")))
  41.  pA = src+strlen("http://"); 
  42.   else if(!strncmp(pA, "https://", strlen("https://")))
  43.  pA = src+strlen("https://"); 
  44.    pB = strchr(pA, '/'); 
  45.   if(pB) { 
  46.     memcpy(web, pA, strlen(pA) - strlen(pB)); 
  47.     if(pB+1) { 
  48.       memcpy(file, pB + 1, strlen(pB) - 1); 
  49.       file[strlen(pB) - 1] = 0; 
  50.     } 
  51.   } 
  52.   else memcpy(web, pA, strlen(pA)); 
  53.   if(pB) web[strlen(pA) - strlen(pB)] = 0; 
  54.   else web[strlen(pA)] = 0; 
  55.    pA = strchr(web, ':'); 
  56.   if(pA) *port = atoi(pA + 1); 
  57.   else *port = 80; 
  58.  
  59.  
  60. int main(int argc, char *argv[]) 
  61.   int sockfd; 
  62.   char buffer[1024]; 
  63.   struct sockaddr_in server_addr; 
  64.   struct hostent *host; 
  65.   int portnumber,nbytes; 
  66.   char host_addr[256]; 
  67.   char host_file[1024]; 
  68.   char local_file[256]; 
  69.   FILE * fp; 
  70.   char request[1024]; 
  71.   int send, totalsend; 
  72.   int i; 
  73.   char * pt; 
  74.  
  75.   if(argc!=2) 
  76.   { 
  77.     fprintf(stderr,"Usage:%s web-address/a/n",argv[0]); 
  78.     exit(1); 
  79.   } 
  80.   printf("parameter.1 is: %s/n", argv[1]); 
  81.    ToLowerCase(argv[1]);/*将参数转换为全小写*/ 
  82.   printf("lowercase parameter.1 is: %s/n", argv[1]); 
  83.  
  84. GetHost(argv[1], host_addr, host_file, &portnumber);/*分析网址、端口、文件名等*/ 
  85.   printf("webhost:%s/n", host_addr); 
  86.   printf("hostfile:%s/n", host_file); 
  87.   printf("portnumber:%d/n/n", portnumber); 
  88.  
  89.   if((host=gethostbyname(host_addr))==NULL)/*取得主机IP地址*/ 
  90.   { 
  91.     fprintf(stderr,"Gethostname error, %s/n", strerror(errno)); 
  92.     exit(1); 
  93.   } 
  94.  
  95.   
  96.  
  97.   /* 客户程序开始建立 sockfd描述符 */ 
  98.   if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)/*建立SOCKET连接*/ 
  99.   { 
  100.     fprintf(stderr,"Socket Error:%s/a/n",strerror(errno)); 
  101.     exit(1); 
  102.   } 
  103.  
  104.   /* 客户程序填充服务端的资料 */ 
  105.    bzero(&server_addr,sizeof(server_addr)); 
  106.    server_addr.sin_family=AF_INET; 
  107.    server_addr.sin_port=htons(portnumber); 
  108.    server_addr.sin_addr=*((struct in_addr *)host->h_addr); 
  109.  
  110.   /* 客户程序发起连接请求 */ 
  111.   if(connect(sockfd,(struct sockaddr *)(&server_addr)
  112. ,sizeof(struct sockaddr))==-1)/*连接网站*/ 
  113.   { 
  114.     fprintf(stderr,"Connect Error:%s/a/n",strerror(errno)); 
  115.     exit(1); 
  116.   } 
  117.  
  118.   sprintf(request, "GET /%s HTTP/1.1/r/nAccept:
  119.  */*/r/nAccept-Language: zh-cn/r/n/ 
  120. User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)/r/n/ 
  121. Host: %s:%d/r/nConnection: Close/r/n/r/n", host_file, host_addr, portnumber); 
  122.   printf("%s", request);/*准备request,将要发送给主机*/ 
  123.  
  124.   /*取得真实的文件名*/ 
  125.   if(host_file && *host_file) pt = Rstrchr(host_file, '/'); 
  126.   else pt = 0; 
  127.  
  128.   memset(local_file, 0, sizeof(local_file)); 
  129.   if(pt && *pt) { 
  130.     if((pt + 1) && *(pt+1)) strcpy(local_file, pt + 1); 
  131.     else memcpy(local_file, host_file, strlen(host_file) - 1); 
  132.   } 
  133.   else if(host_file && *host_file) strcpy(local_file, host_file); 
  134.   else strcpy(local_file, "index.html"); 
  135.   printf("local filename to write:%s/n/n", local_file); 
  136.  
  137.   /*发送http请求request*/ 
  138.   send = 0;totalsend = 0; 
  139.    nbytes=strlen(request); 
  140.   while(totalsend < nbytes) { 
  141.     send = write(sockfd, request + totalsend, nbytes - totalsend); 
  142.     if(send==-1) {printf("send error!%s/n", strerror(errno));exit(0);} 
  143.      totalsend+=send; 
  144.     printf("%d bytes send OK!/n", totalsend); 
  145.   } 
  146.  
  147.    fp = fopen(local_file, "a"); 
  148.   if(!fp) { 
  149.     printf("create file error! %s/n", strerror(errno)); 
  150.     return 0; 
  151.   } 
  152.   printf("/nThe following is the response header:/n"); 
  153.    i=0; 
  154.   /* 连接成功了,接收http响应,response */ 
  155.   while((nbytes=read(sockfd,buffer,1))==1) 
  156.   { 
  157.     if(i < 4) { 
  158.       if(buffer[0] == '/r' || buffer[0] == '/n') i++; 
  159.       else i = 0; 
  160.       printf("%c", buffer[0]);/*把http头信息打印在屏幕上*/ 
  161.     } 
  162.     else { 
  163.       fwrite(buffer, 1, 1, fp);/*将http主体信息写入文件*/ 
  164.        i++; 
  165.       if(i%1024 == 0) fflush(fp);/*每1K时存盘一次*/ 
  166.     } 
  167.   } 
  168.   fclose(fp); 
  169.   /* 结束通讯 */ 
  170.   close(sockfd); 
  171.   exit(0); 

zj@zj:~/C_pram/practice/http_client$ ls
httpclient httpclient.c
zj@zj:~/C_pram/practice/http_client$ ./httpclient http://www.rg4.net/
parameter.1 is: http://www.rg4.net/
lowercase parameter.1 is: http://www.rg4.net/
webhost:www.rg4.net
hostfile:
portnumber:80

GET / HTTP/1.1
Accept: */*
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Host: www.rg4.net:80
Connection: Close

local filename to write:index.html

163 bytes send OK!

The following is the response header:
HTTP/1.1 200 OK
Date: Wed, 29 Oct 2008 10:41:40 GMT
Server: BWS/1.0
Content-Length: 4216
Content-Type: text/html
Cache-Control: private
Expires: Wed, 29 Oct 2008 10:41:40 GMT
Set-Cookie: BAIDUID=A93059C8DDF7F1BC47C10CAF9779030E:FG=1; expires=Wed, 29-Oct-38 10:41:40 GMT; path=/; domain=.rg4.net
P3P: CP=" OTI DSP COR IVA OUR IND COM "

zj@zj:~/C_pram/practice/http_client$ ls
httpclient httpclient.c index.html

不指定文件名字的话,默认就是下载网站默认的首页了^0^.

(yufangbo)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201109/14955.html]
本文出处:blog.csdn.net/yufangbo 作者:yufangbo
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容