Advertisement
Snusmumriken

Reliable UDP protool

Jun 1st, 2017 (edited)
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.00 KB | None | 0 0
  1. require'relativerequire'
  2. math.randomseed(os.time())
  3. local random = math.random
  4. local serpent = require'serpent'
  5. local parser = require'parser'
  6. local socket = require'socket'
  7. local udp = socket.udp4 or socket.udp
  8. local hash = parser.hash
  9.  
  10. local dbg = false
  11. function printf(s, ...)
  12.     if not dbg then return end
  13.     print(s:format(...))
  14. end
  15.  
  16.  
  17.  
  18.  
  19. local function tableprinter(t, opts, pool, lvl)
  20.     pool = pool or {}
  21.     opts = opts or {}
  22.     local res = {}
  23.     lvl = lvl or 1
  24.     for k, v in pairs(t) do
  25.         if not opts[k] then
  26.             if type(v) == 'table' and not pool[v] then
  27.                 if not pool[v] then
  28.                     pool[v] = 1
  29.                     table.insert(res, k..'::\n'..('  '):rep(lvl+1)..tableprinter(v, opts, pool, lvl + 1))
  30.                 end
  31.             else
  32.                 table.insert(res, k..': '..tostring(v))
  33.             end
  34.         end
  35.     end
  36.     return table.concat(res, '\n'..('  '):rep(lvl))
  37. end
  38.  
  39. local function b(char)
  40.     local char = char:byte()
  41.     local res, rest = {}
  42.     while char > 0 do
  43.         char = char * .5
  44.         if math.floor(char) == char then
  45.             table.insert(res, 1, 0)
  46.         else
  47.             char = char - .5
  48.             table.insert(res, 1, 1)
  49.         end
  50.     end
  51.     table.insert(res, 1, ('0'):rep(8-#res))
  52.     return table.concat(res)..' '
  53. end
  54.  
  55. local function binstr(str)
  56.     return str:gsub('.', b)
  57. end
  58.  
  59. local channel = {}
  60. channel.sock = socket.udp()
  61. channel.sock:settimeout(0)
  62. channel.sock:setsockname('*', 3480)
  63.  
  64. --[[local s = parser.encode{
  65.     flags = {         --flags:
  66.         fp = true,      -- first packet
  67.         sp = true,      -- send/receive flag
  68.         ld = true,      -- confirm
  69.         sm = true       -- service message
  70.     },
  71.     id =     math.random(999), -- id of message (x32, 4chars)
  72.     count =  44,               -- count of parts in message (x32, 4chars)
  73.     part =   33,               -- current part number (x32, 4chars)
  74.     window = 2,                -- data-travel window size (N msgs per loop, x8, 1char)
  75.     hash =   111,              -- hash of message/part (x32, 4chars)
  76.     data =   'Love'            -- data of message ( (MTU - 23) chars)
  77. }
  78.  
  79. parser.decode(s)
  80. ]]
  81.  
  82. local message = {}
  83. message.encode = parser.encode
  84. message.decode = parser.decode
  85. message.__index = message
  86. message.conf = {
  87.     window = 8,
  88.     len = 50,
  89.     disc = .6,
  90.     retry = 30,
  91. }
  92.  
  93. local function randstr(n)
  94.     n = n or 10
  95.     local res = {}
  96.     for i = 1, n do
  97.         res[i] = string.char(math.random(42, 126))
  98.     end
  99.     return table.concat(res)
  100. end
  101.  
  102. function message:build(data)
  103.     local len = self.conf.len
  104.     local o = {}
  105.     o.id = math.random(4228250624)
  106.     o.parts = {}
  107.     o.count = math.ceil(#data/len)
  108.     o.flags = {
  109.         fp = true,
  110.         sp = true,
  111.         ld = false,
  112.         sm = false
  113.     }
  114.     o.window = self.conf.window
  115.     for i = 1, o.count do
  116.         table.insert(o.parts, data:sub((i-1)*len + 1, i * len))
  117.     end
  118.     o.hash = hash(data)
  119.     o.data = ''
  120.     return o
  121. end
  122.  
  123. function message:call(fp, udp, ip, port) -- first packet
  124.     local isSend = type(fp) == 'string'
  125.     local o = isSend and self:build(fp) or fp
  126.     o.parts = o.parts or {}        -- list of all parts
  127.     o.flags.fp = false
  128.     o.flags.sp = false
  129.     o.flags.ld = true
  130.     if not isSend then
  131.         o.parts[fp.part] = fp.data
  132.     end
  133.     o.part = 0
  134.     o.update = isSend and self.sw or self.rw  -- update function
  135.     o.timer = isSend and self.conf.disc/2 or self.conf.disc
  136.     o.retry = self.conf.retry
  137.     o.destroy = false   -- destroy flag
  138.     o.data = ''
  139.     o.udp = udp
  140.     o.ip = ip
  141.     o.port = port
  142.     o.bytes = 0
  143.     o.spdtimer = 1
  144.     o.spd = 0
  145.     setmetatable(o, self)
  146.     if isSend then
  147.         o:sendwindow()
  148.     else
  149.         o:sendto(o:encode())
  150.     end
  151.     return o
  152. end
  153.  
  154. setmetatable(message, {__call = message.call})
  155.  
  156. function log(text, ...)
  157.     local file, err = io.open('c:/bin/error_or_not.txt', 'a')
  158.     file:write((... and text:format(...) or text)..'\r\n')
  159.     file:close()
  160. end
  161.  
  162. function message:sendwindow()
  163.     self.flags.sp = true
  164.     printf(self.id..' sendwindow')
  165.     for i = 1, self.window do
  166.         self.flags.fp = self.part == 0
  167.         self.flags.ld = self.window == i or self.part == self.count or self.part == 0
  168.         if self.part < self.count then
  169.             self.part = self.part + 1
  170.             self.data = self.parts[self.part]
  171.             printf('send window', self.part, self.data)
  172.         end
  173.         self:sendto(self:encode())
  174.     end
  175. end
  176.  
  177. function message:updateTimers(dt, bytes)
  178.     self.spdtimer = self.spdtimer - dt
  179.     self.timer = self.timer - dt
  180.    
  181.     if self.spdtimer < 0 then
  182.         self.spd = self.bytes
  183.         self.bytes = 0
  184.         self.spdtimer = 1
  185.     end
  186.    
  187.     -- calc received data speed
  188.     if bytes then
  189.         self.timer = self.flags.sp and self.conf.disc/10 or  self.conf.disc
  190.         self.retry = self.conf.retry
  191.         self.bytes = self.bytes + bytes
  192.         return
  193.     end
  194.    
  195.     if self.timer < 0 then
  196.         if self.retry > 1 then
  197.             self.timer = self.conf.disc
  198.             self.flags.ld = true
  199.             self:sendto(self:encode())
  200.             self.retry = self.retry - 1
  201.         else
  202.             self.destroy = true
  203.         end
  204.     end
  205.    
  206. end
  207.  
  208. function message:sw(dt, data)
  209.     self:updateTimers(dt)
  210.     if not data or not data.flags.ld then return end
  211.     if self.part > data.part then
  212.         printf(self.id..' BACKTRACK!! '..self.part..'  '..data.part)
  213.         self.part = data.part
  214.     end
  215.    
  216.     -- it calls only if data received (receiver confirm received packets)
  217.     if self.part == self.count then
  218.         self.destroy = true
  219.         return
  220.     else
  221.         self:sendwindow()
  222.     end
  223. end
  224.  
  225. function message:rw(dt, data)
  226.     self:updateTimers(dt, data and #data.data)
  227.     if not data or data.part < 1 then return end
  228.     self.parts[data.part] = data.data
  229.    
  230.     -- if sender used 'need confirm'-flag, send confirm
  231.     if data.flags.ld then
  232.         self.part = #self.parts
  233.         self:sendto(self:encode())
  234.     end
  235.     if #self.parts == self.count then
  236.         self:sendto(self:encode())
  237.         self.part = self.count
  238.         self.retry = 5
  239.         self.update = self.rwo
  240.         self.data = table.concat(self.parts)
  241.         self.parts = {}
  242.         if hash(self.data) ~= self.hash then error('Hash not confirmed! '..hash(self.data)..' :: '..self.hash) end
  243.         return true
  244.     end
  245. end
  246.  
  247. function message:rwo(dt, data)
  248.     self.data = ''
  249.     if data then self:sendto(self:encode()) end
  250.     self:updateTimers(dt)
  251. end
  252.  
  253. function message:sendto(data)
  254.     self.udp:sendto(data, self.ip, self.port)
  255. end
  256.  
  257. local channel = {}
  258. channel.__index = channel
  259. function channel:call(udp)
  260.     local o = {}
  261.     o.udp = udp
  262.     o.spool = {}
  263.     o.rpool = {}
  264.     o.time = socket.gettime
  265.     o.timer = o.time()
  266.     o.delta = 0
  267.     return setmetatable(o, {__index = self})
  268. end
  269.  
  270. setmetatable(channel, {__call = channel.call})
  271.  
  272. function channel:updateTime()
  273.     local t = self.time()
  274.     self.delta = t - self.timer
  275.     self.timer = t
  276.     return self.delta
  277. end
  278.  
  279. function channel:send(msg, ip, port)
  280.     local msg = message(msg, self.udp, ip, port)
  281.     self.spool[msg.id] = msg
  282. end
  283.  
  284. function channel:receive()
  285.     local dt = self:updateTime()
  286.     return function()
  287.         local data, ip, port = self.udp:receivefrom()
  288.         while data and ip and port do
  289.             local msg = parser.decode(data)
  290.             if not msg then return data, ip, port end
  291.             local pool = msg.flags.sp and self.rpool or self.spool
  292.  
  293.             if pool[msg.id] then
  294.                 printf('Msg %s updated', msg.id)
  295.                 if pool[msg.id]:update(dt, msg) then
  296.                     return pool[msg.id].data, pool[msg.id].ip, pool[msg.id].port
  297.                 end
  298.             elseif msg.flags.ld and msg.flags.sp then
  299.                 msg = message(msg, self.udp, ip, port)
  300.                 pool[msg.id] = msg
  301.             end
  302.             data, ip, port = self.udp:receivefrom()
  303.         end
  304.         self:updatePool(self.spool, dt)
  305.  
  306.         local c = self:updatePool(self.rpool, dt)
  307.         if c then return c.data, c.ip, c.port end
  308.     end
  309. end
  310.  
  311. function channel:updatePool(pool, dt)
  312.     for k, v in pairs(pool) do
  313.         if v.update(v, dt) then
  314.             return v
  315.         end
  316.         if v.destroy then
  317.             printf('Msg %s destroyed', k)
  318.             pool[k] = nil
  319.         end
  320.     end
  321. end
  322.  
  323. local u1 = udp()
  324. u1:settimeout(0)
  325. u1:setsockname('*', 4444)
  326. ch1 = channel(u1)
  327.  
  328. local u2 = udp()
  329. u2:settimeout(0)
  330. u2:setsockname('*', 5555)
  331. ch2 = channel(u2)
  332.  
  333. --ch1:send(msg, '127.0.0.1', 5555)
  334. --ch1:send(msg, '127.0.0.1', 5555)
  335.  
  336. function timered(f, delay)
  337.     local t = socket.gettime()
  338.     return function(...)
  339.         if socket.gettime() - t > delay then f(...) end
  340.     end
  341. end
  342.  
  343.  
  344. function upd1()
  345.     for data, ip, port in ch1:receive() do
  346.         local file = io.open('c:/bin/textfile.txt', 'wb')
  347.         file:write(data)
  348.         file:close()
  349.     end
  350. end
  351.  
  352. function upd2()
  353.     for data, ip, port in ch2:receive() do
  354.         print('RCV: '..data)
  355.     end
  356. end
  357.  
  358. u1 = timered(upd1, 0)
  359. u2 = timered(upd2, 0)
  360.  
  361. function love.update()
  362.     u1()
  363.     u2()
  364. end
  365.  
  366. local t = {
  367.   parts = 1,
  368.     flags = 1,
  369.     ip = 1,
  370.     port = 1,
  371.     hash = 1,
  372. --  ftimer = 1,
  373. --  id = 1,
  374.     window = 1,
  375.     destroy = 1,
  376. --  data = 1,
  377.     udp = 1,
  378.     update = 1,
  379. }
  380.  
  381. if os.getenv('COMPUTERNAME') == 'FINN' then
  382.     ch1:send('Data: ['..randstr(12565)..']', '192.168.1.3', 5555)
  383. --  ch1:send('Data: ['..randstr(12565000)..']', '192.168.1.3', 5555)
  384. --  ch1:send('Data: ['..randstr(12565000)..']', '192.168.1.3', 5555)
  385. end
  386.  
  387. function love.draw()
  388.     if love.keyboard.isDown('1') then
  389.         ch1:send('Data: ['..randstr(math.random(520, 650))..']', '127.0.0.1', 5555)
  390.     end
  391.     love.graphics.print(tableprinter(ch1.spool, t))
  392.     love.graphics.print(tableprinter(ch2.rpool, t), 500)
  393.     local a, b = 0, 0
  394.     for _ in pairs(ch1.spool) do a = a + 1 end
  395.     for _ in pairs(ch2.rpool) do b = b + 1 end
  396.     love.window.setTitle(a..' :: '..b)
  397.     if love.keyboard.isDown('space') then debug.debug() end
  398. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement