--[[ -- 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