Skip to content

Instantly share code, notes, and snippets.

@rangercyh
Forked from fireyang/onlytcp.lua
Last active August 29, 2015 14:13
Show Gist options
  • Save rangercyh/8ec79c81eb67de77a9c3 to your computer and use it in GitHub Desktop.
Save rangercyh/8ec79c81eb67de77a9c3 to your computer and use it in GitHub Desktop.
--[[
onlytcp lua客户端
因为发现luasocket receive(number)方式的一个奇惨问题 所以收数据改成了按行读取
]]
CONST_Socket_TickTime = 0.1--SOCKET接收信息轮训时间
CONST_Socket_ReconnectTime = 5--socket重连偿试时间时隔
CONST_HeartBeaT_TimeOut = 20--socket心跳超时时间
CONST_HeartBeaT_SendTime = 15--socket心跳发送间隔
CONST_HeartBeaT_CheckTime = 25--socket心跳检查时间
packType_heartbeat = 1--心跳
packType_message = 2--信息包
packType_welcome = 3--心跳
local ONLYSocket = class("ONLYSocket")
local scheduler = require("framework.client.scheduler")
local socket = require "socket"
function ONLYSocket:ctor(host, port)
self.host = nil
self.port = nil
self.tickScheduler = nil--socket 消息接收定时器
self.timeCheckScheduler = nil-- 心跳动超时检测定时器
self.heartbeatScheduler = nil-- 心跳包定时发送定时器
self.reconnectScheduler = nil-- 重连定时器
self.connectTimeTickScheduler = nil--检测连接超时定时器
self.lastHeartbeatTime = os.time()
self.name = 'NTChatClient'
self.tcp = nil
self.isRetryConnect = true
self.isConnected = false
self.delegate = nil
end
--设置委托对像
function ONLYSocket:setDelegate (delegate)
self.delegate = delegate
end
function ONLYSocket:setName( name )
self.name = name
end
function ONLYSocket:connect(host, port)
if host then self.host = host end
if port then self.port = port end
self.tcp = socket.tcp()
self.tcp:settimeout(0)
local response, status, partial = self.tcp:connect(self.host, self.port)
--print("response", response);
--print("status", status);
--print("partial", partial);
--检测连接超时
--两秒后如果未连接视为连接失败
local connectTimeTick = function ()
print(self.name, "connectTimeTick")
if not self.isConnected then
self:doClose()
self:onConnectFailure()
end
end
self.connectTimeTickScheduler = scheduler.performWithDelayGlobal(connectTimeTick, 3)
local tick = function()
while true do
local body, status, partial = self.tcp:receive("*l")--读取包体
if status == "closed" or status == "Socket is not connected" then --如果读取失败 则跳出
self:doClose()
if self.isConnected then
self:onDisconnect()
else
self:onConnectFailure()
end
return
end
if not body then return end
local packArr = string.split(body, "::")
local packType = tonumber(packArr[1]);
local clientEvent = tonumber(packArr[2]);
local message = packArr[3]
self:onPacket(packType, clientEvent, message)
end
end
--开始读取TCP数据
self.tickScheduler = scheduler.scheduleGlobal(tick, CONST_Socket_TickTime)
end
function ONLYSocket:doClose( ... )
--print(self.name, "ONLYSocket:doClose")
self.tcp:close();
if self.connectTimeTickScheduler then scheduler.unscheduleGlobal(self.connectTimeTickScheduler) end
if self.tickScheduler then scheduler.unscheduleGlobal(self.tickScheduler) end
if self.heartbeatScheduler then scheduler.unscheduleGlobal(self.heartbeatScheduler) end
if self.timeCheckScheduler then scheduler.unscheduleGlobal(self.timeCheckScheduler) end
end
--protocal
function ONLYSocket:onDisconnect()
print(self.name, "onDisconnect");
self.isConnected = false
self:_reconnect();
self.delegate:onDisconnect();
end
--成功建立连接
function ONLYSocket:onConnected()
print(self.name, "ONLYSocket:onConnected")
self.isConnected = true
local _sendHeartbeat = function ()
self:sendStr(packType_heartbeat, 0, '{}')
end
local _checkHeartBeat = function ()
print(self.name, "_checkHeartBeat", self.lastHeartbeatTime)
if os.time() - self.lastHeartbeatTime > CONST_HeartBeaT_TimeOut then
print(self.name, "心跳超时")
self:_disconnect()
end
end
self.heartbeatScheduler = scheduler.scheduleGlobal(_sendHeartbeat, CONST_HeartBeaT_SendTime, false)
self.timeCheckScheduler = scheduler.scheduleGlobal(_checkHeartBeat, CONST_HeartBeaT_CheckTime, false)
self.delegate:onConnected();
end
--连接失败
function ONLYSocket:onConnectFailure(status)
--print(self.name, "ONLYSocket:onConnectFailure");
self:_reconnect();
end
--收到服务端数据
function ONLYSocket:onPacket(packType, clientEvent, message)
print(self.name, "onPacket", packType, clientEvent, message, os.time())
self.lastHeartbeatTime = os.time()
if packType == packType_heartbeat then --收到心跳包
elseif packType == packType_welcome then
self:onConnected()
else--收到数据包
local data = JSON.decode(message);
self.delegate.onMessage(clientEvent, data);
end
end
--method
--断开连接 内部方法
function ONLYSocket:_disconnect()
self.isConnected = false
self.tcp:shutdown()
end
--用户主动退出
function ONLYSocket:disconnect()
self:_disconnect()
self.isRetryConnect = false--主动性断开不重连
end
--重连
-- 非主动性断开3秒后重连
--主动性断开不重连
function ONLYSocket:_reconnect()
--print(self.name, "_reconnect")
if not self.isRetryConnect then return end--不允许重连
if self.reconnectScheduler then scheduler.unscheduleGlobal(self.reconnectScheduler) end
local _doReConnect = function ()
self:connect()
end
self.reconnectScheduler = scheduler.performWithDelayGlobal(_doReConnect, CONST_Socket_ReconnectTime)
end
--do send jsonstr
function ONLYSocket:sendStr(packType, serverEvent, jsonStr)
if self.isConnected == false then return end
local _sendStr = packType.."::"..serverEvent.."::"..jsonStr..'\n'
if packType > 1 then print('sendStr:', _sendStr) end
--防止socket中断了还发消息造成crash
local pool = { self.tcp }
-- rx, wr, er = socket.select( nil, pool, 0.001 )
-- if (er ~= nil) then return end;
-- for n, sck in ipairs( wr ) do
self.tcp:send(_sendStr)
-- end
end
--do send table
function ONLYSocket:send(packType, serverEvent, data)
self:sendStr(packType, serverEvent, JSON.encode(data))
end
--触发服务端事件
function ONLYSocket:doEmit( serverEvent, data )
self:sendStr(packType_message, serverEvent, JSON.encode(data))
end
return ONLYSocket
--CCDirector:sharedDirector():getScheduler():scheduleScriptFunc(test, 5, false)--10秒后退出
--testObj:connect('192,168.2.125', '7979')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment