zoukankan      html  css  js  c++  java
  • Skynet入门范例之sproto

    examples同一级目录新建目录myexample,该目录下面新建以下几个文件:

    config,内容:

     

    root = "./"
    luaservice = root.."service/?.lua;"..root.."myexample/?.lua"
    lualoader = root .. "lualib/loader.lua"
    lua_path = root.."lualib/?.lua;"..root.."lualib/?/init.lua;"..root.."myexample/?.lua"
    lua_cpath = root .. "luaclib/?.so"
    snax = root.."myexample/?.lua;"..root.."test/?.lua"

    -- preload = "./examples/preload.lua"    -- run preload.lua before every lua service run
    thread = 8
    logger = nil
    logpath = "."
    harbor = 1
    address = "127.0.0.1:2526"
    master = "127.0.0.1:2013"
    start = "main"    -- main script
    bootstrap = "snlua bootstrap"    -- The service for bootstrap
    standalone = "0.0.0.0:2013"
    -- snax_interface_g = "snax_g"
    cpath = root.."cservice/?.so"
    -- daemon = "./skynet.pid"


    proto.lua
    ,定义通信协议,代码:

    local sprotoparser = require "sprotoparser"

    local proto = {}

    proto.c2s = sprotoparser.parse [[
    .package {
        type 0 : integer
        session 1 : integer
    }

    handshake 1 {
        response {
            msg 0 : string
        }
    }

    say 2 {
        request {
            name 0 : string
            msg 1 : string
        }
    }

    quit 3 {}

    ]]

    proto.s2c = sprotoparser.parse [[
    .package {
        type 0 : integer
        session 1 : integer
    }

    heartbeat 1 {}
    ]]

    return proto

    main.lua,启动服务的主程序,内容如下:

    local skynet = require "skynet"

    --
    启动服务
    (启动函数)
    skynet.start(function()
    --
    启动函数里调用Skynet API开发各种服务
    print("======Server start=======")
    -- skynet.newservice(name, ...)
    启动一个新的 Lua 服务(服务脚本文件名)
    --[[ skynet.newservice("service1")
        local svr2 = skynet.newservice("service2");
        skynet.call(svr2, "lua", "set", "key1", "val1111111");
        
        local kv = skynet.call(svr2, "lua", "get", "key1");
        print(kv);
    --]]
        skynet.newservice("socket1");

    --
    退出当前的服务
    -- skynet.exit
    之后的代码都不会被运行。而且,当前服务被阻塞住的 coroutine 也会立刻中断退出。
    skynet.exit()
    end)

    socket1.lua,接收socket消息的lua服务,内容如下:

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

    local proto = require "proto"
    local sproto = require "sproto"

    local host

    local REQUEST = {}

    function REQUEST:say()
        print("say", self.name, self.msg)
    end

    function REQUEST:handshake()
        print("handshake")
    end

    function REQUEST:quit()
        print("quit")
    end

    local function request(name, args, response)
        local f = assert(REQUEST[name])
        local r = f(args)
        if response then
            --
    生成回应包
    (response是一个用于生成回应包的函数。)
            --
    处理session对应问题
            -- return response(r)
        end
    end

    local function send_package(fd,pack)
        --
    协议与客户端对应(两字节长度包头+内容)
        local package = string.pack(">s2", pack)
        socket.write(fd, package)
    end

    local function accept(id)
        --
    每当 accept 函数获得一个新的 socket id 后,并不会立即收到这个 socket 上的数据。这是因为,我们有时会希望把这个 socket 的操作权转让给别的服务去处理。
        --
    任何一个服务只有在调用 socket.start(id) 之后,才可以收到这个 socket 上的数据。

        socket.start(id)

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

        while true do
            local str = socket.read(id)
            if str then
                local type,str2,str3,str4 = host:dispatch(str)

                if type=="REQUEST" then
                    -- REQUEST :
    第一个返回值为 "REQUEST" 时,表示这是一个远程请求。如果请求包中没有 session 字段,表示该请求不需要回应。这时,第 2 和第 3 个返回值分别为消息类型名(即在 sproto 定义中提到的某个以 . 开头的类型名),以及消息内容(通常是一个 table );如果请求包中有 session 字段,那么还会有第 4 个返回值:一个用于生成回应包的函数。
                    local ok, result = pcall(request, str2,str3,str4)

                    if ok then
                        if result then
                            socket.write(id, "
    收到了
    ")
                            --
    暂时不使用回应包回应

                            -- print("response:"..result)
                            -- send_package(id,result)
                        end
                    else
                        skynet.error(result)
                    end
                end

                if type=="RESPONSE" then
                    -- RESPONSE
    :第一个返回值为 "RESPONSE" 时,第 2 3 个返回值分别为 session 和消息内容。消息内容通常是一个 table ,但也可能不存在内容(仅仅是一个回应确认)。
                    --
    暂时不处理客户端的回应
                    print("client response")
                end        

            else
                socket.close(id)
                return
            end
        end
    end

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

        socket.start(id , function(id, addr)
                --
    接收到客户端连接或发送消息()
                print("connect from " .. addr .. " " .. id)

                --
    处理接收到的消息
                accept(id)
            end)
        --
    可以为自己注册一个别名。(别名必须在 32 个字符以内)
        skynet.register "SOCKET1"
    end)

    client1.lua,客户端测试类,内容如下:

    package.cpath = "luaclib/?.so"
    package.path = "lualib/?.lua;myexample/?.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_request(name, args)
        session = session + 1
        local str = request(name, args, session)

        --
    解包测试
        -- local host2 = sproto.new(proto.c2s):host "package"
        -- local type,str2 = host2:dispatch(str)
        -- print(type)
        -- print(str2)

        socket.send(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

     

  • 相关阅读:
    Sliverlight之 矢量绘图
    Silverlight之 xaml布局
    七天学会ASP.NET MVC(七)——创建单页应用
    MVC视图之间调用方法总结
    C#取得程序的根目录以及判断文件是否存在
    七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL
    [C#] .NET4.0中使用4.5中的 async/await 功能实现异步
    C#中StreamReader读取中文文本出现乱码的解决方法
    七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理
    常用正则表达式
  • 原文地址:https://www.cnblogs.com/skiing886/p/7694813.html
Copyright © 2011-2022 走看看