/usr/share/doc/lua-apr-doc/examples/threaded-webserver.lua is in lua-apr-doc 0.23.2.dfsg-4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | --[[
Example: Multi threaded webserver
Author: Peter Odding <peter@peterodding.com>
Last Change: November 6, 2011
Homepage: http://peterodding.com/code/lua/apr/
License: MIT
Thanks to the [multi threading] [threading_module] and [thread queue]
[thread_queues] modules in the Apache Portable Runtime it is possible to
improve the performance of the [single threaded webserver] [simple_server]
from the previous example. Here is a benchmark of the multi threaded code
listed below (again using [ApacheBench] [ab], but now with the `-c`
argument):
$ CONCURRENCY=4
$ lua examples/threaded-webserver.lua $CONCURRENCY &
$ ab -qt5 -c$CONCURRENCY http://localhost:8080/ | grep 'Requests per second\|Transfer rate'
Requests per second: 9210.72 [#/sec] (mean)
Transfer rate: 5594.79 [Kbytes/sec] received
Comparing these numbers to the benchmark of the [single threaded webserver]
[simple_server] we can see that the number of requests per second went from
3670 to 9210, more than doubling the throughput of the webserver on a dual
core processor. If you want to know how we can make it even faster, have a
look at the [asynchronous webserver] [async_server] example.
[threading_module]: #multi_threading
[thread_queues]: #thread_queues
[simple_server]: #example_single_threaded_webserver
[ab]: http://en.wikipedia.org/wiki/ApacheBench
[thread_pool]: http://en.wikipedia.org/wiki/Thread_pool_pattern
[async_server]: #example_asynchronous_webserver
]]
local num_threads = tonumber(arg[1]) or 2
local port_number = tonumber(arg[2]) or 8080
local template = [[
<html>
<head>
<title>Hello from Lua/APR!</title>
<style type="text/css">
body { font-family: sans-serif; }
dt { font-weight: bold; }
dd { font-family: monospace; margin: -1.4em 0 0 14em; }
</style>
</head>
<body>
<h1>Hello from Lua/APR!</h1>
<p><em>This web page was served by worker %i.</em></p>
<p>The headers provided by your web browser:</p>
<dl>%s</dl>
</body>
</html>
]]
-- Load the Lua/APR binding.
local apr = require 'apr'
-- Initialize the server socket.
local server = assert(apr.socket_create())
assert(server:bind('*', port_number))
assert(server:listen(num_threads * 2))
print("Running webserver with " .. num_threads .. " client threads on http://localhost:" .. port_number .. " ..")
-- Create the thread queue (used to pass sockets between threads).
local queue = apr.thread_queue(num_threads)
-- Define the function to execute in each child thread.
function worker(thread_id, queue, template)
pcall(require, 'luarocks.require')
local apr = require 'apr'
while true do
local client, msg, code = queue:pop()
assert(client or code == 'EINTR', msg)
if client then
local status, message = pcall(function()
local request = assert(client:read(), "Failed to receive request from client!")
local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)')
local headers = {}
for line in client:lines() do
local name, value = line:match '^(%S+):%s+(.-)$'
if not name then
break
end
table.insert(headers, '<dt>' .. name .. ':</dt><dd>' .. value .. '</dd>')
end
table.sort(headers)
local content = template:format(thread_id, table.concat(headers))
client:write(protocol, ' 200 OK\r\n',
'Content-Type: text/html\r\n',
'Content-Length: ' .. #content .. '\r\n',
'Connection: close\r\n',
'\r\n',
content)
assert(client:close())
end)
if not status then
print('Error while serving request:', message)
end
end
end
end
-- Create the child threads and keep them around in a table (so that they are
-- not garbage collected while we are still using them).
local pool = {}
for i = 1, num_threads do
table.insert(pool, apr.thread(worker, i, queue, template))
end
-- Enter the accept() loop in the parent thread.
while true do
local status, message = pcall(function()
local client = assert(server:accept())
assert(queue:push(client))
end)
if not status then
print('Error while serving request:', message)
end
end
-- vim: ts=2 sw=2 et
|