socket 用的是luasocket 解包数据用的是lpack
cocos3.15.1默认没有集成lpack,要使用的同学请先集成
协议定义的包头长度是12
包头包括ver,bodySize,cmd
依次是版本号,报文大小,命令号
本框架大多思路来自http://blog.csdn.net/eastcowboy/article/details/33334283
好了,以下是框架核心对象SubPack(分包器)
--
-- Author: xiaowa
-- Date: 2017-07-20 01:53:55
--
local socket = require("socket")
require("pack")
VER = 1 --客户端当前版本
local headerSize = 12 --定义包头长
local SubPack = SubPack or class("SubPack")
function SubPack:ctor(address,port,out_fun,close_fun)
local sock = socket.tcp()
sock:settimeout(0)
self.sock = sock
self.out_fun = out_fun --超时函数
self.close_fun = close_fun --断开函数
self.recvBuffer = ''
self.sendBuffer = ''
self.sendIndex = 1
self.isConnecting = false
self.isConnected = false
--self.continue_nil = 0 --服务端连续发空数据的次数
if sock:connect(address,port) == 1 then
print('socket connected')
else
self.isConnecting = true
self.connectTime = socket.gettime()
end
self.schedule_ = app.scheduler.scheduleGlobal(handler(self,self.ticks),1/60)
end
function SubPack:ticks()
if self.isConnecting and socket.gettime() - self.connectTime > 10 then
-- 连接超时,关闭socket并清理所有变量。
-- 我还没有发现如何通过luasocket的接口来判断连接超时,所以只好用了这个笨办法
print(" connect time out ")
app.scheduler.unscheduleGlobal(self.schedule_)
self.isConnected = false
self.isConnecting = false
self.sock = nil
self.out_fun()
return
end
local clientSocket = self.sock
local arr = {clientSocket}
local r, s, e = socket.select(arr, (self.isConnecting and arr) or nil, 0)
if r and #r >= 1 and r[1] == clientSocket then
local recvData, recvError, recvParticialData = clientSocket:receive('*a')
if recvError == 'closed' then
-- socket已经断开
print(" connect close ")
app.scheduler.unscheduleGlobal(self.schedule_)
self.isConnected = false
self.isConnecting = false
self.sock = nil
self.close_fun()
return
end
--print((recvData==nil and 'nil') or string.len(recvData),(recvParticialData==nil and 'nil') or string.len(recvParticialData))
-- 如果是大块数据,可能被拆分成多段,需要多次调用clientSocket:receive才能完成接收。
-- 因此可以把接收到数据先放到recvBuffer缓存起来。
if (recvData==nil or string.len(recvData)==0) and (recvParticialData==nil or string.len(recvParticialData)==0) then
print(" connect close ")
app.scheduler.unscheduleGlobal(self.schedule_)
self.isConnected = false
self.isConnecting = false
self.sock:close()
self.sock = nil
self.close_fun()
return
elseif recvData then
self.recvBuffer = self.recvBuffer .. recvData
elseif recvParticialData then
self.recvBuffer = self.recvBuffer .. recvParticialData
end
-- 处理缓存起来的数据。
self:processRecvBuffer()
end
if s and #s >= 1