This surely does not means that I'm stopping FAPWS, at contrary I'm more and more convinced that one of the beauty of Python reside in his gluing capabilities.
This observation is probably not new to lot of people, but for my personal case it's better now than never ;-), no ?
After that small philosophical intro, please go back to our main interest: integrate libevent within the python world.
What's great with libevent is that since several release, they have introduced several HTTP low level APIs: send_reply, send_error, ...
I've tried to use them thanks to pyrex, ctype and swig.
With every of those tools I'm facing issues, problems, ... to get a webserver working correctly.
Because I want FAPWS to be light, efficient and stable, I don't like the idea to add layers on which I don't have too much control. Hoooooo, I'm already hearing some voices ;-). The point is not linked with those tools, but more to my competencies to be able to have them working correctly. Indeed, when you are new to C (which is my case) and try to understand how to use swig, trust me, this is not piece of cake.
Thus I'll use the simple, low level Python API for this project. This will be a way for me to learn C and C API of Python.
Will it be easy to learn C from Python ?
We will see.
Any how, any helps are welcome ;-).
Here after, you can see a minimalist webserver serving the famous "Hello World!":
import ctypes import sys libevent=ctypes.cdll.LoadLibrary('libevent.so') def root_handler(req, *arg): #print "got request:", req libevent.evbuffer_new.restype=ctypes.c_void_p #Build a buffer and put page content into it buf=libevent.evbuffer_new() libevent.evbuffer_add_printf.argtypes=[ctypes.c_void_p, ctypes.c_char_p] libevent.evbuffer_add_printf(buf,"Hello world!\n\n") #send the buffer with a return code of 200 libevent.evhttp_send_reply.argtypes=[ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p] libevent.evhttp_send_reply(req, 200, "OK", buf) return 1 def main(): #We just initialise and give the server address and port libevent.event_init() libevent.evhttp_start.argtypes=[ctypes.c_char_p, ctypes.c_short] libevent.evhttp_start.restype=ctypes.c_void_p http=libevent.evhttp_start('0.0.0.0',8080) #we lik the call to root_handler at a request of "/" FUNC=ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p) libevent.evhttp_set_cb.argtypes=[ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p] libevent.evhttp_set_cb(http,"/",FUNC(root_handler), None) #we loop and wait events ;-) libevent.event_dispatch() #we close the loop print "end loop main" libevent.evhttp_free.argtypes=[ctypes.c_void_p] libevent.evhttp_free(http) if __name__=="__main__": main()
Amazingly, I'm able to get 1700#/sec on my 1.2Ghz Athlon.
[myhost ~]$ ab -n2000 -c10 http://127.0.0.1:8080/ This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0 Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright 2006 The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Server Software: Server Hostname: 127.0.0.1 Server Port: 8080 Document Path: / Document Length: 14 bytes Concurrency Level: 10 Time taken for tests: 1.170227 seconds Complete requests: 2000 Failed requests: 0 Write errors: 0 Total transferred: 196000 bytes HTML transferred: 28000 bytes Requests per second: 1709.07 [#/sec] (mean) Time per request: 5.851 [ms] (mean) Time per request: 0.585 [ms] (mean, across all concurrent requests) Transfer rate: 163.22 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 3 Processing: 2 5 2.5 4 15 Waiting: 1 5 2.6 4 15 Total: 2 5 2.5 4 15 Percentage of the requests served within a certain time (ms) 50% 4 66% 4 75% 7 80% 7 90% 9 95% 11 98% 13 99% 14 100% 15 (longest request) [myhost ~]$