美文网首页Luacocos2dx
0801 - luasocket 在 cocos2d-lua

0801 - luasocket 在 cocos2d-lua

作者: 自由快挂 | 来源:发表于2017-08-01 17:58 被阅读53次

    基于 SocketTCP

    pb + luasocket + 收发缓存

    原版的 quick 里面带了一个 socketTCP 的 luasocket 封装,但是并没有处理网络粘包和少包等情况。我们在这个基础上扩展一个带收发缓存数据,数据格式是 pb 工具。

    local scheduler = require ("cocos.framework.scheduler")
    local tcp = require 'cocos.framework.net.SocketTCP'
    
    local headerSize = 2
    
    local NetMgr = class("NetMgr", tcp)
    
    function NetMgr:ctor()
        NetMgr.super.ctor(self)
    
        self.recvBuffer = ''
        self.process_id = nil
        self.send_task_list = {}
    
        self:on(tcp.EVENT_CLOSE, handler(self, self.stop))
        self:on(tcp.EVENT_CLOSED, handler(self, self.stop))
        self:on(tcp.EVENT_CONNECTED, function (  )
            print('connected')
            self.process_id = scheduler.scheduleGlobal(function ( dt )
                self:processSocketIO()
            end, 0.1)
        end)
        self:on(tcp.EVENT_DATA, function ( data )
            self.recvBuffer = self.recvBuffer .. data.data
        end)
    end
    
    function NetMgr:getInstance()
        if not self.instance_ then
            self.instance_ = NetMgr:new()
        end
        return self.instance_
    end
    
    function NetMgr:stop()
        print('> socket close')
        if self.process_id then
            scheduler:unscheduleScriptEntry(self.process_id)
        end
    end
    
    function NetMgr:processSocketIO()
        if not self.isConnected then
            return
        end
        self:processInput()
        self:processOutput()
    end
    
    function NetMgr:processInput()
        while true do
            local len = string.len(self.recvBuffer)
    
            if len == 0 then
                return
            end
    
            if len < headerSize then
                print('header not full')
                return
            end
    
            --计算包的长度
            local first, sencond = string.byte(self.recvBuffer, 1, 2)
            local bodySize = first * 256 + sencond --通过位计算长度
            print("收到数据长度 = ",bodySize)
    
            if string.len(self.recvBuffer) < headerSize + bodySize then
                print('body not full')
                return
            end
    
            --解析包
            local data = string.sub(self.recvBuffer, 1, headerSize + bodySize)
            local ret, len, pb_head, pb_body, char_data = string.unpack(data, ">HPPb")
            local msg_head = protobuf.decode("PbHead.MsgHead", pb_head)
            local msg_body = protobuf.decode(msg_head.msgname, pb_body)
            print("收到服务器数据", msg_head.msgname)
    
            dump(msg_head)
            dump(msg_body)
    
            self.recvBuffer = string.sub(self.recvBuffer, headerSize + bodySize + 1) -- 更新缓存
            self:dispatchEvent({name = msg_head.msgname, data = msg_body}) -- 把事件和数据抛出去
        end
    end
    
    function NetMgr:processOutput()
        if self.send_task_list  and #self.send_task_list > 0 then
            local data = self.send_task_list[#self.send_task_list]
            if data then
                local _len ,_error = self:send(data)
                -- print("socket send"..#data, "_len:", _len, "error:", _error)
                --发送长度不为空,并且发送长度==数据长度
                if _len ~= nil and _len == #data then
                    table.remove(self.send_task_list, #self.send_task_list)
                else
    
                end
            end
        end
    end
    
    function NetMgr:sendPB(msg_name, msg_body)
        --拼装头
        local msg_head={msgtype = 1, msgname = msg_name, msgret = 0}
        local pb_head = protobuf.encode("PbHead.MsgHead", msg_head)
        local pb_body = protobuf.encode(msg_name, msg_body)
        --计算长度
        local pb_head_len = #pb_head
        local pb_body_len = #pb_body
        local pb_len = 2 + pb_head_len + 2 + pb_body_len + 1
    
        local data = string.pack(">HPPb",pb_len, pb_head, pb_body, string.byte('t'))
        print("GameNet send msg:"..msg_name..":"..string.char(string.byte('t')))
    
        table.insert(self.send_task_list, 1, data)
    end
    
    return NetMgr
    

    测试

    luvit 的一个 tcp-echo 服务器

    --[[
    -- luvit file.lua
    --]]
    local net = require('net')
    
    local server = net.createServer(function(client)
      print("Client connected")
    
      -- Add some listenners for incoming connection
      client:on("error",function(err)
        print("Client read error: " .. err)
        client:close()
      end)
    
      client:on("data",function(data)
        print(data)
        client:write(data)
        client:write(data)
      end)
    
      client:on("end",function()
        print("Client disconnected")
      end)
    end)
    
    -- Add error listenner for server
    server:on('error',function(err)
      if err then error(err) end
    end)
    
    server:listen(1234)
    

    打包变量类型定义

        #define OP_ZSTRING  'z'     //空字符串
        #define OP_BSTRING  'p'     //长度小于2^8的字符串
        #define OP_WSTRING  'P'     //长度小于2^16的字符串
        #define OP_SSTRING  'a'     //长度小于2^32/64的字符串*/
        #define OP_STRING   'A'     //指定长度字符串
        #define OP_FLOAT    'f'     /* float */
        #define OP_DOUBLE   'd'     /* double */
        #define OP_NUMBER   'n'     /* Lua number */
        #define OP_CHAR     'c'     /* char */
        #define OP_BYTE     'b'     /* byte = unsigned char */
        #define OP_SHORT    'h'     /* short */
        #define OP_USHORT   'H'     /* unsigned short */
        #define OP_INT      'i'     /* int */
        #define OP_UINT     'I'     /* unsigned int */
        #define OP_LONG     'l'     /* long */
        #define OP_ULONG    'L'     /* unsigned long */
    

    打包字节序,分为以下3种

    #define OP_LITTLEENDIAN '<' /* little endian */
    #define OP_BIGENDIAN '>' /* big endian */ 
    #define OP_NATIVE '=' /* native endian */
    

    参考链接

    1. http://blog.leanote.com/post/qq-games/cocos2dx
    2. https://github.com/gameloses/cocos2dx_lua_skynet_client

    相关文章

      网友评论

        本文标题:0801 - luasocket 在 cocos2d-lua

        本文链接:https://www.haomeiwen.com/subject/ryxslxtx.html