用vc6提供的方法,哪种方法能够很稳定地读取网页内容(能够兼容死链接而不过于超时)?我用组件读取,不是很稳定,用CHttpFile,好了一些,但依然不是非常稳定。请教网络编程高手。

解决方案 »

  1.   

    如果是只是要取得当前访问的网页内容:
    通过CHtmlView类的派生类,在它的OnDocumentComplete函数中添加:
    HRESULT hr;
    IDispatch *pDispathDoc = NULL;
    CComPtr<IHTMLDocument2>  pHTMLDoc;
    CComPtr<IHTMLElement> pHTMLBody;
    BSTR bstrInnerHTML;
    pDispathDoc = GetHtmlDocument();
    if(pDispathDoc == NULL)
    return;
    hr = pDispathDoc->QueryInterface(__uuidof(IHTMLDocument2), (void**)&pHTMLDoc);
    if(FAILED(hr))
    return;
    hr = pHTMLDoc->get_body(&pHTMLBody);
    pHTMLBody->get_innerHTML(&bstrInnerHTML);
    CString sInnerHTML =CString( bstrInnerHTML);那么sInnerHTML 里的内容就是你浏览器窗口里的html源代码了,你自己再将它另存为即可。
    想要下载东西才用其它方法
      

  2.   

    CInternetSession 类系列,还是很稳定的
    如果需要更精细的控制,使用SOCKET 应该更好
    我在使用中,多数情况下,偏好SOCKET,应为更灵活,但是代码麻烦一些
    普通情况下,就使用CInternetSession 类系列,简单性能上,我的比较还是 SOCKET 要好一些
      

  3.   

    读取网页的程序通常应该有这样一些概念
    1、多线程:每一个读取,应该是在一个单独的线程里工作
    2、socket概念:一般使用同步阻塞模式,connect是否成功,很快就会返回,由此判定服务器相应服务是否可用,webserver通常80端口,程序中要做的是如果连接不成功,重复试几次的问题
    3、HTTP协议,要自己写SOCKET网页下载程序,需要熟悉HTTP协议,详细了解浏览器与WEB SERVER是这样建立通信、传送数据的, HTTP应该说是比较简单的。通常连接成功以后,需要判断状态码,看是否请求被服务器理解并正常完成
    使用socket底层编码,不会有“最长的有读死链接而导致3-4个小时线程才结束的情况”,因为一些都是可以控制的。我在使用中,就是用CInternetSession封装类,也从未发生你说的情况,不过阻塞十分钟左右的情况是有的,所以对于效率上有要求的还是不要使用简单的类或者组件,自己研究研究...
      

  4.   

    HRESULT hr;
    IDispatch *pDispathDoc = NULL;
    CComPtr<IHTMLDocument2>  pHTMLDoc;
    CComPtr<IHTMLElement> pHTMLBody;
    BSTR bstrInnerHTML;
    pDispathDoc = GetHtmlDocument();
    if(pDispathDoc == NULL)
    return;
    hr = pDispathDoc->QueryInterface(__uuidof(IHTMLDocument2), (void**)&pHTMLDoc);
    if(FAILED(hr))
    return;
    hr = pHTMLDoc->get_body(&pHTMLBody);
    pHTMLBody->get_innerHTML(&bstrInnerHTML);
    CString sInnerHTML =CString( bstrInnerHTML
      

  5.   

    我也是使用CInternetSession.OpenUrl  和CHttpFile来读取网页,对有极少数的网页会造成阻塞,CPU占有率竟达到了90%几,造成系统死机。不知道有什么方法能解决?楼主找到解决方法,通知我一声。
      

  6.   

    CInternetSession是可以
    不过好像弄个线程类 好像更好!
      

  7.   

    用阻塞socket设置timeout也不一定每次都能成功,我试了,也会很久不动,不知道什么原因不会返回
      

  8.   

    这个是最有效得办法了
    http://www.zeali.net/entry/13
      

  9.   

    用非阻塞实现连接超时和接收发送超时
    /*
     * on Unix:
     *    cc -c connector.c
     *    cc -o connector connector.o
     *
     * on Windows NT:
     *    open connector.c in Visual Studio
     *    press 'F7' to link -- a project to be created
     *    add wsock32.lib to the link section under project setting
     *    press 'F7' again
     *
     * running:
     *    type 'connector' for usage
     */#include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdarg.h>
    #include <errno.h>
    #include <fcntl.h>
    #ifdef WIN32
    #include <winsock2.h>
    #else
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #endif#ifndef INADDR_NONE
    #define INADDR_NONE     0xffffffff
    #endif
    #define MAX_STRING_LEN  1024
    #define BUFSIZE  2048#ifndef WIN32
    #define SOCKET int
    #else
    #define errno WSAGetLastError()
    #define close(a) closesocket(a)
    #define write(a, b, c) send(a, b, c, 0)
    #define read(a, b, c) recv(a, b, c, 0)
    #endifchar buf[BUFSIZE];static char i_host[MAX_STRING_LEN];  /* site name */
    static char i_port[MAX_STRING_LEN];  /* port number */void err_doit(int errnoflag, const char *fmt, va_list ap);
    void err_quit(const char *fmt, ...);
    int tcp_connect(const char *host, const unsigned short port);
    void print_usage();//xnet_select x defines
    #define READ_STATUS  0
    #define WRITE_STATUS 1
    #define EXCPT_STATUS 2/*
    s    - SOCKET
    sec  - timeout seconds
    usec - timeout microseconds
    x    - select status
    */
    SOCKET xnet_select(SOCKET s, int sec, int usec, short x)
    {
     int st = errno;
     struct timeval to;
     fd_set fs;
     to.tv_sec = sec;
     to.tv_usec = usec;
     FD_ZERO(&fs);
     FD_SET(s, &fs);
     switch(x){
      case READ_STATUS:
      st = select(s+1, &fs, 0, 0, &to);
      break;
      case WRITE_STATUS:
      st = select(s+1, 0, &fs, 0, &to);
      break;
      case EXCPT_STATUS:
      st = select(s+1, 0, 0, &fs, &to);
      break;
     }
     return(st);
    }int tcp_connect(const char *host, const unsigned short port)
    {
        unsigned long non_blocking = 1;
        unsigned long blocking = 0;
        int ret = 0;
        char * transport = "tcp";
        struct hostent      *phe;   /* pointer to host information entry    */
        struct protoent *ppe;       /* pointer to protocol information entry*/
        struct sockaddr_in sin;     /* an Internet endpoint address  */
        SOCKET s;                    /* socket descriptor and socket type    */
        int error;#ifdef WIN32
        {
            WORD wVersionRequested;
            WSADATA wsaData;
            int err;
     
            wVersionRequested = MAKEWORD( 2, 0 );
     
            err = WSAStartup( wVersionRequested, &wsaData );
            if ( err != 0 ) {
                /* Tell the user that we couldn't find a usable */
                /* WinSock DLL.                               */
                printf("can't initialize socket library\n");
                exit(0);
            }
        }
    #endif    
        
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        
        if ((sin.sin_port = htons(port)) == 0)
            err_quit("invalid port \"%d\"\n", port);
        
        /* Map host name to IP address, allowing for dotted decimal */
        if ( phe = gethostbyname(host) )
            memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
        else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
            err_quit("can't get \"%s\" host entry\n", host);
        
        /* Map transport protocol name to protocol number */
        if ( (ppe = getprotobyname(transport)) == 0)
            err_quit("can't get \"%s\" protocol entry\n", transport);
        
        /* Allocate a socket */
        s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
        if (s < 0)
            err_quit("can't create socket: %s\n", strerror(errno));
        
        /* Connect the socket with timeout */
    #ifdef WIN32
        ioctlsocket(s,FIONBIO,&non_blocking);
    #else
        ioctl(s,FIONBIO,&non_blocking);
    #endif
        //fcntl(s,F_SETFL, O_NONBLOCK);
        if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1){
            struct timeval tv; 
            fd_set writefds;
            // 设置连接超时时间
            tv.tv_sec = 10; // 秒数
            tv.tv_usec = 0; // 毫秒
            FD_ZERO(&writefds); 
            FD_SET(s, &writefds); 
            if(select(s+1,NULL,&writefds,NULL,&tv) != 0){ 
                if(FD_ISSET(s,&writefds)){
                    int len=sizeof(error); 
                    //下面的一句一定要,主要针对防火墙 
                    if(getsockopt(s, SOL_SOCKET, SO_ERROR,  (char *)&error, &len) < 0)
                        goto error_ret; 
                    if(error != 0) 
                        goto error_ret; 
                }
                else
                    goto error_ret; //timeout or error happen 
            }
            else goto error_ret; ; #ifdef WIN32
            ioctlsocket(s,FIONBIO,&blocking);
    #else
            ioctl(s,FIONBIO,&blocking);
    #endif    }
        else{
    error_ret:
            close(s);
            err_quit("can't connect to %s:%d\n", host, port);
        }
        return s;
    }void err_doit(int errnoflag, const char *fmt, va_list ap)
    {
        int errno_save;
        char buf[MAX_STRING_LEN];    errno_save = errno; 
        vsprintf(buf, fmt, ap);
        if (errnoflag)
            sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
        strcat(buf, "\n");
        fflush(stdout);
        fputs(buf, stderr);
        fflush(NULL);
        return;
    }
      

  10.   

    /* Print a message and terminate. */
    void err_quit(const char *fmt, ...)
    {
        va_list ap;
        va_start(ap, fmt);
        err_doit(0, fmt, ap);
        va_end(ap);
        exit(1);
    }#ifdef WIN32
    char *optarg;char getopt(int c, char *v[], char *opts)
    {
        static int now = 1;
        char *p;    if (now >= c) return EOF;    if (v[now][0] == '-' && (p = strchr(opts, v[now][1]))) {
            optarg = v[now+1];
            now +=2;
            return *p;
        }    return EOF;
    }#else
    extern char *optarg;
    #endif#define required(a) if (!a) { return -1; }int init(int argc, char *argv[])
    {
        char c;
        //int i,optlen;
        //int slashcnt;    i_host[0]  =  '\0';
        i_port[0]  =  '\0';    while ((c = getopt(argc, argv, "h:p:?")) != EOF) {
            if (c == '?')
                return -1;
            switch (c) { 
            case 'h':
                required(optarg);
                strcpy(i_host, optarg);
                break;
            case 'p':
                required(optarg);
                strcpy(i_port, optarg);
                break;
            default:
                return -1;
            }
        }    /* 
         * there is no default value for hostname, port number, 
         * password or uri
         */
        if (i_host[0] == '\0' || i_port[0] == '\0')
            return -1;    return 1;
    }void print_usage()
    {
        char *usage[] =
        {
            "Usage:",
            "    -h    host name",
            "    -p    port",
            "example:",
            "    -h 127.0.0.1 -p 4001",
        };   
        int i;    for (i = 0; i < sizeof(usage) / sizeof(char*); i++)
            printf("%s\n", usage[i]);
        
        return;
    }int main(int argc, char *argv[])
    {
        SOCKET fd;
        int n;    /* parse command line etc ... */
        if (init(argc, argv) < 0) {
            print_usage();
            exit(1);
        }    buf[0] = '\0';    /* pack the info into the buffer */     
        strcpy(buf, "HelloWorld");    /* make connection to the server */
        fd = tcp_connect(i_host, (unsigned short)atoi(i_port));    if(xnet_select(fd, 0, 500, WRITE_STATUS)>0){
            /* send off the message */
            write(fd, buf, strlen(buf));
        }
        else{
            err_quit("Socket I/O Write Timeout %s:%s\n", i_host, i_port);
        }    if(xnet_select(fd, 3, 0, READ_STATUS)>0){
            /* display the server response */
            printf("Server response:\n");
            n = read(fd, buf, BUFSIZE);
            buf[n] = '\0';
            printf("%s\n", buf);
        }
        else{
            err_quit("Socket I/O Read Timeout %s:%s\n", i_host, i_port);
        }
        close(fd);#ifdef WIN32
        WSACleanup();
    #endif    return 0;
    }