0

我正在尝试使用 CFHTTP 编写一个小型下载器。不幸的是,我不能使用非常简单的 NSURL。我基本上想要一种异步方式来下载数据并将其存储在文件中。我还没有找到如何执行异步方式,但我有一些使用同步方式的代码,但效果不佳。问题是下载器没有下载完整的字节。我看到一些数据丢失导致最终文件损坏。这是我到目前为止的代码。

#include <stdio.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CFNetwork/CFNetwork.h>
#include <CFNetwork/CFHTTPStream.h>

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

    // insert code here...
    const char *data;
    FILE *fp;
    CFShow(CFSTR("Hello, World!\n"));

    CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://the.earth.li/~sgtatham/putty/0.62/x86/putty.zip"), NULL);
    CFHTTPMessageRef cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), cfUrl, kCFHTTPVersion1_1);

    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, cfHttpReq);
    CFReadStreamOpen(readStream);

    CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
    CFIndex numBytesRead;

    do {
        const int nBuffSize = 1024;
        UInt8 buff[nBuffSize];
        numBytesRead = CFReadStreamRead(readStream, buff, nBuffSize);
        if( numBytesRead > 0 )
        {
            CFHTTPMessageAppendBytes(cfHttpResp, buff, numBytesRead);
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError error = CFReadStreamGetError(readStream);
            printf ("Error %d", error.error);
        }
    } while ( numBytesRead > 0 );
    CFStringRef myStatusLine = CFHTTPMessageCopyResponseStatusLine(cfHttpReq);
    CFReadStreamClose(readStream);
    CFDataRef cfResp = CFHTTPMessageCopyBody(cfHttpResp);
    CFIndex length = CFDataGetLength(cfResp);
    printf ("%lu\n", length);
    CFShow(myStatusLine);
    data = (const char*)CFDataGetBytePtr(cfResp);
    fp = fopen("/var/tmp/Update.zip", "w");
    if (fp == NULL) {
        printf("ACnnot be opened\n");
    } else {
        fwrite(data, length, 1, fp);
        fclose(fp);
    }
    printf ("Download done\n");
    CFRelease(cfUrl);
    CFRelease(cfHttpReq);
    CFRelease(readStream);
    CFRelease(cfHttpResp);
    CFRelease(cfResp);

    return 0;
}

我得到的长度小于我实际下载的文件。我不明白这段代码有什么问题。有人可以帮我吗?

4

2 回答 2

1

我仍然不知道这段代码出了什么问题。但我通过更换解决了我的问题

//CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE); CFMutableDataRef cfResp = CFDataCreateMutable(kCFAllocatorDefault, 0); 我现在使用 MutableDataRef 而不是 CFHTTPMessageRef。我将在这里更新新代码。

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

    // insert code here...
    const char *data;
    FILE *fp;
    CFShow(CFSTR("Hello, World!\n"));

    CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, CFSTR("http://the.earth.li/~sgtatham/putty/0.62/x86/putty.zip"), NULL);
    CFHTTPMessageRef cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), cfUrl, kCFHTTPVersion1_1);

    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, cfHttpReq);
    CFReadStreamOpen(readStream);

    //CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);
    CFMutableDataRef cfResp = CFDataCreateMutable(kCFAllocatorDefault, 0);
    CFIndex numBytesRead;

    do {
        const int nBuffSize = 1024;
        UInt8 buff[nBuffSize];
        numBytesRead = CFReadStreamRead(readStream, buff, nBuffSize);
        if( numBytesRead > 0 )
        {
            CFDataAppendBytes(cfResp, buff, numBytesRead);
            //CFHTTPMessageAppendBytes(cfHttpResp, buff, numBytesRead);
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError error = CFReadStreamGetError(readStream);
            printf ("Error %d", error.error);
        }
    } while ( numBytesRead > 0 );

    CFReadStreamClose(readStream);
    //CFDataRef cfResp = CFHTTPMessageCopyBody(cfHttpResp);
    CFIndex length = CFDataGetLength(cfResp);
    printf ("%lu\n", length);

    data = (const char*)CFDataGetBytePtr(cfResp);
    fp = fopen("/var/tmp/Update.zip", "w");
    if (fp == NULL) {
        printf("ACnnot be opened\n");
    } else {
        fwrite(data, length, 1, fp);
        fclose(fp);
    }
    printf ("Download done\n");
    CFRelease(cfUrl);
    CFRelease(cfHttpReq);
    CFRelease(readStream);
    CFRelease(cfResp);

    return 0;
}

希望这可以帮助。如果有人可以指出原始代码出了什么问题,它仍然很有用。

于 2013-04-15T23:02:40.307 回答
0

我知道这很晚,但是您的代码确实帮助了我(很难找到直接、完整的使用 CFNetworking API 获取响应正文字节的示例)。

无论如何,我认为错误是最后一个参数应该是 FALSE(响应消息),而不是 CFHTTPMessageCreateEmpty 行中的 TRUE(请求消息)。

CFHTTPMessageRef cfHttpResp = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, FALSE);
于 2014-01-17T01:17:24.557 回答