zoukankan      html  css  js  c++  java
  • 用c socket 方式下载网页

    http://blog.csdn.net/gggxin/article/details/588498

    用c socket 方式下载网页

    分类: c程序 1367人阅读 评论(0) 收藏 举报

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <fcntl.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #define MaxRecvLen  500

    //定义网站结构
    struct DOMAIN
    {
     char url[255];      //http://www.xh88.com:80/index.php 完整网址
     char host[20];      //www.xh88.com  主机地址
     int  port;       //sock 联接的端口号
    };
    typedef struct DOMAIN domain;

    int main(int argc,char *argv[])
    {

    //******************* 有关 sock 的变量 *************************

     int sock_id;       //sock 联接句柄

     struct hostent *hostbyname;    //主机的信息 结构
     struct sockaddr_in remote_addr;   //包含远端主机IP地址和端口号的结构


    //******************* 有关 无阻塞 select 所用到 的变量 *************************

     struct timeval timeout;     //用于无阻塞 select 调用 的时间变量
     fd_set sockid_readable;     //sock 类似联接句柄 传递给 select 有效的连接

     domain web_domain;      //定义一个 web domain 的结构

     char send_str[255];      //保存要发送的字符串
     char *tempStr,*recBuf;     //临时字串,接收到的字串指针

     int recv_numb;       //保存远端返回的字串大小
     FILE *fp;        //文件指针,用于保存从远端得到的数据
     char *tmpfile;       //临时文件名

     timeout.tv_sec = 1;      //设置几秒钟超时
     timeout.tv_usec = 500000;    //设置几微秒超时
     web_domain.port=80;      //默认端口 为 80

     tmpfile="abc.txt";
    //******************* 处理命令行的参数 *************************

     if(argc<2)      //参数不足
     { printf("%s","/n/nExp: ./client http://192.168.1.254:80 /n/n");
      exit(1);
     }
     if(!(tempStr=strstr(argv[1],"http://")))   //必须以 http://开头
     { printf("parameter error!/n");
      exit(0);
     }
     strcpy(web_domain.url,tempStr);      //http://www.xh88.com:80/index.php
     strcpy(web_domain.host,web_domain.url+7);   //www.xh88.com
     //处理 host
     if((tempStr=strstr(web_domain.host,"/")))
     { *tempStr='/0';         //web_domain.host 里去除:后的东西
     }
     if((tempStr=strstr(web_domain.host,":")))
     { *tempStr='/0';         //Host 里去除:后的东西
      web_domain.port=atoi(tempStr+1);    //改写端口
     }
    //!
    printf("%s/n%d/n%s/n",web_domain.host,web_domain.port,web_domain.url);

     hostbyname = gethostbyname(web_domain.host);  //将基本名字和地址转换
     if((sock_id=socket(PF_INET,SOCK_STREAM,0))==-1)
     { perror("socket");
      exit(1);
     }

    //初始化远端要传递的socket
     remote_addr.sin_family=AF_INET;      //地址族
     remote_addr.sin_port=htons(web_domain.port);  //端口号
     remote_addr.sin_addr=*((struct in_addr *)hostbyname->h_addr);  //IP地址
     bzero(&(remote_addr.sin_zero),8);     //填充0 以保持与struct sockaddr同样大小

    //和服务器建立连接
     if(connect(sock_id,(struct sockaddr *)&remote_addr,sizeof(remote_addr))==-1)
     { perror("connect");
      exit(1);
     }
    printf("/n/nconnected %s:%d ok!/n/n",web_domain.url,web_domain.port);

    //创建要发送给远端的字串
     sprintf(send_str,"GET %s HTTP/1.1/nAccept: */*/nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)/nHost: %s/n/n",web_domain.url,web_domain.host);
     printf("%s/n/n",send_str);
    //开始向服务器发送数据
     if(send(sock_id,send_str,strlen(send_str),0)==-1)
     { perror("send");
      exit(1);
     }
     recBuf=malloc(MaxRecvLen);  //为储存远端返回的字串的变量申请空间
     //fp=fopen(tmpfile,"w");
     while(1)
     {

    //设置无堵塞模式
      FD_ZERO(&sockid_readable);
      FD_SET(sock_id,&sockid_readable);
      select(sock_id+1, &sockid_readable, NULL, NULL, &timeout);
      if (!FD_ISSET(sock_id, &sockid_readable))
      { printf("Timed out./n");
       break;
      }
      recv_numb = recv(sock_id,recBuf,MaxRecvLen,0); //得到远端返回的字串
      recBuf[recv_numb]='/0';

      //fputs(fp,);
      // fp=fopen(tmpfile,"w");
      printf("/n/t********* %d *******",recv_numb);
      printf("%s",recBuf);
      if(recv_numb<1)  //返回的长度不够退出循环
       break;
     }

     printf("/n/nrecv  ok!/n/n");
     close(sock_id);
     return 0;
    }


    socket下载网页时网络阻塞

      2006-9-25 00:00
    提问者:songma931 | 悬赏分:20 | 浏览次数:1735次
    我用socket写了个小程序,用来下载一个网页的HTML文件,connect和connect以前都没有问题,当recv的返回值是0的时候,就显示下载完毕.
    我用它来下mail.163.com的HTML的时候,什么问题也没有,但如果用来下zhidao.baidu.com的HTML的时候,明明整个HTML都下载下来了,可它却不马上显示下载完毕,停在recv(),要过一些时间才显示下载完毕.
    哪位大虾给解释一下啊.它在停下的这一些时间里做什么,以及怎么避免这种情况发生.没时间大体给分析一下也可以啊.
    检举 | 2006-10-1 14:59
     最佳答案
    这个问题涉及到HTTP协议。
    
    估计zhidao默认是以KeepAlive的方式处理HTTP请求的,就是说服务器端会保持连接一段时间,以便重新利用该连接接受新的HTTP请求。
    
    解决的办法是 
    1. 发送HTTP请求的时候主动要求不使用KeepAlive;
    2. 或者对服务器返回的内容做分析,根据返回的头部信息能够知道数据的长度或者数据块的大小和数目(如果是以Transfer-Encoding: chunked的方式返回),这样就能确定是否已经接受了所有的数据,然后进行主动close().
    
    另外补充一下: 自己写socket程序下载网页会涉及到很多问题,比如有些服务器是把数据压缩后返回的,比如google的有些服务,你还需要对它进行解压还原。
    因此,建议使用一些已有的库进行开发会比较方便一点,推荐使用libcurl来处理HTTP/FTP。
  • 相关阅读:
    hdu 5534(dp)
    hdu 5533(几何水)
    hdu 5532(最长上升子序列)
    *hdu 5536(字典树的运用)
    hdu 5538(水)
    假如数组接收到一个null,那么应该怎么循环输出。百度结果,都需要提前判断。否则出现空指针异常。。我还是想在数组中实现保存和输出null。
    第一个登录页面 碰到的疑问
    浅谈堆和栈的区别
    Java中的基础----堆与栈的介绍、区别
    JS的Document属性和方法
  • 原文地址:https://www.cnblogs.com/lexus/p/2248867.html
Copyright © 2011-2022 走看看