就是返回头中没有包含content-length:参数的例如下面这个网页文件, 该如何下载用快车是可以正确下载的需要有TIMEOUT控制功能且能下载未知长度文件的方法
请指教, 谢谢!再问一下,
浏览器又是如何识别网页已经加载完毕的呢?服务器端是否会发送一个结束标志表示文件已传送完毕?

解决方案 »

  1.   

    CHTTPSocket - Class to Explore Web 2002-4-25
    http://www.vchelp.net/vchelp/view_article.asp?ft=1&article_id=283
    封装了HTTP操作的类,支持代理服务HTTP下载类 2002-4-25
    http://www.vchelp.net/vchelp/view_article.asp?ft=2&article_id=291
    基于Winsock2的支持断点续传和SOCKS代理的HTTP下载类AmHttpUtilities 2002-4-25
    http://www.vchelp.net/vchelp/view_article.asp?ft=1&article_id=308
    封装了GET POST方法的HTTP类Multithread server class with example of HTTP server 2002-5-18
    http://www.vchelp.net/vchelp/view_article.asp?ft=1&article_id=738
    一个HTTP服务器的例子
      

  2.   

    楼上说的我都试过了,不行返回头中没有包含content-length:参数的  
     
    例如下面这个网页文件,  该如何下载  
    http://ent.sina.com.cn/x/2005-07-31/1213796953.html
     
    用快车是可以正确下载的  
      

  3.   

    试下这个函数,我就是用这个的BOOL CDownLoadDlg::GetFromWeb(LPSTR pURL, LPSTR SaveAsFilePath)
    {
    CInternetSession session; //会话期对象)
    CHttpConnection* pServer = NULL; // 指向服务器地址(URL)
    CHttpFile * pHttpFile = NULL;//HTTP文件指针
    CString strServerName; //服务器名
    CString strObject; //查询对象名(http文件)
    INTERNET_PORT nPort; //端口
    DWORD dwServiceType; //服务类型
    DWORD dwHttpRequestFlags = //请求标志
    //INTERNET_FLAG_EXISTING_CONNECT;
    INTERNET_FLAG_NO_AUTO_REDIRECT;
    const TCHAR szHeaders[]=_T("Accept: text/* User-Agent:HttpClient ");
    BOOL OK=AfxParseURL( //词法分析
    pURL, //被分析URL串
    dwServiceType, //服务类型,ftp,http等
    strServerName, //服务器名
    strObject, //URL中被查询对象
    nPort ); //URL指定的端口,可能为空
    OK=OK && //本例只考虑http协议
    (dwServiceType ==
    INTERNET_SERVICE_HTTP);
    if (!OK) 
    {
    AfxMessageBox("URL出错"); //报错
    return false; 
    }
    pServer = session.GetHttpConnection(strServerName, nPort); //获得服务器名
    pHttpFile = pServer-> OpenRequest( CHttpConnection::HTTP_VERB_GET,strObject, NULL, 1, NULL, NULL,dwHttpRequestFlags);
    //向服务器发送请求,建立http连接,
    //建立本机上的http文件指针
    pHttpFile->AddRequestHeaders(szHeaders);
    pHttpFile->SendRequest(); //发送请求
    CStdioFile f; //输出文件对象
    //打开输出文件
    if( !f.Open( SaveAsFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary ) ) 
    {
    MessageBox("Unable to open file"); 
    return false;
    }
    //下面将检索结果保存到文件上
    TCHAR szBuf[1024]; //缓存
    int length=0;
    UINT a=pHttpFile->GetLength();
    //pHttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,a);
    while (length=pHttpFile->Read(szBuf, 1023))
    f.Write(szBuf,length);
    f.Close(); //善后工作
    pHttpFile ->Close();
    pServer ->Close();
    if (pHttpFile != NULL) delete pHttpFile;
    if (pServer != NULL) delete pServer;
    session.Close();
    return true;
    }
      

  4.   

    连接结束就表示文件下载完毕,recv正常返回而且返回字节数为0的时候表示连接关闭。
    发请求的时候别要求keep-alive就行
      

  5.   

    char *szHtm = (char *)malloc(1000000);
    CInternetSession sess;
    CHttpFile* pF = (CHttpFile*)sess.OpenURL(strUrl);
    nLength = pF->Read(szHtm, 1000000);
    pF->Close();
    CFile f;
    f.Open("c:\\1.html", CFile::modeCreate | CFile::modeWrite);
    f.Write(szHtm, nLength);
    f.Close();
      

  6.   

    http://ent.sina.com.cn/x/2005-07-31/1213796953.html------------------------------------------------------------------
    GET /x/2005-07-31/1213796953.html HTTP/1.1
    Accept: */*
    User-Agent: Wix; Mozilla/4.0 (compatible; MSIE 6.0; Win32)
    Host: ent.sina.com.cn
    Cookie: UNIPROCT=1-4-2:1|71-0-0:1|60-2-2:1; UNIPROPATH=2:jin0607:0:13505166737:2:|*|1122992214918.3374|pid:60-2-2-0-4370|news.sr/cul/2005-03-01/4370.html|st:111.791|et:1122992214958|http://www.google.com/search?hl=zh-CN&q=%E7%AA%A6%E5%A9%B4&btnG=Google+%E6%90%9C%E7%B4%A2&lr=lang_zh-CN|hp:N|lb:1|*|; bn_stream_speed=301; UNIPROINFO=sz:1024x768||dp:32||ac:Mozilla||an:Microsoft Internet Explorer||av:4.0 (compatible, MSIE 6.0, Windows NT 5.0)||cpu:x86||pf:Win32||jv:1.3||ct:lan||lg:zh-cn||tz:-8
    ------------------------------------------------------------------
    HTTP/1.0 200 OK
    Date: Thu, 11 Aug 2005 07:42:16 GMT
    Server: Apache/2.0.52 (Unix)
    Last-Modified: Sun, 31 Jul 2005 04:52:49 GMT
    ETag: "49e91f-eca0-e2ffca40"
    Accept-Ranges: bytes
    X-Powered-By: mod_xlayout_jh/0.0.1e
    Vary: Accept-Encoding
    Cache-Control: max-age=120
    Expires: Thu, 11 Aug 2005 07:44:16 GMT
    Content-Type: text/html
    Age: 40
    X-Cache: HIT from sqsh-228.sina.com.cn
    Connection: close
    ------------------------------------------------------------------
    LastURL : http://ent.sina.com.cn/x/2005-07-31/1213796953.html
    ContentLength : 0
    Date : 2005-08-11 07:42:16
    LastModified : 2005-07-31 04:52:49
    Expires : 1899-12-30 00:00:00
    Server : Apache/2.0.52 (Unix)
    AcceptRanges : bytes
    ContentType : text/html
    ContentEncodeing : 
    ------------------------------------------------------------------
    这是用WinInet.dll 写的程序下的,是可以正确下载的,下完后大小60576,
    但不清楚WinInet.dll 是如何知道下载完毕的。
      

  7.   

    HTTP/1.0 200 OK
    Date: Thu, 11 Aug 2005 07:42:16 GMT
    Server: Apache/2.0.52 (Unix)
    Last-Modified: Sun, 31 Jul 2005 04:52:49 GMT
    ETag: "49e91f-eca0-e2ffca40"
    Accept-Ranges: bytes
    X-Powered-By: mod_xlayout_jh/0.0.1e
    Vary: Accept-Encoding
    Cache-Control: max-age=120
    Expires: Thu, 11 Aug 2005 07:44:16 GMT
    Content-Type: text/html
    Age: 40
    X-Cache: HIT from sqsh-228.sina.com.cn
    Connection: close                 //这个地方不是说明了下载完毕关闭连接吗,连接关闭表示下载完毕,别告诉我,你不会判断对方关闭连接。
      

  8.   

    如果没有CONTENT LENGTH的话,那么传输到最后,连接断开就是传输完毕呀,很简单的道理。
      

  9.   

    我这方面的代码,要的话发e-mail:[email protected]
      

  10.   

    如果没有CONTENT LENGTH的话,那么传输到最后,连接断开就是传输完毕呀,很简单的道理。
    ---------------------
    就是这样啊,这种方式下载是非常规的哦,你明白了吗?
      

  11.   

    使用wininet api可以下载各种形式的文件。这种未知长度的文件是采用所谓的chunked编码,编码规则就RFC2068的3.6节,下面是我的翻译,如果觉得翻译得不好或喜欢看英文就去看原文吧:参考:RFC2068
    3.6 传输编码传输编码值是用来表示一个传输实体为编码传输以确保其在网络上安全传输。这与那些传输实体的内容编码是不同的。这种编码只是消息的一个属性,而不是针对原始实体。(注:即一个是对头部进行编码,而一个是对内容进行编码)所有的传输编码值都是视情况而定的。HTTP/1.1在传输编码头部使用传输编码值。(参看14.40)传输编码类似于MIME的内容传输编码。它的设计是为了使....块状传输编码修改消息体以使可以传输一系列的大数据块,这些数据块都有自己的长度标识,并且接下来就是一个可有可无的包含实体头部域的页脚。这可以使一些必要的信息可以随动态产生的数据一起传输给接收者,以使接收者可以接收到完整的消息。大数据块(头部)的组成:
    *chunk
    "0"CRLF ---CRLF即为\r\n,CR这\r,LF为\n -- 注意前面如果位数不够,后面用"0"(字符串0即0x20填充)
    footer
    CRLF其中,chunk的组成为:
    chunk-size[chunk-ext] CRLF    -- 中括号中表示字段可有可无
    chunk-data CRLFchunk-size = hex-no-zero * HEX
    hex-no-zero = <HEX excluding "0">chunk-ext = *(";" chunk-ext-name [ "=" chunk-ext-value ] )
    chunk-ext-name  = token
    chunk-ext-value = token | quoted-string
    chunk-data      = chunk-size(0CTET)footer = *entity-header块编码以一个带footer的大小为零的块结尾。使用footer的目的是为了提供一条高效的途径来提供有关动态生成的实体信息。应用程序不能在footer里发送没有显示定义对footer来说合适的头部域。比如Content-MD5或其它对HTPP的未来的数字签名或其它应用。有关处理Chunked-body的解码的例子在19.4.6节中有陈述。所有的HTTP/1.1的应用程序必须能够接收和解码"chunked"传输编码,并且必须忽略那些自己不能理解的传输编码扩展。如果一个服务器收到了一个自身不能理解的传输编码实体,它必须返回501(即没有实现)(给客户端)并且关闭连接。服务方不能发送传输编码给那些HTTP/1.0的客户端。19.4.6      ——有关chunked encoding的解码伪语言表达方式length = 0; // 初始化length为0,这个长度应该为所下载的文件长度
    // 读入chunk-size及chunk-ext(如果有的话)及\r\n
    read chunk-size, chunck-ext(if any) and CRLF
    while(chunk-size > 0) // 如果chunk-size大于0
    {
       read chunk-data and CRLF // 读入chunk数据及\r\n
       append chunk-data to entity-body // 将读到的chunk数据添加到实体(所下载的文件)
       length = length + chunk-size; // 更新文件长度
       read chunk-size and CRLF // 循环读入数据库大小
    }
    // 下面是干什么?循环读入entity-header并添加到已存在的header域中
    read entity-header
    while(entity-header not empty)
    {
       append entity-header to existing header fields
       read entity-header
    }据理解,chunk-size是以字符串形式的十六进制表示的,并且以\r\n结尾。如:61 62 63 0d 0a则表示chunk-size = (HEX)abc = (DEC)2748。参考PHP源码:
    $header = "";
    $response = "";// connect
    if (!($request=fsockopen('whatever.com',80,$errno,$errstr))) exit($errstr);
    else {
       socket_set_timeout($request,10);
       // send request
       fwrite($request,$post);
       // get header -- 读出响应头
       do $header.=fread($request,1); while (!preg_match('/\\r\\n\\r\\n$/',$header));
       // check for chunked encoding
       if (preg_match('/Transfer\\-Encoding:\\s+chunked\\r\\n/',$header))
         do {
             $byte = "";
             $chunk_size="";
             do {
               $chunk_size.=$byte;
               $byte=fread($request,1);
             } while ($byte!="\\r");      // till we match the CR
             fread($request, 1);        // also drop off the LF
             $chunk_size=hexdec($chunk_size); // convert to real number
             $response.=fread($request,$chunk_size);
             fread($request,2);          // ditch the CRLF that trails the chunk
         } while ($chunk_size);        // till we reach the 0 length chunk (end er)
       else {
         // check for specified content length
         if (preg_match('/Content\\-Length:\\s+([0-9]*)\\r\\n/',$header,$matches)) {
             $response=fread($request,$matches[1]);
         } else {
             // not a nice way to do it (may also result in extra CRLF which trails the real content???)
             while (!feof($request)) $response .= fread($request, 4096);
         }
       }
       // close connection
       fclose($request);
    }// do something useful with the response
    print($header);
    print($response);
      

  12.   

    更好的就是用wininet api或用CInternetSession + CHttpConnection + CHttpFile