Hi Azat,

Thank you for the detailed response and sorry for the late reply, I do really 
appreciate your time to respond - thank you. May I also appologize for the 
incompleteness of the example, I lifted the code out of a bigger project and 
failed to compile it stand-alone before I sent it - lesson learned :)

Yes that fixed the problem, it also highlighted another problem, I was linking 
against an earlier version of the lib event library so the 
evthread_use_pthreads() could not be resolved at link time, I have also 
corrected that problem and also used “event2/event.h” instead of “event.h”.  It 
is not that obvious from the various examples that there are different headers 
and library versions to contend with (thats my excuse anyway :)

It now works as expected so thank you for your help.  I did try to use libevhtp 
but I could not get it to compile, I think this was most likely down to the 
fact I was including version 1x of the lib event, I will try it again. 

I am trying to create two different HTTP server patterns: -

First one is a simple multi-threaded web server, where I receive requests 
asynchronously complete HTTP requests, event driven into a buffer (so 
presumably a buffered event) - this is the async part.  Once I receive a valid 
HTTP request from the client, I put the request (and its connection) into a 
queue to be serviced synchronously by a thread from a pool of worker threads, 
ones the request has been served, the connection is once again put into the 
async receive queue ready for the next request.  

The second pattern, I want to create a server to be able to accept a large 
number of long-term and generally idle connections. Like the first example, the 
event driven receive will handle the request part, and once a valid request has 
been received the connection will be added to a connection list.  At any point, 
other threads in the server will be able to send data to any clients open 
connection by looking up the open connection in the connection list. To 
visualise in HTTP terms the response data would most likely look like a 
never-ending chunked response, each chunk would be sent as times dictated by 
the server system.

I am sure there are more formal names/descriptions for these patterns but thats 
as I understand them. These patterns are both terribly important for web-scale 
application design so they are worthy of some good documentation I think. 

For me personally, I thought it would be good to learn how to do this using 
libevent just as an exercise to learn how the library and event model 
implemented by libevent works, but so far its not been terribly obvious how I 
should approach either of these.  I tried the first pattern but failed to make 
it work, evthread_use_pthreads() might solve this now so I will need to test.

It would be terribly helpful if someone could point me in the right general 
direction with some pseudo code, which functions I would call to achieve those 
patterns, I know that may be asking a bit much but I thought I would ask 
anyway. 

For what its worth, I will make an effort do document my efforts on these two 
patterns on my blog http://gerrysweeney.com/ in order to hopefully feedback to 
the community. 

Gerry

> 


Gerry Sweeney
http://gerrysweeney.com/


> On 30 Dec 2014, at 16:00, Azat Khuzhin <[email protected]> wrote:
> 
> On Sun, Dec 28, 2014 at 06:49:28PM +0000, Gerry Sweeney wrote:
>> 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 
> 
> Please see comments for code, in short all you need in
> evthread_use_pthreads(), but you code have some design issues and also
> errors that don't allow me to compile this simple program.
> 
>> 
>> 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);
> 
> No such function -- httpserver_GenericHandler.
> 
>> 
>>        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);
> 
> This will close accept socket, because of LEV_OPT_CLOSE_ON_FREE in
> evhttp_accept_socket_with_handle(), you must use evhttp_bind_listener()
> here to avoid this.
> 
> You could look into libevhtp, it has thread support out-of-the-box, and
> it is simpler since it is library that just implements http server.
> 
>> 
>>      // 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);
> 
> Here you first freeing base, and then in separate thread
> event_base_dispatch() will use some internal fields in it after free --
> IOW you must free all resources after pthread_join().
> 
>> 
>>      // We are in the main thread so we join with each worker thread here
>>        pthread_join(worker->thr, NULL);
>>    }
>>    std::cout << “Closed..." << std::endl;
> 
> Bad quotes.
> 
>> 
>>    return 0;
>> }
>> 
>> int main(int argc, char* argv[])
>> {
> 
> In short all you need is add the next line here:
> evthread_use_pthreads();
> 
> This will enable inter-thread notification for loop break.
> 
> [ I do have some other changes to you program, so if just adding
> evthread_use_pthreads() didn't work for you -- let me know, I will send
> you patch with my local changes ].
> 
>>    httpserver_start(8080, NUM_THREADS, 100);
> 
> NUM_THREADS undefined.
> ***********************************************************************
> To unsubscribe, send an e-mail to [email protected] with
> unsubscribe libevent-users    in the body.

***********************************************************************
To unsubscribe, send an e-mail to [email protected] with
unsubscribe libevent-users    in the body.

Reply via email to