Hi
I am not sure if c++ is an option. I have created cppexecutor
<https://github.com/cppexecutor/gexecutor/blob/dev/README.md> (
https://github.com/cppexecutor/gexecutor/blob/dev/README.md) just for this
particular use case. It works on both libevent and asio...

Even if you don't want to use library you can see a sample implementation
of one way to handle such use case.

thanks,
Gaurav



On Sat, Jan 3, 2015 at 9:02 AM, Gerry Sweeney <
[email protected]> wrote:

> 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.
>



-- 
Gaurav Rastogi

Reply via email to