new gist: simpletcpserver.lua
parent
f5271eda24
commit
d4f2d5cfb0
@ -0,0 +1,92 @@
|
||||
--[[
|
||||
-- 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
|
Loading…
Reference in New Issue