Skip to content

Commit 681b1e4

Browse files
committed
initial commit
0 parents  commit 681b1e4

7 files changed

Lines changed: 896 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.swp

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A lua library by zengrong.net
2+
3+
This library depend on [quick-cocos2d-x framework][1] .
4+
5+
[1]: https://github.com/dualface/quick-cocos2d-x/tree/develop/framework

src/net/PacketBuffer.lua

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
--[[
2+
PacketBuffer receive the byte stream and analyze them, then pack them into a message packet.
3+
The method name, message metedata and message body will be splited, and return to invoker.
4+
@see https://github.com/zrong/as3/blob/master/src/org/zengrong/net/PacketBuffer.as
5+
@author zrong(zengrong.net)
6+
Creation: 2013-11-14
7+
]]
8+
9+
local PacketBuffer = class("PacketBuffer")
10+
local Protocol = require("Protocol")
11+
local ByteArrayVarint = require("utils.ByteArrayVarint")
12+
require("bit")
13+
14+
PacketBuffer.ENDIAN = ByteArrayVarint.ENDIAN_LITTLE
15+
16+
PacketBuffer.MASK1 = 0x59
17+
PacketBuffer.MASK2 = 0x7a
18+
PacketBuffer.RANDOM_MAX = 10000
19+
PacketBuffer.PACKET_MAX_LEN = 2100000000
20+
21+
PacketBuffer.FLAG_LEN = 2 -- package flag at start, 1byte per flag
22+
PacketBuffer.TYPE_LEN = 1 -- type of message, 1byte
23+
PacketBuffer.BODY_LEN = 4 -- length of message body, int
24+
PacketBuffer.METHOD_LEN = 2 -- length of message method code, short
25+
PacketBuffer.VER_LEN = 1 -- version of message, byte
26+
PacketBuffer.META_NUM_LEN = 1 -- how much item in a message, 1byte
27+
28+
local DATA_TYPE =
29+
{
30+
R = 0,
31+
S = 1,
32+
r = 2,
33+
t = 3
34+
}
35+
36+
local DATA_TYPE_UVINT = 0 -- how much item in a message, 1byte
37+
local DATA_TYPE_STRING = 1 -- how much item in a message, 1byte
38+
local DATA_TYPE_VINT = 2 -- how much item in a message, 1byte
39+
local DATA_TYPE_LIST = 3 -- how much item in a message, 1byte
40+
41+
function PacketBuffer.getBaseBA()
42+
return ByteArrayVarint.new(PacketBuffer.ENDIAN)
43+
end
44+
45+
function PacketBuffer:ctor()
46+
self._buf = self.getBaseBA()
47+
end
48+
49+
--- Create a formated packet that to send server
50+
-- @param __msgDef the define of message, a table
51+
-- @param __msgBodyTable the message body with key&value, a table
52+
function PacketBuffer:createPackets(__msgDef, __msgBodyTable)
53+
if self._buf:getLen()>0 then self._buf = self.getBaseBA() end
54+
-- write 2 flags and message type, for clent, is always 0
55+
self._buf:rawPack("b3ihb",
56+
PacketBuffer.MASK1,
57+
PacketBuffer.MASK2,
58+
0,
59+
__LEN__,
60+
__METHOD_CODE__,
61+
0,
62+
unpack()
63+
)
64+
end
65+
66+
--- metadata item description
67+
function PacketBuffer:_getMetaDes(__metaTable)
68+
local __fmt = nil
69+
local __byteTable = {}
70+
for i=1,#__metaTable do
71+
__fmt = __metaTable[i]
72+
-- create a metadata description: data number(7~3bit) + data type(0~1bit)
73+
__byteTable[i] = bit.bor(bit.lshift(i-1, 3), DATA_TYPE[__fmt])
74+
end
75+
return __byteTable
76+
end
77+
78+
function PacketBuffer:_getBody()
79+
end
80+
81+
function PacketBuffer:_writeMeta()
82+
end
83+
84+
function PacketBuffer:_writeBody()
85+
end
86+
87+
88+
--- Get a byte stream and analyze it, return a splited table
89+
-- Generally, the table include a message, but if it receive 2 packets meanwhile, then it includs 2 messages.
90+
function PacketBuffer:parsePackets(__byteString)
91+
local __msgs = {}
92+
local __pos = 0
93+
self._buf:setPos(self._buf:getLen()+1)
94+
self._buf:writeBuf(__byteString)
95+
self._buf:setPos(1)
96+
local __flag1 = nil
97+
local __flag2 = nil
98+
printf("start analyzing... buffer len: %u", self._buf:getLen())
99+
while self._buf:getAvailable() do
100+
end
101+
end
102+
103+
return PacketBuffer

src/net/SocketTcp.lua

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
--[[
2+
SocketTcp lua客户端
3+
@author zrong (zengrong.net)
4+
Creation: 2013-11-12
5+
修改自: http://cn.quick-x.com/?topic=quickkydsocketfzl
6+
因为发现luasocket receive(number)方式的一个奇惨问题 所以收数据改成了按行读取
7+
]]
8+
local SOCKET_TICK_TIME = 0.1 --SOCKET接收信息轮询时间
9+
local SOCKET_RECONNECT_TIME = 5 --socket重连偿试时间时隔
10+
local SOCKET_CONNECT_FAIL_TIMEOUT = 3 --多长时间没有连接成功视为失败
11+
12+
local STATUS_CLOSED = "closed"
13+
local STATUS_NOT_CONNECTED = "Socket is not connected"
14+
local STATUS_TIMEOUT = "timeout"
15+
16+
local scheduler = require("framework.scheduler")
17+
local socket = require "socket"
18+
19+
local SocketTcp = class("SocketTcp")
20+
21+
SocketTcp.EVENT_DATA = "SOCKET_TCP_DATA"
22+
SocketTcp.EVENT_CLOSE = "SOCKET_TCP_CLOSE"
23+
SocketTcp.EVENT_CLOSED = "SOCKET_TCP_CLOSED"
24+
SocketTcp.EVENT_CONNECTED = "SOCKET_TCP_CONNECTED"
25+
SocketTcp.EVENT_CONNECT_FAILURE = "SOCKET_TCP_CONNECT_FAILURE"
26+
27+
SocketTcp._VERSION = socket._VERSION
28+
SocketTcp._DEBUG = socket._DEBUG
29+
30+
require("framework.api.EventProtocol").extend(SocketTcp)
31+
32+
function SocketTcp:ctor(__host, __port, __retryConnectWhenFailure)
33+
self.host = __host
34+
self.port = __port
35+
self.tickScheduler = nil -- 消息接收定时器
36+
self.reconnectScheduler = nil -- 重连定时器
37+
self.connectTimeTickScheduler = nil -- 检测连接超时定时器
38+
self.lastHeartbeatTime = os.time()
39+
self.name = 'SocketTcp'
40+
self.tcp = nil
41+
self.isRetryConnect = __retryConnectWhenFailure
42+
self.isConnected = false
43+
end
44+
45+
function SocketTcp:setName( name )
46+
self.name = name
47+
end
48+
49+
function SocketTcp:getTime()
50+
return socket.gettime()
51+
end
52+
53+
function SocketTcp:connect(__host, __port, __retryConnectWhenFailure)
54+
if __host then self.host = __host end
55+
if __port then self.port = __port end
56+
if __retryConnectWhenFailure ~= nil then self.isRetryConnect = __retryConnectWhenFailure end
57+
assert(self.host or self.port, "Host and port are necessary!")
58+
--echoInfo("%s.connect(%s, %d)", self.name, self.host, self.port)
59+
self.tcp = socket.tcp()
60+
self.tcp:settimeout(0)
61+
62+
self.tcp:connect(self.host, self.port)
63+
-- 检测连接是否成功
64+
-- SOCKET_CONNECT_FAIL_TIMEOUT 后如果未连接视为连接失败
65+
local __connectTimeTick = function ()
66+
--echoInfo("%s.connectTimeTick", self.name)
67+
if self.isConnected then return end
68+
self.waitConnect = self.waitConnect or 0
69+
self.waitConnect = self.waitConnect + SOCKET_TICK_TIME
70+
if self.waitConnect >= SOCKET_CONNECT_FAIL_TIMEOUT then
71+
self.waitConnect = nil
72+
self:close()
73+
self:_connectFailure()
74+
end
75+
-- 每 SOCKET_TICK_TIME 发送一个值到服务器,发送成功说明服务器连接成功
76+
-- 不能采用此种方式,因为服务器会缓存这个1,加到下一次发送的协议的前面,导致下一次发送正常协议就会不返回
77+
-- local __succ, __status = self.tcp:send(1)
78+
-- 改为采用接收包体
79+
local __body, __status, __partial = self.tcp:receive("*l")
80+
--print("receive:", __body, __status, string.len(__partial))
81+
if __status == STATUS_TIMEOUT then
82+
self:_onConnected()
83+
end
84+
end
85+
self.connectTimeTickScheduler = scheduler.scheduleGlobal(__connectTimeTick, SOCKET_TICK_TIME)
86+
end
87+
88+
-- 直接调用socket的原始发送功能
89+
function SocketTcp:send(__data)
90+
assert(self.isConnected, self.name .. " is not connected.")
91+
self.tcp:send(__data)
92+
end
93+
94+
function SocketTcp:close( ... )
95+
--echoInfo("%s.close", self.name)
96+
self.tcp:close();
97+
if self.connectTimeTickScheduler then scheduler.unscheduleGlobal(self.connectTimeTickScheduler) end
98+
if self.tickScheduler then scheduler.unscheduleGlobal(self.tickScheduler) end
99+
if self.connectTimeTickScheduler then scheduler.unscheduleGlobal(self.connectTimeTickScheduler) end
100+
self:dispatchEvent({name=SocketTcp.EVENT_CLOSE})
101+
end
102+
103+
--用户主动退出
104+
function SocketTcp:disconnect()
105+
self:_disconnect()
106+
self.isRetryConnect = false --主动性断开不重连
107+
end
108+
109+
--------------------
110+
-- private
111+
--------------------
112+
113+
function SocketTcp:_disconnect()
114+
self.isConnected = false
115+
self.tcp:shutdown()
116+
self:dispatchEvent({name=SocketTcp.EVENT_CLOSED})
117+
end
118+
119+
function SocketTcp:_onDisconnect()
120+
--echoInfo("%s._onDisConnect", self.name);
121+
self.isConnected = false
122+
self:dispatchEvent({name=SocketTcp.EVENT_CLOSED})
123+
self:_reconnect();
124+
end
125+
126+
-- 成功建立连接,取消超时计时器
127+
function SocketTcp:_onConnected()
128+
--echoInfo("%s._onConnectd", self.name)
129+
self.isConnected = true
130+
self:dispatchEvent({name=SocketTcp.EVENT_CONNECTED})
131+
if self.connectTimeTickScheduler then scheduler.unscheduleGlobal(self.connectTimeTickScheduler) end
132+
133+
local __tick = function()
134+
while true do
135+
local __body, __status, __partial = self.tcp:receive("*l")--读取包体
136+
--print("body:", __body, "__status:", __status, "__partial:", __partial)
137+
if __status == STATUS_CLOSED or __status == STATUS_NOT_CONNECTED then --如果读取失败 则跳出
138+
self:close()
139+
if self.isConnected then
140+
self:_onDisconnect()
141+
else
142+
self:_connectFailure()
143+
end
144+
return
145+
end
146+
if string.len(__partial) == 0 then return end
147+
self:dispatchEvent({name=SocketTcp.EVENT_DATA, partial=__partial, body=__body})
148+
end
149+
end
150+
151+
--开始读取TCP数据
152+
self.tickScheduler = scheduler.scheduleGlobal(__tick, SOCKET_TICK_TIME)
153+
end
154+
155+
-- 连接失败
156+
function SocketTcp:_connectFailure(status)
157+
--echoInfo("%s._connectFailure", self.name);
158+
self:dispatchEvent({name=SocketTcp.EVENT_CONNECT_FAILURE})
159+
self:_reconnect();
160+
end
161+
162+
-- 重连
163+
-- 非主动性断开 SOCKET_RECONNECT_TIME 秒后重连
164+
--主动性断开不重连
165+
function SocketTcp:_reconnect()
166+
if not self.isRetryConnect then return end -- 不允许重连
167+
--echoInfo("%s._reconnect", self.name)
168+
if self.reconnectScheduler then scheduler.unscheduleGlobal(self.reconnectScheduler) end
169+
local __doReConnect = function ()
170+
self:connect()
171+
end
172+
self.reconnectScheduler = scheduler.performWithDelayGlobal(__doReConnect, SOCKET_RECONNECT_TIME)
173+
end
174+
175+
return SocketTcp

0 commit comments

Comments
 (0)