C libevent在发布多部分文件上载时阻止

C libevent在发布多部分文件上载时阻止,c,libevent,C,Libevent,我正在使用linux内核4.14开发C语言的嵌入式arm板。 我使用的是libevent版本2,并为两个URL创建了处理程序。 一个用于发布文件,另一个用于获取上载状态。 用户将通过浏览器连接并通过多部分表单POST上传文件,并使用get请求获取上传状态 下面是一些伪代码,您可以了解这个过程 void upload_cb(struct evhttp_request *req, void *arg){ struct bufferevent *bev = evhttp_connection_

我正在使用linux内核4.14开发C语言的嵌入式arm板。 我使用的是libevent版本2,并为两个URL创建了处理程序。 一个用于发布文件,另一个用于获取上载状态。 用户将通过浏览器连接并通过多部分表单POST上传文件,并使用get请求获取上传状态

下面是一些伪代码,您可以了解这个过程

void upload_cb(struct evhttp_request *req, void *arg){
    struct bufferevent *bev = evhttp_connection_get_bufferevent(req->evcon);
    if (bev) //Prio is initialized with 10 states in main
        bufferevent_priority_set(bev, 9); // set to low priority
    struct evbuffer* post_buffer = evhttp_request_get_input_buffer(req);
    size_t body_size = evbuffer_get_length(post_buffer);
    // a multipart parser takes care of writing the 
    // post_buffer content to a file
    // this takes a few seconds and after completing this 
    // the status_cb is accessible again
}

void status_cb(struct evhttp_request *req, void *arg){
    // send some json
}

evhttp_set_cb(_http, "/upload", upload_cb, NULL);
evhttp_set_cb(_http, "/status", status_cb, NULL);
当我上传一个大约10 Mb的文件,同时每1秒轮询一次状态URL时,状态URL在大约12秒钟内不会响应,直到文件得到正确处理并返回函数

上载\u cb需要一段时间来处理数据,因此会阻止状态\u cb的执行。 这是不可取的,因为此时应用程序没有响应

我试图不断地从应用程序获取状态,并使UI保持最新状态。 据我所知,一旦所有数据都被缓冲并准备好让回调处理它,就会调用upload_cb回调。这意味着它将在内存中缓冲整个10MB

我曾试图降低缓冲区的优先级,希望事件调度器会中断并给其他事件一些时间,但我对libevent如何工作的想法似乎不正确

我正在寻找其他解决方案,我觉得我可以创建一个单独的线程,在其中我可以处理上传+保存到文件,然后将控制权交回主线程。 但我更愿意在这里问一下,是否有一个更优雅的解决方案,包括完全使用libevent

我可以让libevent中断处理上传并回复状态请求吗? 我是否可以强制libevent以块的形式接收数据,以便它可以处理其他回调


更新1:根据需要,我必须使用非阻塞api调用。虽然写入文件是非阻塞的,但内核写入缓冲区似乎已被填满,因为我将10+Mb写入一个文件。 我已经将解析和写入移动到一个新线程,该线程允许libevent从函数返回,现在正在研究如何处理post_缓冲区(多线程访问、使用后释放等)

更新2:将解析移动到新线程不起作用,因为回调
上载\u cb
返回,并且
evhttp\u请求及其缓冲区在线程仍要解析时被清除。

我倾向于创建一个额外的event_base实例来处理无缝上传,如链接中所述。我一直在线阅读,并找到了一个适合我的解决方案,主要受以下代码的启发:


然后可能会清理你的线程后

我还添加了libevhtp库,它允许注册上传块的回调。这样我就不必在内存中缓冲整个文件,可以在上传文件时将内容直接写入文件。
struct eventbase *eventbase2;

void threadfunction(){
    eventbase2 = event_base_new();
    struct evhttp* http2 = evhttp_new(event_base2);
    evhttp_set_cb(http2, "/upload", upload_cb, NULL);
    struct evhttp_bound_socket* handle = 
        evhttp_bind_socket_with_handle(http2, "0.0.0.0", 8080);
    event_base_dispatch(event_base2);  // <-------- it will wait here
    evhttp_del_accept_socket(http2, handle);
    evhttp_free(http2);
    event_base_free(event_base2);
}

// initialize a thread with the threadfunction
event_base_loopbreak(event_base2);