2016-08-04 40 views
0

所以我有一个运行libev I/O循环和计时器循环的程序。当char数组遇到7000个字符或者定时器循环命中10秒时,它会转到JSON POST一个在localhost上运行的服务。 I/O循环导致程序在空闲时使用差不多100%的CPU。libev循环在空闲时使用99%的CPU

此程序需要的任一1的argv的或0:

  • A 1使得程序仅处理一条线并退出。
  • 0使其等待输入。

错误只发生在我们将它传递给0并让它等待输入时。

#include <stdio.h> 
#include <ev.h> 
#include <curl/curl.h> 
#include <json-c/json.h> 
#include <unistd.h> 

void curlPage(char url[], char message[]); 
void io_callback(EV_P_ ev_io *w_, int rev); 
void time_callback(EV_P_ ev_timer *w_, int rev); 

struct watcher 
{ 
    ev_io stdin_watcher; 
    ev_timer time_watcher; 
}; 

char lines[BUFSIZ]; 
char *argv1; 
char url[1024] = "http://127.0.0.1:"; 
char *end; 


int main(int argc, char *argv[]) { 
    struct ev_loop *loop; 
    struct watcher w; 

    if (!argv[1]) { 
     printf("YOU NEED A 1 OR 0 PARAMATER FOR THIS TO WORK!\n"); 
     exit(0); 
    } 
    else { 
     end = argv[1]; 
    } 
    argv1 = argv[2]; 

    if (argv[3]) { 
     strcat(url, argv[3]); 
    } 
    else { 
     strcat(url, "8888"); 
    } 

    loop = ev_default_loop(0); 

    ev_io_init(&w.stdin_watcher, io_callback, STDIN_FILENO, EV_READ); 
    ev_timer_init(&w.time_watcher, time_callback, 10, 0); 
    w.time_watcher.repeat=10; 
    ev_io_set(&w.stdin_watcher, STDIN_FILENO, EV_READ); 
    ev_io_start(loop, &w.stdin_watcher); 
    ev_timer_start(loop, &w.time_watcher); 

    ev_run(loop, 0); 

    return 0; 
} 

void time_callback(EV_P_ ev_timer *w_, int rev) { 
    if (strlen(lines)) { 
     curlPage(url, lines); 
     lines[0] = '\0'; 
    } 
    return; 
} 

void io_callback(EV_P_ ev_io *w_, int rev) { 
    struct watcher *w = (struct watcher *)w_; 

    char buf[BUFSIZ]; 
    char * resp; 

    resp = fgets(buf, sizeof buf, stdin); 
    if (resp != NULL) { 
     sprintf(lines, "%s %s", lines, buf); 
    } 


    if (strlen(lines) > 7000) { 
     curlPage(url, lines); 
     lines[0] = '\0'; 
    } 
    if (strcmp(end, "1") == 0) { 
     ev_io_stop(loop, w_); 
    } 
    return; 
} 

void curlPage(char url[], char message[]) { 
    CURL *curl; 
    CURLcode res; 
    json_object * jsonObj = json_object_new_object(); 
    char hostname[1024]; 

    gethostname(hostname, 1024); 
    struct curl_slist * headers=NULL; 
    headers = curl_slist_append(headers, "Accept: application/json"); 
    headers = curl_slist_append(headers, "Content-Type: application/json"); 
    headers = curl_slist_append(headers, "charsets: utf-8"); 

    curl = curl_easy_init(); 

    if(curl) { 

     if (hostname) { 
      json_object *jstring2 = json_object_new_string(hostname); 
      json_object_object_add(jsonObj, "hostname", jstring2); 
     } 
     if (argv1) { 
      json_object *jstring3 = json_object_new_string(argv1); 
      json_object_object_add(jsonObj, "tag", jstring3); 
     } 

     json_object *jstring = json_object_new_string(message); 
     json_object_object_add(jsonObj, "message", jstring); 

     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); 
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
     curl_easy_setopt(curl, CURLOPT_URL, url); 
     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_get_string(jsonObj)); 

     res = curl_easy_perform(curl); 

     if(res != CURLE_OK) { 
      fprintf(stderr, "curl_easy_preform() failed: %s\n", curl_easy_strerror(res)); 
     } 
     curl_easy_cleanup(curl); 
    } 
    curl_global_cleanup(); 
    json_object_put(jsonObj); 

    // run only once. 
    if (strcmp(end, "1") == 0) { 
     exit(0); 
    } 
    return; 
} 

这里是线程回溯和堆栈打印出来:

bt and stack print out

所以它看起来像I/O观察者的第一个事件后得到连续的I/O事件。它正确地等待第一个事件,但之后消耗大部分CPU。我使用它是这样的:

cat test.txt | logpush 0 & 

也许管道是造成这种情况?

所以我写了一个测试程序,它只是一个简单的libev I/O守望者:

#include <stdio.h> 
#include <ev.h> 
#include <unistd.h> 

void io_callback(EV_P_ ev_io *w_, int rev); 
void time_callback(EV_P_ ev_timer *w_, int rev); 

char lines[BUFSIZ]; 

int main(int argc, char *argv[]) { 
    struct ev_loop *loop; 
    struct ev_io stdin_watcher; 

    loop = ev_default_loop(0); 

    ev_io_init(&stdin_watcher, io_callback, STDIN_FILENO, EV_READ); 
    ev_io_set(&stdin_watcher, STDIN_FILENO, EV_READ); 
    ev_io_start(loop, &stdin_watcher); 

    ev_run(loop, 0); 

    return 0; 
} 

void io_callback(EV_P_ ev_io *w_, int rev) { 
    printf("callback hit\n"); 
    return; 
} 

的I/O回调被撞了数百次第二,即使没有输入,如果调用一个管,像这样:

cat test.txt | ./test & 

也会发生这种情况时,一个进程我的程序中我管标准输出。

这是我的问题的根本原因。

+0

如果(argv [2])== NULL,则if(argv [3])是UB。建议检查预期范围内的“argc”。 – chux

+0

'BUFSIZ'的价值是什么? – chux

+0

'BUFSIZ是8192' –

回答

0

第二个片段的修改对管道起作用(至少:cat event.c | ./a.out)。这个问题似乎是没有检测到EOF,并继续锤打文件描述符

#include <stdio.h> 
#include <ev.h> 
#include <unistd.h> 

void io_callback(EV_P_ ev_io *w_, int rev); 
void time_callback(EV_P_ ev_timer *w_, int rev); 


struct ev_loop *loop; /* made this global, because needed by the callback at closing time */ 

int main(int argc, char *argv[]) { 
    struct ev_io stdin_watcher; 

    loop = ev_default_loop(0); 

    ev_io_init(&stdin_watcher, io_callback, STDIN_FILENO, EV_READ); 
    ev_io_set(&stdin_watcher, STDIN_FILENO, EV_READ); 
    ev_io_start(loop, &stdin_watcher); 

    // ev_run(loop, 0); 
    ev_loop(loop, 0); 

    return 0; 
} 

void io_callback(EV_P_ ev_io *w_, int rev) { 
    int rc; 
    char ch; 

     /* replaced fgets() by read() */ 
    rc = read(STDIN_FILENO, &ch, 1); 

     /* diagnostic output should go to stderr */ 
    fprintf(stderr, "Callback hit, rc=%d, ch = %02x\n" 
     , rc, ch & 0xff 
     ); 
    if (rc == 0) ev_io_stop(loop, w_); 
    return; 
} 

- 和测试你可以使用下面的程序和管道输出通过二进制,如:sh loop.sh | ./a.out

#!/bin/sh 
while true; do 
     date 
     sleep 5 
done 
+0

被读取比fgets更有效率? –

+0

这不关乎效率。我想摆脱缓冲(至少不会被它弄糊涂)在内部,当它认为需要一个充满数据的缓冲区时,fgets()当然会调用read()。你当然应该用更大的缓冲区和第三个参数来调用read()。 – joop

+0

'谢谢你的帮助 –

0

sprintf(lines, "%s %s", lines, buf);是未定义的行为。

int sprintf(char * restrict s, const char * restrict format, ...); 

restrict意味着sprintf()并不希望数据s点由别的功能访问进行访问。由于代码通过liness和一个参数,代码破坏了合同和未定义的行为结果。可能的lines是简单的增长和增长和增长。

相反

// sprintf(lines, "%s %s", lines, buf); 
strcat(lines, " "); 
strcat(lines, buf); 
// Other more time efficient code is possible 

像往常一样,看出来了缓冲区溢出是一个问题。

代码也可能有其他问题。

+0

取得许可证*联系* - > *合同*':)' –

+0

'将sprintf更改为strcat,就像您建议的那样不能解决问题。 ' –

+0

'即使我注释掉了整个回调块,并且只有返回它仍然使用90%的cpu。 ' –

相关问题