Skip to content

Commit

Permalink
add udp gate
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudwu committed Apr 16, 2015
1 parent 4d0693f commit c4f0441
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 38 deletions.
15 changes: 6 additions & 9 deletions client/main.lua
Expand Up @@ -9,6 +9,7 @@ local fd = assert(socket.login {
pass = "password",
})


fd:connect("127.0.0.1", 8888)

local function request(fd, type, obj, cb)
Expand All @@ -30,16 +31,12 @@ local function dispatch(fd)
end
end

request(fd, "ping", { what = "hello" } , function(obj)
print("1===>", obj.sleep)
end)

dispatch(fd)

request(fd, "ping", { what = "world" } , function(obj)
print("2===>", obj.sleep)
request(fd, "join", { room = 1 } , function(obj)
obj.secret = fd.secret
local udp = socket.udp(obj)
udp:send "Hello"
end)

for i=2,20 do
for i=1,20 do
dispatch(fd)
end
22 changes: 22 additions & 0 deletions client/socket.lua
Expand Up @@ -249,6 +249,7 @@ function socket.login(token)
local subid = crypt.base64decode(string.sub(result, 5))
self.__token = string.format("%s@%s#%s:", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid))
crypt.base64decode(string.sub(result, 5))
self.secret = secret
self.connect = connect_gameserver
self.request = request_gameserver
self.reconnect = reconnect_gameserver
Expand All @@ -258,4 +259,25 @@ function socket.login(token)
end
end

local function udp_send(self, data)
data = string.pack("<L", self.__session) .. data
data = crypt.hmac_hash(self.__secret, data) .. data
self.__fd:send(data)
end

local function udp_recv(self)
return self.__fd:recv()
end

function socket.udp(conf)
local fd = assert(lsocket.connect("udp", conf.host, conf.port))
return {
__fd = fd,
__secret = conf.secret,
__session = conf.session,
send = udp_send,
recv = udp_recv,
}
end

return socket
8 changes: 5 additions & 3 deletions proto/lobby.sproto
@@ -1,8 +1,10 @@
ping 1 {
join 1 {
request {
what 0 : string
room 0 : integer
}
response {
sleep 0 : integer
session 0 : integer
host 1 : string
port 2 : integer
}
}
36 changes: 26 additions & 10 deletions server/agent.lua
Expand Up @@ -3,29 +3,35 @@ local skynet = require "skynet"
local sprotoloader = require "sprotoloader"
local sproto = require "sproto"

local gate
local userid, subid
local roomkeeper
local gate, room
local U = {}
local proto

function response.login(source, uid, sid, secret)
-- you may use secret to make a encrypted data stream
roomkeeper = snax.queryservice "roomkeeper"
snax.printf("%s is login", uid)
gate = source
userid = uid
subid = sid
U.userid = uid
U.subid = sid
U.key = secret
-- you may load user data from database
end

local function logout()
if gate then
skynet.call(gate, "lua", "logout", userid, subid)
skynet.call(gate, "lua", "logout", U.userid, U.subid)
end
snax.exit()
end

function response.logout()
-- NOTICE: The logout MAY be reentry
snax.printf("%s is logout", userid)
snax.printf("%s is logout", U.userid)
if room then
room.req.leave(U.session)
end
logout()
end

Expand All @@ -45,11 +51,21 @@ local function encode_proto(name, obj)
return sproto.pack(proto:response_encode(name, obj))
end


local client_request = {}

function client_request.join(msg)
local handle, host, port = roomkeeper.req.apply(msg.room)
local r = snax.bind(handle , "room")
local session = assert(r.req.join(skynet.self(), U.key))
U.session = session
room = r
return { session = session, host = host, port = port }
end

local function dispatch_client(_,_,name,msg)
local sleep = math.random(100)
snax.printf("Recv %s, sleep %d return",msg.what, sleep)
skynet.sleep(sleep)
skynet.ret(encode_proto(name, { sleep = sleep }))
local f = assert(client_request[name])
skynet.ret(encode_proto(name, f(msg)))
end

function init()
Expand Down
4 changes: 1 addition & 3 deletions server/main.lua
Expand Up @@ -4,9 +4,7 @@ local snax = require "snax"
skynet.start(function()
skynet.newservice("console")
skynet.newservice("debug_console",8000)

-- local udp = snax.newservice("udpserver","127.0.0.1", 9999)
-- local room = snax.newservice("room", udp.handle)
snax.uniqueservice("roomkeeper")

local loginserver = skynet.newservice("logind")
local gate = skynet.newservice("gated", loginserver)
Expand Down
54 changes: 49 additions & 5 deletions server/room.lua
@@ -1,16 +1,60 @@
local skynet = require "skynet"
local snax = require "snax"

local max_number = 4
local roomid
local gate
local users = {}

function accept.update(session, data)
print("room ->", session, data)
gate.post.post(session, "pong")
function accept.update(data)
local session = string.unpack("<L", data)
print("========>", session, data)
for s,v in pairs(users) do
if s~=session then
-- forward to others in room
gate.post.post(s, data)
end
end
end

function init(udpserver)
function response.join(agent, secret)
local n = 0
for _ in pairs(users) do
n = n + 1
end
if n >= max_number then
return false -- max number of room
end
agent = snax.bind(agent, "agent")
local user = {
agent = agent,
key = secret,
session = gate.req.register(skynet.self(), secret),
}
users[user.session] = user
return user.session
end

function response.leave(session)
users[session] = nil
end

function response.query(session)
local user = users[session]
-- todo: we can do more
if user then
return user.agent.handle
end
end

function init(id, udpserver)
roomid = id
gate = snax.bind(udpserver, "udpserver")
local session = gate.req.register(skynet.self(), "XXXX")
end

function exit()
for _,user in pairs(users) do
gate.req.unregister(user.session)
end
end

22 changes: 22 additions & 0 deletions server/roomkeeper.lua
@@ -0,0 +1,22 @@
local snax = require "snax"

-- todo: we can use a gate pool
local host = "127.0.0.1"
local port = 9999
local udpgate
local rooms = {}

function response.apply(roomid)
local room = rooms[roomid]
if room == nil then
room = snax.newservice("room", roomid, udpgate.handle)
rooms[roomid] = room
end
return room.handle , host, port
end

-- todo : close room ?

function init()
udpgate = snax.newservice("udpserver",host, port)
end
54 changes: 46 additions & 8 deletions server/udpserver.lua
Expand Up @@ -6,42 +6,80 @@ local snax = require "snax"
local U
local S = {}
local SESSION = 0
local timeout = 10 * 60 * 100 -- 10 mins

--[[
8 bytes hmac crypt.hmac_hash(key, session .. data)
4 bytes session
padding data
]]

function response.register(service, key)
SESSION = SESSION + 1
SESSION = (SESSION + 1) & 0xffffffff
S[SESSION] = {
session = SESSION,
key = key,
room = snax.bind(service, "room"),
address = nil,
time = skynet.now(),
}
return SESSION
end

function response.unregister(session)
S[session] = nil
end

function accept.post(session, data)
local s = S[session]
if s and s.address then
print("Send to ", session)
socket.sendto(U, s.address, data)
else
print("post invalid ", session)
snax.printf("Session is invalid %d", session)
end
end

local function udpdispatch(str, from)
local session, index = string.unpack("<L", str)
str = str:sub(index)
local session = string.unpack("<L", str, 9)
local s = S[session]
if s then
s.address = from
s.room.post.update(session, str)
if s.address ~= from then
if crypt.hmac_hash(s.key, str:sub(9)) ~= str:sub(1,8) then
snax.printf("Invalid signature of session %d from %s", session, socket.udp_address(from))
return
end
s.address = from
end
s.time = skynet.now()
s.room.post.update(str:sub(9))
else
print("Invalid session" , session)
snax.printf("Invalid session %d from %s" , session, socket.udp_address(from))
end
end

local function keepalive()
-- trash session after no package last 10 mins (timeout)
while true do
local i = 0
local ti = skynet.now()
for session, s in pairs(S) do
i=i+1
if i > 100 then
skynet.sleep(3000) -- 30s
ti = skynet.now()
i = 1
end
if ti > s.time + timeout then
S[session] = nil
end
end
skynet.sleep(6000) -- 1 min
end
end

function init(host, port, address)
U = socket.udp(udpdispatch, host, port)
skynet.fork(keepalive)
end

function exit()
Expand Down

0 comments on commit c4f0441

Please sign in to comment.