You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.4 KiB
Lua

--[[
-- Simplest possible tcp echo server.
-- ... Well, that's a lie. It's the simplest possible TCP server that can handle multiple clients at the same time, that I was able to write.
]]--
local socket = require("socket")
local server = socket.tcp()
-- The low timeout time is so no one client blocks any other
-- I can see that if the server needs to receive or send a lot of data, then those routines will become blocked. I _could_ use something better than coroutines to make this, but then it wouldn't have been so simple, now would it? :þ
server:settimeout(0.005, "t")
hostname = "localhost"
port = 12346
server:bind(hostname, port)
server:listen(128)
local clients = {}
co_newClient = coroutine.create(function ()
while true do
local nC, err = server:accept()
if err then
if err == "timeout" then
coroutine.yield()
else
error("ERROR: "..err)
end
end
if nC then
-- Individual clients, however, need a higher timeout if we want to be able to give them time to connect to the tcp socket and actually send something.
nC:settimeout(10)
-- Insert the new client into the client table
table.insert(clients, nC)
nC = nil
coroutine.yield()
end
end
end)
co_selectClient = coroutine.create(function ()
while true do
-- For more information, see https://lunarmodules.github.io/luasocket/socket.html#select
r, w, e = socket.select(clients, nil, 0.005)
if e then
-- Timeout = No clients, keep waiting for clients
if e == "timeout" then
coroutine.resume(co_newClient)
else
error("ERROR: "..e)
end
end
coroutine.yield()
end
end)
co_receiveFromClient = coroutine.create(function ()
while true do
for _, client in ipairs(r) do
local message, err, partial = client:receive("*l")
if err then
-- Maybe timeout should remove the client from the table too?
if err == "timeout" then
coroutine.yield()
elseif err == "closed" then
table.remove(clients, _)
coroutine. yield()
end
end
if message then
if message == "goodbye" then
client:send("GOODBYE\n")
client:close()
table.remove(clients, _)
coroutine.yield()
else
client:send("Echo: "..message.."\n")
coroutine.yield()
end
end
if partial then
coroutine.yield()
end
end
coroutine.yield()
end
end)
while true do
coroutine.resume(co_newClient)
coroutine.resume(co_selectClient)
coroutine.resume(co_receiveFromClient)
end