require'concurrent'
require'cltime'
require'socket'
concurrent.setoption('trapexit',true)
local out=io.write
port=1888
nodename='master@linkerhp'
concurrent.init(nodename)
out('concurrent node name:'..nodename.."/n")
--tcpport=socket.tcp()
--tcpport:bind("*",port)
--tcpport:settimeout(0)
require'copas'
local tcphandlers={}
local function tcphandler(sock)
clientip,clientport=sock:getpeername()
sock=copas.wrap(sock)
sock:settimeout(0)
clientid=clientip..':'..clientport
tcphandlers[clientid]='connected'
while true do
local data=sock:receive("*l")-- receive a line
--if tcphandlers[clientid]=='connected' then
if data then
out('copas:/"'..data..'/"')
out"/n"
concurrent.send('master',{cmd='tcpdata',
from=sock,
clientid=clientid,
['data']=data})
end
--sock:send(data)
--out'handler step/n'
--else
--return;
--end
end
end
tcplistensock=socket.bind("*",port)
copas.addserver(tcplistensock,tcphandler)
-- udp
local udpinit=function(port)
local u=socket.udp()
collectgarbage('collect')
u:settimeout(0)
--u:setoption('reuseaddr',true)
ret,err=u:setsockname("*",port)
if not ret then
out('bind error:'..err)
concurrent.exit('port:'..port..' bind error.')
end
out('udp listening at '..port..'/n')
out'/n'
return u;
end
local function udpfini(udpsock)
udpsock:close()
end
local udpstep=function(udpsock)
local data,ip,port=udpsock:receivefrom(1024)
if data then
--out('udp receivefrom '..ip..':'..port..' '..data..'/n')
--out(port)
concurrent.send('master',{cmd='udpdata',
from=udpsock,
['clientip']=ip,
['clientport']=port,
['data']=data})
out'=/n'
--udpsock:sendto(data,ip,port)
end
--out'udp step/n'
end
--udppkt=0
--function incudppkt() udppkt=udppkt+1 end
--function getudppkt() return udppkt end
-- concurrent main process
--local udpsock=udpinit(port)-- must be here!!!!!!!!!!!!!!!!!!!!!!!!
local master=function()
out"master inited./n"
selfpid=concurrent.whereis('master')
out('selfpid:'..selfpid)
local udplistener={}
local tcplistener={}
local udpsock=udpinit(port)
if not udpsock then concurrent.exit('udp init failed.') end
concurrent.send('monitor',{from=selfpid,cmd='started',['udpsock']=udpsock})
while true do
out'#'
copas.step(0.1)-- noblock
udpstep(udpsock)
local msg=concurrent.receive(100) -- timeout
--if not msg then out'master timeout/n'; end
--io.flush()
if msg then
if msg.cmd=='new udp' then
elseif msg.cmd=='accept tcp' then
elseif msg.cmd=='tcpdata' then
out('master got a tcp data:'..msg.data)
out'/n'
msg.from:send(msg.data)
--msg.from:close()
--tcphandlers[msg.clientid]='disconnect'
elseif msg.cmd=='udpdata' then
out('udp:'..msg.clientip..':'..msg.clientport..' '..msg.data)
msg.from:sendto(msg.data,msg.clientip,msg.clientport)
--incudppkt()
--concurrent.exit('master exit.')
elseif msg.cmd=='close tcp' then
elseif msg.cmd=='close udp' then
elseif msg.cmd=='disconnect tcp client' then
else
error("*********************")
end
end
end
end
function monitor()
local masterpid=concurrent.spawnmonitor(master)
concurrent.register('master',masterpid)
--concurrent.monitor('master')
usocks={}
while true do
out'*'
local msg=concurrent.receive(1000)
--for k,v in pairs(usocks) do
-- if not msg then print('/nudppkt:'..k:status()..'/n') end
--end
-- msg.signal=='EXIT' or
if msg and (msg.signal=='DOWN') then
out(msg.from..' exit:'..msg.reason..'./n')
if usocks[msg.from] then
usocks[msg.from]:close()
usocks[msg.from]=nil
collectgarbage('collect')
out'gc'
end
concurrent.unregister('master')
local masterpid=concurrent.spawnlink(master)
concurrent.register('master',masterpid)
concurrent.monitor('master')
elseif msg and msg.cmd=='started' then
out'receive a started msg./n'
if msg.udpsock and msg.from then
usocks[msg.from]=msg.udpsock
out'monitor: saw a master./n'
end
end
end
end
local monitorpid=concurrent.spawn(monitor)
concurrent.register('monitor',monitorpid)
--while true do
-- main loop
--concurrent.step(0)-- noblock
--out"."
--cltime.sleep(1)
io.flush()
--end
concurrent.loop()
--return masterpid