gateserver 用於管理網絡連接,也可以讀取網絡數據,但它並沒有提供發送網絡數據相關的寫功能,而涉及請求處理與響應一般交給 agent 服務(agent 服務可以由一個普通服務來充當)。
一、agent 服務
myagent.lua
local skynet = require "skynet"
local netpack = require "skynet.netpack"
local socket = require "skynet.socket"
local client_fd = ...
client_fd = tonumber(client_fd)
skynet.register_protocol {
name = "client",
id = skynet.PTYPE_CLIENT,
--需要將網路數據轉換成lua字符串,不需要打包,所以不用註冊pack函數
unpack = netpack.tostring,
}
local function task(msg)
print("recv from fd", client_fd, msg)
--響應消息的時候直接通過fd發送出去
socket.write(client_fd, netpack.pack(string.upper(msg)))
end
skynet.start(function()
--註冊client消息專門用來接收網絡數據
skynet.dispatch("client", function(_,_, msg)
task(msg)
end)
--註冊lua消息,來退出服務
skynet.dispatch("lua", function(_,_, cmd, ...)
if cmd == "quit" then
skynet.error(client_fd, "agent quit")
--skynet.exit()
end
end)
end)
二、網關服務
修改上一篇文章中的 mygateserver.lua,爲每一個客戶端連接創建一個 agent 服務,並把fd、從客戶端收到數據就轉發給agent服務,同時與客戶端的其他交流工作都通過agent來解決。
mygateserver.lua
local skynet = require "skynet"
local gateserver = require "snax.gateserver"
local netpack = require "skynet.netpack"
local handler = {}
local agents = {}
function handler.connect(fd, ipaddr)
skynet.error("ipaddr:",ipaddr,"fd:",fd,"connect")
gateserver.openclient(fd)
--連接成功就啓動一個agent來代理
local agent = skynet.newservice("myservice/myagent", fd)
agents[fd] = agent
end
--斷開連接後,agent服務退出
function handler.disconnect(fd)
skynet.error("fd:", fd, "disconnect")
--通過發送消息的方式來退出不要使用skynet.kill(agent)
local agent = agents[fd]
if(agent) then
skynet.send(agent, "lua", "quit")
agents[fd] = nil
end
end
function handler.message(fd, msg, sz)
--skynet.error("recv message from fd:", fd)
--skynet.error(netpack.tostring(msg, sz))
--收到消息就轉發給agent
local agent = agents[fd]
skynet.redirect(agent, 0, "client", 0, msg, sz)
end
function handler.error(fd, msg)
gateserver.closeclient(fd)
end
function handler.warning(fd, size)
skynet.skynet("warning fd=", fd , "unsent data over 1M")
end
function handler.open(source, conf)
skynet.error("open by ", skynet.address(source))
skynet.error("listen on", conf.port)
skynet.error("client max", conf.maxclient)
skynet.error("nodelay", conf.nodelay)
end
local CMD = {}
function CMD.kick(source, fd)
skynet.error("source:", skynet.address(source), "kick fd:", fd)
gateserver.closeclient(fd)
end
function handler.command(cmd, source, ...)
local f = assert(CMD[cmd])
return f(source, ...)
end
--註冊client消息專門用來將接收到的網絡數據轉發給agent,不需要解包,也不需要打包
skynet.register_protocol {
name = "client",
id = skynet.PTYPE_CLIENT,
}
gateserver.start(handler)
三、測試
先啓動 mygateserver,然後啓動客戶端 socketclient,然後在 socketclient 所在的控制檯輸入“hello world!!!”: