您的位置:首页 > 其它

Skynet基础入门例子详解(7)

2017-04-07 15:50 393 查看

GateServer的使用

skynet 提供了一个通用模板 lualib/snax/gateserver.lua 来启动一个网关服务器,通过 TCP 连接和客户端交换数据。

TCP 基于数据流,但一般我们需要以带长度信息的数据包的结构来做数据交换。gateserver 做的就是这个工作,把数据流切割成包的形式转发到可以处理它的地址。

skynet 提供了一个 lua 库 netpack ,用来把 tcp 流中的数据解析成 长度 + 内容的包。

gateserver就是使用netpack进行包解析。

在同一个目录建立7个文件(config,proto.lua,main.lua,mygate.lua,socket1.lua,service1.lua,client1.lua)

本例子的client1使用前两节的client,代码稍作修改。

client1.lua代码:

package.cpath = "luaclib/?.so"
package.path = "lualib/?.lua;myexample/e5/?.lua"

if _VERSION ~= "Lua 5.3" then
error "Use lua 5.3"
end

local socket = require "clientsocket"

-- 通信协议
local proto = require "proto"
local sproto = require "sproto"

local host = sproto.new(proto.s2c):host "package"
local request = host:attach(sproto.new(proto.c2s))

local fd = assert(socket.connect("127.0.0.1", 8888))

local session = 0

-- 封包(长度+内容)
local function send_package(fd, pack)
local package = string.pack(">s2", pack)
socket.send(fd, package)
end

local function send_request(name, args)
session = session + 1
local str = request(name, args, session)

-- socket.send(fd, str)

-- 添加数据长度包头,gateserver接收自动判断类型为data(gateserver使用了netpack进行解析)
-- skynet 提供了一个 lua 库 netpack ,用来把 tcp 流中的数据解析成 长度 + 内容的包。
send_package(fd,str);

print("Request:", session)
end

send_request("handshake")
send_request("say", { name = "soul", msg = "hello world" })

while true do
-- 接收服务器返回消息
local str   = socket.recv(fd)

-- print(str)
if str~=nil and str~="" then
print("server says: "..str)
-- socket.close(fd)
-- break;
end

-- 读取用户输入消息
local readstr = socket.readstdin()

if readstr then
if readstr == "quit" then
send_request("quit")
-- socket.close(fd)
-- break;
else
-- 把用户输入消息发送给服务器
send_request("say", { name = "soul", msg = readstr })
end
else
socket.usleep(100)
end

end


socket1.lua代码:

local skynet = require "skynet"
local common = require "common"

local gate

skynet.start(function()
print("==========Socket Start=========")
print("Listen socket :", "127.0.0.1", 8888)

-- Socket服务配置
local conf = {
address = "127.0.0.1",
port = 8888,
maxclient = 1024,
nodelay = true,
}

-- common:dump(conf)
-- 启动Socket管理网关
gate=skynet.newservice("mygate")

-- 打开监听端口
skynet.call(gate, "lua", "open" , conf)

end)


mygate.lua代码:

local skynet = require "skynet"
local gateserver = require "snax.gateserver"
local netpack = require "netpack"
local common = require "common"

local connection = {}   -- fd -> connection : { fd , ip }
local handler = {}

local agentlist = {}

-- 当一个完整的包被切分好后,message 方法被调用。这里 msg 是一个 C 指针、sz 是一个数字,表示包的长度(C 指针指向的内存块的长度)。
function handler.message(fd, msg, sz)
print("===========gate handler.message============"..fd)
-- common:dump(connection[fd])

local c = connection[fd]
local agent = agentlist[fd]
if agent then
-- skynet.redirect(agent, c.client, "client", 1, msg, sz)
print("接收到客户端消息,传给agent服务处理")
else
print("没有agent处理该消息")
end
end

function handler.connect(fd, addr)
print("===========gate handler.connect============")
local c = {
fd = fd,
ip = addr,
}
-- common:dump(c)
-- 保存客户端信息
connection[fd] = c

-- 马上允许fd 接收消息(由于下面交给service1处理消息,所以可以在service1准备好再调用)
-- 这样可能导致客户端发来的消息丢失,因为service1未准备好的情况下,无法处理消息
gateserver.openclient(fd)

agentlist[fd] = skynet.newservice("service1")
skynet.call(agentlist[fd], "lua", "start", { fd = fd, addr = addr })
end

function handler.disconnect(fd)
print(fd.."-断开连接")
end

function handler.error(fd, msg)
print("异常错误")
end

gateserver.start(handler)


service1.lua代码:

local common = require "common"
local skynet = require "skynet"
require "skynet.manager"    -- import skynet.register

local CMD = {}
local client_fd
local host

-- TODO
-- skynet.register_protocol
-- 注册新的消息类别 PTYPE_CLIENT,新的类别必须提供 pack 和 unpack 函数,用于消息的编码和解码。

function CMD.start(conf)
print("service1 CMD.start")
-- common:dump(conf)
-- SOCKET处理
end

function CMD.disconnect()
-- todo: do something before exit
skynet.exit()
end

skynet.start(function()
print("==========Service1 Start=========")
skynet.dispatch("lua", function(session, address, cmd, ...)
print("==========Service1 dispatch============"..cmd)
local f = CMD[cmd]
skynet.ret(skynet.pack(f(...)))
end)
end)


项目源码:http://download.csdn.net/detail/uisoul/9806650

API参考文档:https://github.com/cloudwu/skynet/wiki/GateServer
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息