Quick-Cocos2d-x v3.3里面提供了兩種長連接WebSockets、SocketTCP,這里說一下SocketTCP的用法。
1
2
3
|
local net = require(
"framework.cc.net.init"
)
local ByteArray = require(
"framework.cc.utils.ByteArray"
)
require(
"framework.cc.utils.bit"
)
|
-- 網絡初始化,添加偵聽函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
function scnet.init( )
local
time
= net.SocketTCP.getTime()
print(
"socket time:"
..
time
)
local socket = net.SocketTCP.
new
()
socket:setName(
"HeroGameTcp"
)
socket:setTickTime(1)
socket:setReconnTime(6)
socket:setConnFailTime(4)
socket:addEventListener(net.SocketTCP.EVENT_DATA, scnet.receive)
socket:addEventListener(net.SocketTCP.EVENT_CLOSE, scnet.tcpClose)
socket:addEventListener(net.SocketTCP.EVENT_CLOSED, scnet.tcpClosed)
socket:addEventListener(net.SocketTCP.EVENT_CONNECTED, scnet.tcpConnected)
socket:addEventListener(net.SocketTCP.EVENT_CONNECT_FAILURE, scnet.error)
scnet.socket = socket
end
|
--發送數據給服務器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
function scnet.send( msgid,data )
-- encodeData 此方法是根據需要發送的數據安裝與服務器定義好的消息格式去write
local _ba = scnet.encodeData(msgid,data)
print(
"scnet.send _ba"
,_ba:getLen())
if
not _ba then
print(
"發送數據出錯了......."
,msgid)
return
end
_ba:setPos(1)
local byteList = {}
local byteCount = 0
-- 把數據讀出來,加密
for
i=1,#_ba._buf
do
local tmpBit = string.byte(_ba:readRawByte())
byteCount = byteCount + tmpBit
tmpBit = bit.band(tmpBit + 80,255)
tmpBit = bit.band(bit.bnot(bit.band(tmpBit,255)),255)
byteList<i> = tmpBit
end
byteCount = byteCount % 256
-- 最后再組成一個新的ByteArray
local result = ByteArray.
new
(ByteArray.ENDIAN_BIG)
result:writeShort(_ba:getLen() + 3)
result:writeByte(byteCount)
for
i=1,#byteList
do
result:writeByte(byteList<i>)
end
-- 把數據發送給服務器
scnet.socket:send(result:getPack())
end
|
-- 根據messageid來確定數據格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
function scnet.encodeData( msgid,data )
if
msgid then
local ba = ByteArray.
new
(ByteArray.ENDIAN_BIG)
local fmt = InfoUtil:getMsgFmt(msgid) -- 此處為讀取消息格式 看下面的MessageType里面會有定義
ba:writeStringUShort(
"token"
) -- 此處為用戶token,沒有就為
""
,此處可以判斷用戶是否重新登陸啊等等.......
for
i=1,#fmt
do
scnet.writeData(ba,fmt<i>,data)
end
local baLength = ba:getLen()
local bt = ByteArray.
new
(ByteArray.ENDIAN_BIG)
bt:writeShort(baLength + 4) -- 2為message length 2為message type
bt:writeShort(msgid)
bt:writeBytes(ba)
return
bt
end
end
|
-- write 數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
function scnet.writeData( ba,msg_type,data )
local key = msg_type.key
print(
"scnet.writeData"
,
"key"
,key)
if
key and data[key] then
local _type = msg_type[
"fmt"
]
if
type(_type) ==
"string"
then
if
_type ==
"string"
then
ba:writeStringUShort(data[key])
elseif _type ==
"number"
then
ba:writeLuaNumber(data[key])
elseif _type ==
"int"
then
ba:writeInt(data[key])
elseif _type ==
"short"
then
ba:writeShort(data[key])
end
else
ba:writeShort(#data[key])
for
k,v in pairs(data[key])
do
for
i=1,#_type
do
scnet.writeData(ba,_type<i>,v)
end
end
end
else
print(
"找不到對應的 key"
,msg_type.key,msg_type,data)
end
end
|
-- 讀取數據
-- 接收消息
1
2
3
4
5
6
7
8
9
10
11
12
|
function scnet.receive( event )
local ba = ByteArray.
new
(ByteArray.ENDIAN_BIG)
ba:writeBuf(event.data)
ba:setPos(1)
-- 有連包的情況,所以要讀取數據
while
ba:getAvailable() <= ba:getLen()
do
scnet.decodeData(ba)
if
ba:getAvailable() == 0 then
break
end
end
end
|
-- 消息數據解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
function scnet.decodeData( ba )
local len = ba:readShort() -- 讀數據總長度
local total = ba:readByte() -- 一個用於驗證的數子
local byteList = {}
local tmpTotal = 0
for
i=1,len - 3
do
-- 去除前兩個長度
local tmpBit = ba:readByte()
local enByte = scnet.decodeByte(tmpBit)
tmpTotal = tmpTotal + enByte
byteList<i> = enByte
end
local result = ByteArray.
new
(ByteArray.ENDIAN_BIG)
for
i=1,#byteList
do
result:writeRawByte(string.
char
(byteList<i>))
end
result:setPos(1)
if
(tmpTotal % 256) == total then
scnet.decodeMsg(result)
else
print(
"scnet.decodeData total error"
)
end
end
|
-- 根據格式解析數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
function scnet.decodeMsg( byteArray )
local rData = {}
local len = byteArray:readShort()
local msgid = byteArray:readShort()
local roleString = byteArray:readStringUShort()
local fmt = InfoUtil:getMsgFmt(msgid)
for
i=1,#fmt
do
scnet.readData(byteArray,fmt<i>,rData)
end
if
rData[
"result"
] ~= 0 then
print(
"result handler is here "
,rData[key])
return
else
NetManager:receiveMsg(msgid,rData)
end
end
-- readData
function scnet.readData( ba,msg_type,data)
local key = msg_type.key
if
key then
data[key] = data[key] or {}
local _type = msg_type[
"fmt"
]
if
type(_type) ==
"string"
then
if
_type ==
"string"
then
data[key] = ba:readStringUShort()
elseif _type ==
"number"
then
data[key] = ba:readLuaNumber()
elseif _type ==
"int"
then
data[key] = ba:readInt()
elseif _type ==
"short"
then
data[key] = ba:readShort()
end
if
key ==
"result"
then -- 當結果不為零的時候,說明有錯誤
if
data[key] ~= 0 then
print(
"result handler is here "
,data[key])
return
end
end
else
local _len = ba:readShort() -- 讀取數組長度
for
i=1,_len
do
local tmp = {}
for
j=1,#_type
do
scnet.readData(ba,_type[j],tmp)
end
table.insert(data[key],tmp)
end
end
else
print(
"找不到對應的 key scnet.readData"
,msg_type.key,msg_type,data)
end
end
|
-- 數據解密
1
2
3
4
5
|
function scnet.decodeByte( byte )
local tmp = bit.band(bit.bnot(bit.band(byte,255)),255)
tmp = bit.band((tmp + 256 - 80),255)
return
tmp
end
|
消息格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
-- 發送
MsgFmt[
"1001"
] = {
{
key =
"list"
,
fmt = {
{
key =
"id"
,fmt =
"int"
},
{
key =
"name"
,fmt =
"string"
},
{
key =
"level"
,fmt =
"int"
},
{
key =
"sex"
,fmt =
"int"
}
}
},
{
key =
"userid"
,fmt =
"int"
}
}
-- 返回
MsgFmt[
"5001"
] = {
{
key =
"result"
,fmt =
"int"
},
{
key =
"list"
,
fmt = {
{
key =
"id"
,fmt =
"int"
},
{
key =
"name"
,fmt =
"string"
},
{
key =
"level"
,fmt =
"int"
},
{
key =
"sex"
,fmt =
"int"
}
}
}
}
|
網絡管理NetManager
管理網絡的發送與接收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
-- 初始化
function NetManager:init( )
self._listenerList = {}
scnet.init()
scnet.connect(host,port)
end
-- 注冊消息
-- 注冊之后 接受到服務器消息之后進行廣播,誰注冊,誰相應
function NetManager:registerMsg( msgid,callBack )
self._listenerList[msgid] = self._listenerList[msgid] or {}
local isExist = self:findCallBack(msgid,callBack)
if
not isExist then
table.insert(self._listenerList[msgid],callBack)
end
end
-- 移除注冊消息
function NetManager:removeRegister( msgid,callBack )
if
self._listenerList[msgid] then
for
k,v in pairs(self._listenerList)
do
if
v == callBack then
self._listenerList[msgid][k] = nil
end
end
end
end
-- 發送消息
-- 整理數據發送給服務器
function NetManager:sendMsg( msgid,data )
scnet.send(msgid,data)
end
-- 接受消息
-- 派發事件(數據)
function NetManager:receiveMsg( msgid,data )
if
self._listenerList[msgid] then
for
k,v in pairs(self._listenerList[msgid])
do
v(data)
end
end
end
function NetManager:findCallBack( msgid,callBack )
for
k,v in pairs(self._listenerList[msgid])
do
if
v == callBack then
return
true
end
end
return
false
end
|
test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
-- 監聽事件
function MainScene:onEnter()
NetManager:registerMsg(MsgType.SC_LOGIN ,handler(self,self.receiveHandler))
end
-- 移除堅挺
function MainScene:onExit()
NetManager:removeRegister(MsgType.SC_LOGIN ,handler(self,self.receiveHandler))
end
-- 發送數據,根據MsgFmt構造數據
local data = {}
data.list = {}
table.insert(data.list,{id = 1001,name =
"小房"
,level = 1,sex = 1})
table.insert(data.list,{id = 1002,name =
"小田"
,level = 11,sex = 2})
table.insert(data.list,{id = 1003,name =
"2222"
,level = 21,sex = 1})
table.insert(data.list,{id = 1004,name =
"3333"
,level = 31,sex = 2})
data.userid = 10001
NetManager:sendMsg(MsgType.CS_LOGIN,data)
|
http://cn.cocos2d-x.org/tutorial/show?id=2604
http://zengrong.net/post/2020.htm