【问题标题】:libcurl FTP-Download incomplete in the Unreal Enginelibcurl FTP-在虚幻引擎中下载不完整
【发布时间】:2021-04-22 09:44:43
【问题描述】:

我目前正在尝试在我的 Unreal C++ 项目中使用 curl 从公共 git-Repository 下载文件。这是我尝试执行的代码,我从FTP-Example 派生:

// This is in the .h file
struct FFtpFile {
    FILE* File;
    const char* Filename;
};

void FtpFetch(const std::string URL, const char* Filename) {
    CURL* Curl = curl_easy_init();

    const FFtpFile FtpFile {
        nullptr,
        Filename
    };
    
    if (!Curl) {
        UE_LOG(LogTemp, Warning, TEXT("Error Initiating cURL"));
        return;
    }

    curl_easy_setopt(Curl, CURLOPT_URL, URL.c_str());
    curl_easy_setopt(Curl, CURLOPT_VERBOSE, 1);
    curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(Curl, CURLOPT_SSL_VERIFYPEER, false);
    
    // Data Callback
    const auto WriteCallback = +[](void* Contents, const size_t Size, const size_t NumMem, FFtpFile* FileStruct) -> size_t {
        if (!FileStruct->File) {
            fopen_s(&FileStruct->File, FileStruct->Filename, "wb");
            if (!FileStruct->File) {
                return CURLE_WRITE_ERROR;
            }
        }
        return fwrite(Contents, Size, NumMem, FileStruct->File);
    };
    curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, DownloadCallback);
    curl_easy_setopt(Curl, CURLOPT_WRITEDATA, FtpFile);

    
    const CURLcode Result = curl_easy_perform(Curl);
    if (Result != CURLE_OK) {
        const FString Message(curl_easy_strerror(Result));
        UE_LOG(LogTemp, Warning, TEXT("Error Getting Content of the Model File: %s"), *Message);
        return;
    }
    curl_easy_cleanup(Curl);

    // Close the Stream after Cleanup
    UE_LOG(LogTemp, Log, TEXT("Successfully Fetched FTP-File. Closing Write Stream"))
    if (FtpFile.File) {
        fclose(FtpFile.File);
    }
}

请注意,这是使用 Unreal Async 函数在单独的线程上执行的:

void AsyncFetchModelFile(const std::string URL) {
    std::string Path = ...
    
    TFunction<void()> Task = [Path, URL]() {
        FtpFetch(URL, Path.c_str());
    };

    UE_LOG(LogTemp, Log, TEXT("Fetching FTP on Background Thread"))
    Async(EAsyncExecution::Thread, Task, [](){UE_LOG(LogTemp, Warning, TEXT("Finishied FTP on Background Thread!"))});
}

我已经删除了 curl_global 调用,因为文档指出这些调用不是线程安全的。我也尝试在主线程上运行代码,但是那里也发生了同样的错误。

对于错误本身:下载运行几乎完美无缺,但下载的文件(在本例中为 .fbx 文件)总是错过最后约 800 字节,因此不完整。此外,该文件在 Unreal 中一直处于打开状态,因此除非我关闭编辑器,否则我无法删除/移动该文件。

在编写此 Unreal 代码之前,我尝试在纯 C++ 设置中运行相同的代码,并且它完美地运行。但由于某种原因,在 Unreal 中做同样的事情是行不通的。

我也尝试使用私有方法而不是 lambda-Function,但这没有任何区别。

任何帮助将不胜感激 ~冈花

【问题讨论】:

  • 听起来好像缓冲区中可能有最后约 800 个字节。为什么是FtpFile const?请也显示DownloadCallback函数。
  • 顺便说一句,你是在程序开始时调用curl_global_init,在程序结束时调用curl_global_cleanup吗?
  • @TedLyngmo curl_global_init documentation 声明:This function is not thread-safe. You must not call it when any other thread in the program is running 所以我从代码中删除了它,因为这段代码在不同的线程上运行。但是放入并不能解决问题。 FtpFile 是 const 因为 Rider 建议我这样做。但这似乎也没有什么不同。我同意这感觉就像最后一批数据没有正确写入文件,但问题是:为什么会这样?
  • curl_easy_init 文档还声明“如果您还没有调用curl_global_initcurl_easy_init 会自动调用。这在多线程情况下可能是致命的,因为curl_global_init不是线程安全的,因为没有相应的清理,可能会导致资源问题。” - 所以,我建议你在程序启动时调用once(然后调用@ 987654337@ 程序退出时一次)。
  • (除非您将其放入 DLL - 不要将其放入 DllMain 或在这种情况下的静态初始化程序中)

标签: c++ curl libcurl unreal-engine4


【解决方案1】:

我最终没有设法让它工作(我怀疑这是一个与虚幻相关的错误),但我找到了另一种使用包含的虚幻 HTTP 模块的方法:

FString Path = ...

// Create the Callback when the HTTP-Request has finished
auto OnRequestComplete = [Path](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) {
    if (bWasSuccessful) {
        FFileHelper::SaveArrayToFile(Response->GetContent(), *Path);
        UE_LOG(LogTemp, Log, TEXT("Successfully downloaded the file to '%s'"), *Path)
    } else {
        UE_LOG(LogTemp, Warning, TEXT("Error downloading the file (See EHttpResponseCodes): %s"), Response->GetResponseCode())
    }
};


// Create a HTTP-Request and Fetch the file
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
Request->SetVerb("GET");
Request->SetURL(URL);
Request->OnProcessRequestComplete().BindLambda(OnRequestComplete);

Request->ProcessRequest();

【讨论】:

    猜你喜欢
    • 2020-03-26
    • 2016-11-24
    • 2018-09-01
    • 1970-01-01
    • 2022-06-28
    • 2022-12-17
    • 1970-01-01
    • 2015-01-13
    • 2020-07-24
    相关资源
    最近更新 更多