13

2つのHTTP応答を比較するためにどういうわけか必要な宿題があります。私はそれをCで書いています、そして私は物事を簡単にするためにlibcurlを使います。libcurlを使用してHTTP要求と別の関数からの応答を行う関数を呼び出していますが、HTTP応答をとして返したいと思いますchar *。これまでの私のコードは次のとおりです(クラッシュします):

#include <stdio.h>
#include <curl/curl.h>
#include <string.h>

size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) {
    size_t written;
    written = fwrite(ptr, size, nmemb, stream);
    return written;
}

char *handle_url(void) {
    CURL *curl;
    char *fp;
    CURLcode res;
    char *url = "http://www.yahoo.com";
    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        if(res != CURLE_OK)
                fprintf(stderr, "curl_easy_perform() failed: %s\n",   curl_easy_strerror(res));

        curl_easy_cleanup(curl);

        //printf("\n%s", fp);
    }
    return fp;
}

このソリューションClibcurlget output into a stringは機能しますが、私の場合は、文字列を呼び出し元の関数に返したいだけなので、機能しません。

何か案は?

4

1 に答える 1

22

あなたのためにそれを修正しました。write_data()関数が複数回呼び出されるケースを処理し、適切な種類のパラメーターを渡す必要があります。また、十分なメモリを割り当てることができるように、取得した構造体の大きさを追跡する必要があります。

関数がどのように機能するかを理解できるようにprintf、関数のデバッグを残しました。write_data

#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>

struct url_data {
    size_t size;
    char* data;
};

size_t write_data(void *ptr, size_t size, size_t nmemb, struct url_data *data) {
    size_t index = data->size;
    size_t n = (size * nmemb);
    char* tmp;

    data->size += (size * nmemb);

#ifdef DEBUG
    fprintf(stderr, "data at %p size=%ld nmemb=%ld\n", ptr, size, nmemb);
#endif
    tmp = realloc(data->data, data->size + 1); /* +1 for '\0' */

    if(tmp) {
        data->data = tmp;
    } else {
        if(data->data) {
            free(data->data);
        }
        fprintf(stderr, "Failed to allocate memory.\n");
        return 0;
    }

    memcpy((data->data + index), ptr, n);
    data->data[data->size] = '\0';

    return size * nmemb;
}

char *handle_url(char* url) {
    CURL *curl;

    struct url_data data;
    data.size = 0;
    data.data = malloc(4096); /* reasonable size initial buffer */
    if(NULL == data.data) {
        fprintf(stderr, "Failed to allocate memory.\n");
        return NULL;
    }

    data.data[0] = '\0';

    CURLcode res;

    curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
        res = curl_easy_perform(curl);
        if(res != CURLE_OK) {
                fprintf(stderr, "curl_easy_perform() failed: %s\n",  
                        curl_easy_strerror(res));
        }

        curl_easy_cleanup(curl);

    }
    return data.data;
}

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

    if(argc < 2) {
        fprintf(stderr, "Must provide URL to fetch.\n");
        return 1;
    }
    data = handle_url(argv[1]);

    if(data) {
        printf("%s\n", data);
        free(data);
    }

    return 0;
}

注: でコンパイルしgcc -o test test.c -lcurlます (に貼り付けたと仮定しますtest.c)。gcc -o test test.c -lcurl -DDEBUGテストprintf()コールを表示するために使用します。

免責事項: これは醜く、手早く汚いコードです。バグがあるかもしれません。より堅牢で、より適切にコメントされた例をこちらでご覧ください。

于 2012-12-16T22:17:30.620 に答える