比如大家可以抓包看一下
http://www.flyrom.com/PHPWind_UTF8_4.3.2/upload/ck.php?windid=真郁闷,如果不但不返回Content-Length 而且HTTP协议头后面(#13#10#13#10)并不是正文的开始,而是 XXX+空格+空格+#13#10后面才是正文注:
XXX有时候是16进制的正文长度比如“d3af8”此时后面的2个空格是没有的,这样我也可以计算到长度并处理。
但有时候则是完全无意义的数字,真是搞不懂。不过浏览器倒是完全可以处理这种情况,不知道是如何处理的。我看了HTTP的RFC但是找不到,或者哪位仁兄发来详细的HTTP RFC文档。

解决方案 »

  1.   

    并不是所有的的HTTP文件都会返回Content-Length,有的是所谓的chunked,客户端不知道文件的大小,只能不停地接收,只到没有数据了,即recv返回0或错误
      

  2.   

    没有长度也可以处理,但问题是有时候 协议头结束后开始的第一字节并不是正文。我发现好像Unlix的系统会出现这种情况,HTTP头没有包含长度,而是在头结束后第一字节到#13#10之间是一个16进制的主体长度。必须处理这种情况,否则得到的主体头部多出N字节。还有一种情况更离谱,就是我上面说的,头结束后第一字节到#13#10之间是一个包含空格的未知数字,根本没法处理阿。
      

  3.   

    以前写过,见笑了,是datachunked.自从遇见此类BT网站过,我还是改用CHttp了.DWORD WINAPI CHttpIO::ReceiveChunkedThread(LPVOID pParam)
    { SOCKET Socket = ((SOCKET )((void **)pParam)[0]);
    char *pHtmlBuf = (char *)((void **)pParam)[1];
    int nHtmlBufLen = (int)((void **)pParam)[2];
    CString *pCookie = (CString *)((void **)pParam)[3];
    CEvent *pCreateRecvChunkedEvent = (CEvent *)((void **)pParam)[4];
    CEvent *pGetHtmlEvent = (CEvent *)((void **)pParam)[5];
    pCreateRecvChunkedEvent->SetEvent(); // 接收HTTP头信息
    char szRecvBuf[2048]={0};
    int nRecvLen = 0; // 找HTTP头的结尾
    while(true)
    {
    int nTmpRecvLen = recv(Socket,(char *)szRecvBuf+nRecvLen,sizeof(szRecvBuf),0);
    // 错误,悲观处理
    if (nTmpRecvLen < 1)
    break;
    nRecvLen += nTmpRecvLen; // 找http头的结尾
    char *pHtmlPack = strstr(szRecvBuf, "\r\n\r\n");
    if(pHtmlPack != NULL)
    {
    /*
    // 找cookie
    int nContentLength = {0};
    for (int nCurParse = 0;nCurParse < pHtmlPack-szRecvBuf;)
    {
    // 取出当前行
    char szCurLineData[2048] = {0};
    char *pEol = strstr(szRecvBuf+nCurParse, "\r\n") + strlen("\r\n");
    int nCurLineLen = pEol - (szRecvBuf+nCurParse);
    memcpy(szCurLineData, szRecvBuf+nCurParse, nCurLineLen);
    nCurParse += nCurLineLen; CString strCurLineData;
    strCurLineData = szCurLineData;
    strCurLineData.MakeLower();
    if (pCookie!=NULL)
    if (strncmp("set-cookie: " , strCurLineData, strlen("set-cookie: ")) == 0)
    {
    char szCookie[128] = {0};
    memcpy(szCookie, szCurLineData+strlen("set-cookie: "), strstr(szCurLineData, ";")-szCurLineData-strlen("set-cookie: "));
    *pCookie = szCookie;
    } } //*/ // 求HTTP包内html数据开始位置
    pHtmlPack += strlen("\r\n");
    memcpy(szRecvBuf, pHtmlPack, (szRecvBuf+nRecvLen) - pHtmlPack);
    memset(szRecvBuf + ((szRecvBuf+nRecvLen) - pHtmlPack), 0, pHtmlPack-szRecvBuf);
    nRecvLen = (szRecvBuf+nRecvLen) - pHtmlPack;
    break;
    }
    } // HTTP包长总度
    int nHtmlPackLen = 0;
    // 当前包还需要多少数据
    int nHtmlPackNeedLen = 0;
    // 接收HTTP中的HTML包一直到最后一个长度为0的包
    do
    {
    // 当前HTTP包内的HTML数据位置
    char *pHtmlPack = szRecvBuf;
    // 处理一个段数据
    // 数据已Chunked编码所以需要还原
    // ,Chunked包结构类似[长度][数据......][长度][数据......][长度][数据......]
    do
    {
    if (nHtmlPackNeedLen < 1) // 说明是一个Chunked新包
    {
    pHtmlPack = strstr(szRecvBuf+strlen("\r\n"), "\r\n");
    if (pHtmlPack != NULL)
    {
    // 取得包长度 pHtmlPack += strlen("\r\n"); char szHtmlPackLen[32] = {0};
    memcpy(szHtmlPackLen, szRecvBuf, pHtmlPack - szRecvBuf);
    sscanf(szHtmlPackLen, "%x", &nHtmlPackLen); nHtmlPackNeedLen = nHtmlPackLen;
    }
    else
    {
    // 该段数据长度不够,无法取出长度,继续接收.
    break;
    }
    }
    else
    {
    // 将数据取出给返回数据的缓冲
    CString strHtmlPackBuf;
    if (nHtmlPackNeedLen < szRecvBuf+nRecvLen - pHtmlPack)   // 需要的数据小于现在包内的数据,说明该包数据都在当前数据段(nRecvBuf)内
    strHtmlPackBuf.GetBufferSetLength(nHtmlPackNeedLen);
    else // 现有数据不够需要数据,现有多少给多少
    strHtmlPackBuf.GetBufferSetLength(szRecvBuf+nRecvLen - pHtmlPack);
    memcpy(strHtmlPackBuf.GetBuffer(strHtmlPackBuf.GetLength()
    ), pHtmlPack, strHtmlPackBuf.GetLength());
    strncat(pHtmlBuf, strHtmlPackBuf.GetBuffer(0), nHtmlBufLen);
    // 将得到的数据从接收buf(szRecvBuf)中删除(提前)
    memcpy(szRecvBuf, pHtmlPack+strHtmlPackBuf.GetLength(), (szRecvBuf+nRecvLen)-(pHtmlPack+strHtmlPackBuf.GetLength()));
    nRecvLen = szRecvBuf+nRecvLen-(pHtmlPack+strHtmlPackBuf.GetLength());
    memset(szRecvBuf+nRecvLen, 0, sizeof(szRecvBuf)-nRecvLen);
    nHtmlPackNeedLen -= strHtmlPackBuf.GetLength();
    }
    }while(nRecvLen > 0 && nHtmlPackLen>0); // 当szRecvBuf有数据未处理时 int nTmpRecvLen = recv(Socket, szRecvBuf+nRecvLen, sizeof(szRecvBuf)-nRecvLen, 0);
    if (nTmpRecvLen > 0)
    nRecvLen += nTmpRecvLen;
    else
    break; }while(nHtmlPackLen > 0 || nRecvLen > 0);//*/
    pGetHtmlEvent->SetEvent(); return 0;
    }
      

  4.   

    赫赫,感谢2楼的提示,我找了找Chunked编码的资料自己搞定了。这100分给大家平分了吧以下是我的代码其中RecvBuffer是接收到的增个封包,String类型,最后处理过的RecvBuffer就是主体内容  else if Pos('transfer-encoding: chunked',LowerCase(RecvBuffer))>0 then begin
        //取得正文内容,包含Chunked部分
        ChunkStr:=Copy(RecvBuffer,Pos(#13#10#13#10,RecvBuffer)+4,Length(RecvBuffer));
        RecvBuffer:='';
        ChunkIndex:=1;
        While ChunkIndex<Length(ChunkStr) do begin
          //取得一个Chunk
          TempStr:=Copy(ChunkStr,ChunkIndex,Pos(#13#10,ChunkStr)-1);
          if TryStrToInt('$'+Trim(TempStr),Len) then begin  //使用Trim是因为有些时候TempStr后面有一个空格
            if Len=0 then Break;
            //计主体内容
            RecvBuffer:=RecvBuffer+Copy(ChunkStr,ChunkIndex+Length(TempStr)+2,Len);
          end;
          ChunkIndex:=ChunkIndex+Length(TempStr)+2+Len+2;
        end;如果代码有什么不足,或没有预料到的错误请指出 谢谢
      

  5.   

    其中RecvBuffer是接收到的整个封包