diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2005-11-20 08:56:19 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2005-11-20 08:56:19 +0000 |
| commit | 5e09779c7f6b1710150d5a0f12d86ded7ede75c6 (patch) | |
| tree | ffd2e2e7d918cc30015c89bd14122aa8cadb1546 /samples | |
| parent | f20f4889bfe5a02cd9b77868b90cc8042352176a (diff) | |
| download | luasocket-5e09779c7f6b1710150d5a0f12d86ded7ede75c6.tar.gz luasocket-5e09779c7f6b1710150d5a0f12d86ded7ede75c6.tar.bz2 luasocket-5e09779c7f6b1710150d5a0f12d86ded7ede75c6.zip | |
In pre release mode!
Diffstat (limited to 'samples')
| -rw-r--r-- | samples/README | 57 | ||||
| -rw-r--r-- | samples/forward.lua | 207 | ||||
| -rw-r--r-- | samples/lpr.lua | 2 |
3 files changed, 25 insertions, 241 deletions
diff --git a/samples/README b/samples/README index 0100a4a..e63a6f5 100644 --- a/samples/README +++ b/samples/README | |||
| @@ -1,59 +1,50 @@ | |||
| 1 | This directory contains some sample programs using LuaSocket. This code | 1 | This directory contains some sample programs using |
| 2 | is not supported. | 2 | LuaSocket. This code is not supported. |
| 3 | 3 | ||
| 4 | listener.lua -- socket to stdout | 4 | listener.lua -- socket to stdout |
| 5 | talker.lua -- stdin to socket | 5 | talker.lua -- stdin to socket |
| 6 | 6 | ||
| 7 | listener.lua and talker.lua are about the simplest applications you can | 7 | listener.lua and talker.lua are about the simplest |
| 8 | write using LuaSocket. Run | 8 | applications you can write using LuaSocket. Run |
| 9 | 9 | ||
| 10 | 'lua listener.lua' and 'lua talker.lua' | 10 | 'lua listener.lua' and 'lua talker.lua' |
| 11 | 11 | ||
| 12 | on different terminals. Whatever you type on talk.lua will be | 12 | on different terminals. Whatever you type on talk.lua will |
| 13 | printed by listen.lua. | 13 | be printed by listen.lua. |
| 14 | |||
| 15 | b64.lua | ||
| 16 | qp.lua | ||
| 17 | eol.lua | ||
| 18 | |||
| 19 | These are tiny programs that perform Base64, Quoted-Printable and | ||
| 20 | end-of-line marker conversions. | ||
| 21 | 14 | ||
| 22 | lpr.lua -- lpr client | 15 | lpr.lua -- lpr client |
| 23 | 16 | ||
| 24 | This is a cool program written by David Burgess to print files using the | 17 | This is a cool program written by David Burgess to print |
| 25 | Line Printer Daemon protocol, widely used in Unix machines. It uses the | 18 | files using the Line Printer Daemon protocol, widely used in |
| 26 | lp.lua implementation, in the etc directory. Just run | 19 | Unix machines. It uses the lp.lua implementation, in the |
| 27 | 'lua lpr.lua <filename> queue=<printername>' and the file will print! | 20 | etc directory. Just run 'lua lpr.lua <filename> |
| 21 | queue=<printername>' and the file will print! | ||
| 28 | 22 | ||
| 29 | cddb.lua -- CDDB client | 23 | cddb.lua -- CDDB client |
| 30 | 24 | ||
| 31 | This is the first try on a simple CDDB client. Not really useful, but one | 25 | This is the first try on a simple CDDB client. Not really |
| 32 | day it might become a module. | 26 | useful, but one day it might become a module. |
| 33 | 27 | ||
| 34 | daytimeclnt.lua -- day time client | 28 | daytimeclnt.lua -- day time client |
| 35 | 29 | ||
| 36 | Just run the program to retrieve the hour and date in readable form from | 30 | Just run the program to retrieve the hour and date in |
| 37 | any server running an UDP daytime daemon. | 31 | readable form from any server running an UDP daytime daemon. |
| 38 | 32 | ||
| 39 | echoclnt.lua -- UDP echo client | 33 | echoclnt.lua -- UDP echo client |
| 40 | echosrvr.lua -- UDP echo server | 34 | echosrvr.lua -- UDP echo server |
| 41 | 35 | ||
| 42 | These are a UDP echo client/server pair. They work with other client and | 36 | These are a UDP echo client/server pair. They work with |
| 43 | servers as well. | 37 | other client and servers as well. |
| 44 | 38 | ||
| 45 | tinyirc.lua -- irc like broadcast server | 39 | tinyirc.lua -- irc like broadcast server |
| 46 | 40 | ||
| 47 | This is a simple server that waits simultaneously on two server sockets | 41 | This is a simple server that waits simultaneously on two |
| 48 | for telnet connections. Everything it receives from the telnet clients | 42 | server sockets for telnet connections. Everything it |
| 49 | is broadcasted to every other connected client. It tests the select | 43 | receives from the telnet clients is broadcasted to every |
| 50 | function and shows how to create a simple server whith LuaSocket. Just | 44 | other connected client. It tests the select function and |
| 51 | run tinyirc.lua and then open as many telnet connections as you want | 45 | shows how to create a simple server whith LuaSocket. Just |
| 52 | to ports 8080 and 8081. | 46 | run tinyirc.lua and then open as many telnet connections |
| 53 | 47 | as you want to ports 8080 and 8081. | |
| 54 | check-memory.lua -- checks memory consumption | ||
| 55 | |||
| 56 | This is just to see how much memory each module uses. | ||
| 57 | 48 | ||
| 58 | Good luck, | 49 | Good luck, |
| 59 | Diego. | 50 | Diego. |
diff --git a/samples/forward.lua b/samples/forward.lua deleted file mode 100644 index 548a753..0000000 --- a/samples/forward.lua +++ /dev/null | |||
| @@ -1,207 +0,0 @@ | |||
| 1 | -- load our favourite library | ||
| 2 | local socket = require"socket" | ||
| 3 | |||
| 4 | -- creates a new set data structure | ||
| 5 | function newset() | ||
| 6 | local reverse = {} | ||
| 7 | local set = {} | ||
| 8 | return setmetatable(set, {__index = { | ||
| 9 | insert = function(set, value) | ||
| 10 | if not reverse[value] then | ||
| 11 | table.insert(set, value) | ||
| 12 | reverse[value] = table.getn(set) | ||
| 13 | end | ||
| 14 | end, | ||
| 15 | remove = function(set, value) | ||
| 16 | local index = reverse[value] | ||
| 17 | if index then | ||
| 18 | reverse[value] = nil | ||
| 19 | local top = table.remove(set) | ||
| 20 | if top ~= value then | ||
| 21 | reverse[top] = index | ||
| 22 | set[index] = top | ||
| 23 | end | ||
| 24 | end | ||
| 25 | end | ||
| 26 | }}) | ||
| 27 | end | ||
| 28 | |||
| 29 | -- timeout before an inactive thread is kicked | ||
| 30 | local TIMEOUT = 10 | ||
| 31 | -- set of connections waiting to receive data | ||
| 32 | local receiving = newset(1) | ||
| 33 | -- set of sockets waiting to send data | ||
| 34 | local sending = newset() | ||
| 35 | -- context for connections and servers | ||
| 36 | local context = {} | ||
| 37 | |||
| 38 | function wait(who, what) | ||
| 39 | if what == "input" then receiving:insert(who) | ||
| 40 | else sending:insert(who) end | ||
| 41 | context[who].last = socket.gettime() | ||
| 42 | coroutine.yield() | ||
| 43 | end | ||
| 44 | |||
| 45 | -- initializes the forward server | ||
| 46 | function init() | ||
| 47 | if table.getn(arg) < 1 then | ||
| 48 | print("Usage") | ||
| 49 | print(" lua forward.lua <iport:ohost:oport> ...") | ||
| 50 | os.exit(1) | ||
| 51 | end | ||
| 52 | -- for each tunnel, start a new server socket | ||
| 53 | for i, v in ipairs(arg) do | ||
| 54 | -- capture forwarding parameters | ||
| 55 | local iport, ohost, oport = | ||
| 56 | socket.skip(2, string.find(v, "([^:]+):([^:]+):([^:]+)")) | ||
| 57 | assert(iport, "invalid arguments") | ||
| 58 | -- create our server socket | ||
| 59 | local server = assert(socket.bind("*", iport)) | ||
| 60 | server:settimeout(0) -- we don't want to be killed by bad luck | ||
| 61 | -- make sure server is tested for readability | ||
| 62 | receiving:insert(server) | ||
| 63 | -- add server context | ||
| 64 | context[server] = { | ||
| 65 | thread = coroutine.create(accept), | ||
| 66 | ohost = ohost, | ||
| 67 | oport = oport | ||
| 68 | } | ||
| 69 | end | ||
| 70 | end | ||
| 71 | |||
| 72 | -- starts a connection in a non-blocking way | ||
| 73 | function connect(who, host, port) | ||
| 74 | who:settimeout(0) | ||
| 75 | local ret, err = who:connect(host, port) | ||
| 76 | if not ret and err == "timeout" then | ||
| 77 | wait(who, "output") | ||
| 78 | ret, err = who:connect(host, port) | ||
| 79 | if not ret and err ~= "already connected" then | ||
| 80 | kick(context[who].peer) | ||
| 81 | kick(who) | ||
| 82 | return | ||
| 83 | end | ||
| 84 | end | ||
| 85 | return forward(who) | ||
| 86 | end | ||
| 87 | |||
| 88 | -- gets rid of a client | ||
| 89 | function kick(who) | ||
| 90 | if who then | ||
| 91 | sending:remove(who) | ||
| 92 | receiving:remove(who) | ||
| 93 | who:close() | ||
| 94 | context[who] = nil | ||
| 95 | end | ||
| 96 | end | ||
| 97 | |||
| 98 | -- loops accepting connections and creating new threads to deal with them | ||
| 99 | function accept(server) | ||
| 100 | while true do | ||
| 101 | -- accept a new connection and start a new coroutine to deal with it | ||
| 102 | local client = server:accept() | ||
| 103 | if client then | ||
| 104 | -- create contexts for client and peer. | ||
| 105 | local peer, err = socket.tcp() | ||
| 106 | if peer then | ||
| 107 | context[client] = { | ||
| 108 | last = socket.gettime(), | ||
| 109 | -- client goes straight to forwarding loop | ||
| 110 | thread = coroutine.create(forward), | ||
| 111 | peer = peer, | ||
| 112 | } | ||
| 113 | context[peer] = { | ||
| 114 | last = socket.gettime(), | ||
| 115 | peer = client, | ||
| 116 | -- peer first tries to connect to forwarding address | ||
| 117 | thread = coroutine.create(connect), | ||
| 118 | last = socket.gettime() | ||
| 119 | } | ||
| 120 | -- resume peer and client so they can do their thing | ||
| 121 | local ohost = context[server].ohost | ||
| 122 | local oport = context[server].oport | ||
| 123 | coroutine.resume(context[peer].thread, peer, ohost, oport) | ||
| 124 | coroutine.resume(context[client].thread, client) | ||
| 125 | else | ||
| 126 | print(err) | ||
| 127 | client:close() | ||
| 128 | end | ||
| 129 | end | ||
| 130 | -- tell scheduler we are done for now | ||
| 131 | wait(server, "input") | ||
| 132 | end | ||
| 133 | end | ||
| 134 | |||
| 135 | -- forwards all data arriving to the appropriate peer | ||
| 136 | function forward(who) | ||
| 137 | who:settimeout(0) | ||
| 138 | while true do | ||
| 139 | -- wait until we have something to read | ||
| 140 | wait(who, "input") | ||
| 141 | -- try to read as much as possible | ||
| 142 | local data, rec_err, partial = who:receive("*a") | ||
| 143 | -- if we had an error other than timeout, abort | ||
| 144 | if rec_err and rec_err ~= "timeout" then return kick(who) end | ||
| 145 | -- if we got a timeout, we probably have partial results to send | ||
| 146 | data = data or partial | ||
| 147 | -- forward what we got right away | ||
| 148 | local peer = context[who].peer | ||
| 149 | while true do | ||
| 150 | -- tell scheduler we need to wait until we can send something | ||
| 151 | wait(who, "output") | ||
| 152 | local ret, snd_err | ||
| 153 | local start = 0 | ||
| 154 | ret, snd_err, start = peer:send(data, start+1) | ||
| 155 | if ret then break | ||
| 156 | elseif snd_err ~= "timeout" then return kick(who) end | ||
| 157 | end | ||
| 158 | -- if we are done receiving, we are done | ||
| 159 | if not rec_err then | ||
| 160 | kick(who) | ||
| 161 | kick(peer) | ||
| 162 | break | ||
| 163 | end | ||
| 164 | end | ||
| 165 | end | ||
| 166 | |||
| 167 | -- loop waiting until something happens, restarting the thread to deal with | ||
| 168 | -- what happened, and routing it to wait until something else happens | ||
| 169 | function go() | ||
| 170 | while true do | ||
| 171 | -- check which sockets are interesting and act on them | ||
| 172 | readable, writable = socket.select(receiving, sending) | ||
| 173 | -- for all readable connections, resume its thread | ||
| 174 | for _, who in ipairs(readable) do | ||
| 175 | if context[who] then | ||
| 176 | receiving:remove(who) | ||
| 177 | coroutine.resume(context[who].thread, who) | ||
| 178 | end | ||
| 179 | end | ||
| 180 | -- for all writable connections, do the same | ||
| 181 | for _, who in ipairs(writable) do | ||
| 182 | if context[who] then | ||
| 183 | sending:remove(who) | ||
| 184 | coroutine.resume(context[who].thread, who) | ||
| 185 | end | ||
| 186 | end | ||
| 187 | -- put all inactive threads in death row | ||
| 188 | local now = socket.gettime() | ||
| 189 | local deathrow | ||
| 190 | for who, data in pairs(context) do | ||
| 191 | if data.peer then | ||
| 192 | if now - data.last > TIMEOUT then | ||
| 193 | -- only create table if at least one is doomed | ||
| 194 | deathrow = deathrow or {} | ||
| 195 | deathrow[who] = true | ||
| 196 | end | ||
| 197 | end | ||
| 198 | end | ||
| 199 | -- finally kick everyone in deathrow | ||
| 200 | if deathrow then | ||
| 201 | for who in pairs(deathrow) do kick(who) end | ||
| 202 | end | ||
| 203 | end | ||
| 204 | end | ||
| 205 | |||
| 206 | init() | ||
| 207 | go() | ||
diff --git a/samples/lpr.lua b/samples/lpr.lua index caab387..5ab4d69 100644 --- a/samples/lpr.lua +++ b/samples/lpr.lua | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | local lp = require("socket.lp") | 1 | local lp = require("socket.lp") |
| 2 | 2 | ||
| 3 | local function usage() | 3 | local function usage() |
| 4 | print('\nUsage: lua lptest.lua [filename] [keyword=val...]\n') | 4 | print('\nUsage: lua lpr.lua [filename] [keyword=val...]\n') |
| 5 | print('Valid keywords are :') | 5 | print('Valid keywords are :') |
| 6 | print( | 6 | print( |
| 7 | ' host=remote host or IP address (default "localhost")\n' .. | 7 | ' host=remote host or IP address (default "localhost")\n' .. |
