[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [Libevent-users] Help with Libevent multi-threaded HTTP server
Hi Azat,
See below, this is the program, see the comments in main() for an explanation of the problem. This needs to be a c++ compile as I am using an STL <vector>. I have made it work by freeing the event_base object by calling free_event_base() but that feels like the wrong thing to do.
Thanks for the response, I appreciate itâany help would be much appreciated
Gerry
----------------------------------
#include <sys/types.h>
#include <sys/time.h>
#include <sys/queue.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <event.h>
#include <evhttp.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <vector>
void httpserver_ProcessRequest(struct evhttp_request *req) {
struct evbuffer *buf = evbuffer_new();
if (buf == NULL)
return;
evbuffer_add_printf(buf, "Requested: %s", evhttp_request_uri(req));
evhttp_send_reply(req, HTTP_OK, "OK", buf);
evbuffer_free(buf);
}
void* httpserver_Dispatch(void *arg) {
event_base_dispatch((struct event_base*)arg);
std::cout << "Event dispatch thread ended..." << std::endl;
return 0;
}
int httpserver_bindsocket(int port, int backlog)
{
int r;
int nfd;
nfd = socket(AF_INET, SOCK_STREAM, 0);
if (nfd < 0) return -1;
int one = 1;
r = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
r = bind(nfd, (struct sockaddr*)&addr, sizeof(addr));
if (r < 0) return -1;
r = listen(nfd, backlog);
if (r < 0) return -1;
int flags;
if ((flags = fcntl(nfd, F_GETFL, 0)) < 0
|| fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
return -1;
return nfd;
}
int httpserver_start(int port, int nthreads, int backlog)
{
int r, i;
int nfd = httpserver_bindsocket(port, backlog);
if (nfd < 0)
return -1;
struct workder_t
{
struct event_base* base;
struct evhttp* httpd;
struct evhttp_bound_socket* soc;
pthread_t thr;
};
std::vector<workder_t> _workers;
for (i = 0; i < nthreads; i++)
{
workder_t worker;
worker.base = event_base_new();
if (worker.base == NULL)
return -1;
worker.httpd = evhttp_new(worker.base);
if (worker.httpd == NULL)
return -1;
worker.soc = evhttp_accept_socket_with_handle(worker.httpd, nfd);
evhttp_set_gencb(worker.httpd, httpserver_GenericHandler, NULL);
r = pthread_create(&worker.thr, NULL, httpserver_Dispatch, worker.base);
if (r != 0)
return -1;
_workers.push_back(worker);
}
std::cout << "Running - press return to stop..." << std::endl;
getchar();
std::cout << "Stopping..." << std::endl;
close(nfd);
std::cout << "Closed listening socket..." << std::endl;
for(auto worker = _workers.begin(); worker != _workers.end(); ++worker)
{
// I would expect that this would cause the thread blocked in event_base_dispatch() function called in httpserver_Dispatch function to end
event_base_loopbreak(worker->base);
// seems like I should do this, but not sureâworks either way
evhttp_free(worker->httpd);
// If I do this the the event_base_dispatch() does return so I get the expected result, but this feels wrong to
// destroy the base before the thread ends
// comment the next line to see the problem
event_base_free(worker->base);
// We are in the main thread so we join with each worker thread here
pthread_join(worker->thr, NULL);
}
std::cout << âClosed..." << std::endl;
return 0;
}
int main(int argc, char* argv[])
{
httpserver_start(8080, NUM_THREADS, 100);
}
Gerry Sweeney
http://gerrysweeney.com/
> On 28 Dec 2014, at 18:13, Azat Khuzhin <a3at.mail@xxxxxxxxx> wrote:
>
> On Sun, Dec 28, 2014 at 01:30:36PM +0000, Gerry Sweeney wrote:
>> Hi,
>>
>> I am new to lib event so please forgive me if this is a noob question. I ran into a problem usinglib event and wonder if anyone can help
>>
>> My question I hope is very simple: -
>>
>> I am trying to create a simple multi-threaded HTTP server.
>>
>> I create and bind a non-blocking listening socket on port 8080, then for each thread I want to create to process HTTP requests I call the following
>>
>> event_base_new()
>> evhttp_new()
>> evhttp_accept_socket_with_handle()
>> evhttp_set_gencb()
>> pthread_create(my_http_worker_thread_fn, base);
>>
>> Then in the thread function for each worker thread I call event_base_dispatch((struct event_base*)arg);
>>
>> Everything works as expected and I can process HTTP requests. The problem I am having is shutting down cleanly.
>>
>> After my main thread creates the worker threads I wait for a return key press on getchar() so I can press return to shutdown, after which I call event_base_loopbreak() on each event base I created, then I call pthread_join() from my main thread on each worker thread handle to wait for all threads to complete.
>>
>> The problem is, after calling event_base_loopbreak() I am expecting event_base_dispatch() to return but it never does, looking at the call stack for each thread they all appear to be waiting for an event. So I end up stuck waiting for threads to end which never do.
>
> The loop must breaks after event_base_loopbreak().
>
> Could you try debug mode and analyze it's messages?
> If you could write 50L code sample to reproduce this problem - I
> could have a look.
>
> Cheers,
> Azat.
> ***********************************************************************
> To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
> unsubscribe libevent-users in the body.
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users in the body.