【问题标题】:C++ – cURL cmd, stderr piped to program, very slowC++ – cURL 命令,stderr 管道到程序,非常慢
【发布时间】:2015-12-18 22:00:49
【问题描述】:

注意:我使用的是openFrameworks,但我认为这不是理解我的问题所必需的知识。

概述

OSX 10.8.5

XCode 5.1.1

我有一个程序fork()s,子进程运行这个cURL cmd:

curl -c cookies.txt -b cookies.txt -k https://www.space-track.org/ajaxauth/login -d 'identity=email@example.com&password=p4$$w0rd&query=https://www.space-track.org/basicspacedata/query/class/tle_latest/ORDINAL/1/EPOCH/%3Enow-30/orderby/OBJECT_ID/format/json' > ~/../myApp/bin/data/myData.json -#

这个:

  • 管理Space Track API 的 cookie 文件
  • 使用我的 Space Track 帐户登录
  • 将数据集(约 15,000 个 json 对象)下载到“myData.json”
  • 显示进度条######################################################################## 100.0%

子进程将进度条传递给父进程,一次 1 个字符。父级同时将进度条打印到控制台。以下是我的代码的整个fork() 部分:

.h(相关的全局变量)

{
    bool forkOnce, isBufferFull;
    int childToParentPipe[2]; // Child to parent pipe. [0] = read (output), [1] = write (input)
    char ch;
    int pid, outCount;
    string buffer; 
}

.cpp

if(!forkOnce){ //we're in an ∞ loop, so we need to control the flow

    //make pipe
    if( pipe(childToParentPipe) < 0){
        perror("Can't make pipe");
        _exit(1);
    }

    //vars for dealing w piped chars
    buffer = ""; // string that holds 1 line of progress meter
    isBufferFull = false; // is ^ buffer string full?
    outCount = 0; //counts chars coming from pipe (for carriage returns)

    cout << "Forking..." << endl;
    pid = fork();
}
switch(pid){
    case -1:{
        perror("Can't fork");
        _exit(EXIT_FAILURE);
        break;
    }
    case 0:{ // child

        if(!forkOnce){ // do child stuff once

            close(2); // Close current stderr
            dup( childToParentPipe[1]); //Make stderr go to write end of pipe
            close( childToParentPipe[0]); //Close read end of pipe because it's not needed in child process

            //make output file for stdout
            int out = creat("/.../myApp/bin/data/myData.json", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

            if (out == -1){
                perror("Can't make file");
                _exit(EXIT_FAILURE);
            } else { //if file successfully created
                dup2(out,STDOUT_FILENO);// redirect stdout to the file                
                execlp( [the curl command goes here] , NULL); // exec the command
                close(out); // close file
                _exit(0);

            }
        }
        break;
    }
    default:{ // parent

        close(childToParentPipe[1]);

        //while num bytes piped out is 1 (meaning we haven't reached EOF yet)
        if( read(childToParentPipe[0], &ch, 1) == 1) {

            if(outCount == 80){
                isBufferFull = true;
                outCount = 0;
            }

            if(!isBufferFull){
                buffer += ch;
            } else {
                char* bufferChars = strdup(buffer.c_str());
                bufferChars[outCount] = ch;
                buffer = bufferChars;
            }

            cout << buffer << endl;

            outCount++;
        }

        // wait for child process
        int status = 0;
        waitpid(-1, &status, WNOHANG);
        //printf("child status:%d\n",status); // "0"

        signal(SIGCHLD,signalHandler); //signalHandler = func that finalizes this process

        break;
    }
}

forkOnce = true;

问题

与在终端中运行相比,我的应用程序的 cURL 下载速度非常慢:

...有时,在我的应用程序中,此错误会在下载过程中多次打印到控制台:

2015-12-18 15:44:16.595 forkTest2Debug[22858:5f1f] -[NSPersistentUIManager writeWindowSnapshot:length:width:height:bytesPerRow:toFile:inDirectory:encryptingWithKey:uuid:checksum:isUserWaitingImpatientlyForThisThingToFinish:]: 0 == ftruncate(fd, finalFileSize) failed on line 2770: Bad file descriptor

无法弄清楚为什么我会收到 Bad file descriptor 错误。在这种情况下,我似乎找不到任何关于 isUserWaitingImpatientlyForThisThingToFinish 或 ftruncate 的官方文档。

我的应用程序以 60fps 的速度运行,因此管道的输出以该速率泵出字符。这可能会填满我的管道,因为输入字符的速度比输入的速度快吗?

是什么导致了这种缓慢,我该如何解决?

【问题讨论】:

  • 你为什么不使用 libcurl 而不是从命令行分叉和调用curl?另外,这是c++ 而不是c
  • 我尝试使用 libcurl,但这似乎是更简单的路径。既然我已经走了这么远,我宁愿以这种方式完成它。
  • 1. libcurl 一点也不难(除非你使用 mutli 接口)。 2. 你为什么不用popen()?
  • 我不是一个经验丰富的程序员,这花了我整整一个月的时间来整理,哈哈。老实说,我什至不知道从哪里开始使用 libcurl(我已经多次阅读所有文档)。拜托,我想这样结束。
  • 然后使用popen()。请问你为什么在c这样做。

标签: c++ unix curl pipe openframeworks


【解决方案1】:

这是popen() 的简单示例,这可能会帮助您按照自己的方式进行操作

#include <stdio.h>

int main(int argc, char *argv[])
{
    char output[100];
    char command[100];
    ssize_t length;
    FILE *pipe;
    if (argc < 2)
        return -1; // Missing command line parameters
    if (snprintf(command, sizeof(command), "curl %s", argv[1]) >= sizeof(command))
        return -1; // URL too long
    pipe = popen(command, "r");
    if (pipe == NULL)
        return -1; // Execution failure
    while ((length = fread(output, 1, sizeof(output), pipe)) > 0)
        fwrite(output, 1, length, stdout);
    pclose(pipe);
    return 0;
}

像这样编译和测试

$ gcc -Wall -Werror -g3 -O0 SOURCE.c -o _curl_test
$ ./_curl_test http://stackoverflow.com

【讨论】:

  • 好的。我会试试这个。谢谢。由于我知道这需要很长时间才能弄清楚这里发生了什么以及如何将其合并到我的代码中,与此同时,您是否碰巧知道是什么导致了我已经完成的工作缓慢,按照我原来的问题?
  • ...你能解释一下如何使用popen() 来解决这个问题吗?再次感谢。
猜你喜欢
  • 2012-03-19
  • 2023-03-31
  • 1970-01-01
  • 2017-08-19
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多