I have a gopher server written in Lua [1] that uses coroutines to handle each connection. This bit of code is executed as the main menu page [2] is being displayed (with comments)
-- -------------------
-- Load in some modules.
-- The first makes a gopher menu item of type link
-- The second allows us to do a TCP connection
-- --------------------------
local mklink = require "port70.mklink"
local tcp = require "org.conman.nfl.tcp"
-- ------------------------------
-- tcp.connect() connects to the given address and port and timeout
-- (in seconds). This function will create a socket, set it
-- to non-blocking, call connect, then yield. When the socket has
-- connected, the coroutine is then resumed with the connection; if
-- 1 second has passed before the connection is done, then nil is
-- returned when resumed. This just calls a local QOTD service.
-- ---------------------
local ios = tcp.connect("127.0.0.1",'qotd',1)
if ios then
local res = ""
-- --------------------------------
-- The following loop will yield the coroutine until a line
-- of data has been accumulated from the network. The coroutine
-- is then resumed with the line of text.
-- ---------------------------------------
for line in ios:lines() do
-- -----------
-- We're just accumulating the text into one long blob of
-- text that we'll return
-- -----------------
res = res .. mklink { type = 'info' , display = line }
end
ios:close() -- another yield point, when closed, resume
return res
else
return mklink { type = 'info' , display = "Not Available" }
end
No exceptions here. If we can't connect, it's a simple 'if' test and do something else. The functions `tcp.connect()`, `ios:lines()` and `ios:close()` are all blocking points that cause the coroutine to yield. Yes, if I put something like `while true do end` that will block the entire process as there is no preemption, but aside from that detail, I find this code easy to read.
[1] https://github.com/spc476/port70/blob/master/share/index.por...
[2] gopher://gopher.conman.org/