Многопоточный http-сервер libevent: не удается успешно ответить на evhttp_request в подпотоках

Проблема в том, что клиент не может получить HTTP-ответ с ответом «evhttp_send_reply» в подпотоке на стороне сервера.

Я попробовал модель для настройки многопоточного http-сервера с libevent evhttp, ниже коды, работающие в основном потоке:

    struct event_base *mpEventBase = event_base_new();
    struct evhttp *pHttp = evhttp_new(mpEventBase);
    evhttp_bind_socket(pHttp, "0.0.0.0", port);
    evhttp_set_gencb(pHttp, HttpGenericCallback, (void *)this);
    event_base_dispatch(mpEventBase);

затем настроен http-сервер и начинает принимать соединения от клиента. Но для общей ситуации с обработкой длительного кода я перенаправляю весь http-запрос в подпоток и также отправляю http-ответ в подпоток.

    void HttpGenericCallback(struct evhttp_request *pRequest, void* arg) {
        Class *thiz = (Class *)arg;
        // run in sub thread in thread pool
        thiz->mpThreadPool->Run([thiz](struct evhttp_request *pReq){
            struct evbuffer* pEvbuf = evbuffer_new();
            if (!pEvbuf) {
                std::cout << "create evbuffer failed!\n";
                return ;
            }

            const char *pUrl = evhttp_request_get_uri(pRequest);
            evbuffer_add_printf(pEvbuf, "Server response. Your request url is %s", pUrl);
            evhttp_send_reply(pRequest, HTTP_OK, "OK", pEvbuf);
            evbuffer_free(pEvbuf);
        }, pRequest);
    }

НО я обнаружил, что после "evhttp_send_reply" клиент НЕ получил никакого ответа. Я не уверен, какой шаг неправильный? Кроме того, если я перенесу код, работающий в подпотоке, в HttpGenericCallback, он будет работать!

Любые советы высоко ценится!


person Ring.Yee    schedule 11.09.2018    source источник


Ответы (1)


Ваш HttpGenericCallback вызывается, и вы передаете struct evhttp_request* своему потоку. HttpGenericCallback завершается и, вероятно, уничтожает ваш struct evhttp_request*, в то время как ваш поток продолжает работать с уже недопустимым указателем.

РЕДАКТИРОВАТЬ: я узнал, что evhttp_request не удаляется до тех пор, пока не будет выполнен evhttp_send_reply. Тем не менее, я хотел бы упомянуть, что поток использует pRequest, но должен использовать pReq, объект, который был передан функции.

person Alex    schedule 18.10.2018