Quick-cocos2d-x SocketTCP链接

quick 里面提供了两种长连接WebSockets、SocketTCP,这里说一下SocketTCP的用法

local net = require("framework.cc.net.init")
local ByteArray = require("framework.cc.utils.ByteArray")
require("framework.cc.utils.bit")
```





-- 网络初始化,添加侦听函数
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
```






-- -- 发送数据给服务器
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* = 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*)
 end
 -- 把数据发送给服务器
 scnet.socket:send(result:getPack())
end


 -- 根据messageid来确定数据格式
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*,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 数据
function scnet.writeData( ba,msg_type,data )
 
 local key = msg_type.key
 print("scnet.writeData","key",key)
 if key and data then
 local _type = msg_type"fmt"]
 if type(_type) == "string" then
 if _type == "string" then
 ba:writeStringUShort(data)
 elseif _type == "number" then
 ba:writeLuaNumber(data)
 elseif _type == "int" then
 ba:writeInt(data)
 elseif _type == "short" then
 ba:writeShort(data)
 end
 else
 ba:writeShort(#data)
 for k,v in pairs(data) do
 for i=1,#_type do
 scnet.writeData(ba,_type*,v)
 end
 end
 end
 else
 print("找不到对应的 key",msg_type.key,msg_type,data)
 end
end
```






-- 读取数据
-- 接收消息
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



-- 消息数据解析
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* = enByte
 end


 local result = ByteArray.new(ByteArray.ENDIAN_BIG)
 for i=1,#byteList do
 result:writeRawByte(string.char(byteList*))
 end
 result:setPos(1)
 if (tmpTotal % 256) == total then
 scnet.decodeMsg(result)
 else
 print("scnet.decodeData  total   error")
 end
end

-- 根据格式解析数据
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*,rData)
 end
 if rData"result"] ~= 0 then
 print("result  handler is here  ",rData)
 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 = data or {}
 local _type = msg_type"fmt"]
 if type(_type) == "string" then
 if _type == "string" then
 data = ba:readStringUShort()
 elseif _type == "number" then
 data = ba:readLuaNumber()
 elseif _type == "int" then
 data = ba:readInt()
 elseif _type == "short" then
 data = ba:readShort()
 end


 if key == "result" then  -- 当结果不为零的时候,说明有错误
 
 if data ~= 0 then
 print("result  handler is here  ",data)
 return
 end
 end


 else
 local _len = ba:readShort() -- 读取数组长度
 for i=1,_len do
 local tmp = {}
 for j=1,#_type do
 scnet.readData(ba,_type,tmp)
 end
 table.insert(data,tmp)
 end
 
 end
 else
 print("找不到对应的 key  scnet.readData",msg_type.key,msg_type,data)
 end
end

-- 数据解密
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
```




------------------------------------------------------------------- 消息格式  -------------------------------------------------------------------
-- 发送
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  -------------------------------------------------------------------
管理网络的发送与接收


-- 初始化
function NetManager:init(  )
 self._listenerList = {}
 scnet.init()
 scnet.connect(host,port)
end





-- 注册消息
-- 注册之后 接受到服务器消息之后进行广播,谁注册,谁相应
function NetManager:registerMsg( msgid,callBack )
 self._listenerList = self._listenerList or {}
 local isExist = self:findCallBack(msgid,callBack)
 if not isExist then
 table.insert(self._listenerList,callBack)
 end
end



-- 移除注册消息
function NetManager:removeRegister( msgid,callBack )
 if self._listenerList then
 for k,v in pairs(self._listenerList) do
 if v == callBack then
 self._listenerList = nil
 end
 end
 end
end



-- 发送消息
-- 整理数据发送给服务器
function NetManager:sendMsg( msgid,data )
 scnet.send(msgid,data)
end



-- 接受消息
-- 派发事件(数据)
function NetManager:receiveMsg( msgid,data )
 if self._listenerList then
 for k,v in pairs(self._listenerList) do
 v(data)
 end
 end
end


function NetManager:findCallBack( msgid,callBack )
 for k,v in pairs(self._listenerList) do
 if v == callBack then
 return true
 end
 end
 return false
end



------------------------------------------------------------------- test  -------------------------------------------------------------------
-- 监听事件
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)
```


*******

好东西,mark:2::2:

我也mark一下

这个支持下,是基于哪个版本的呢?

Quick V3.3

:7:赞!:7::7::7:

有个 问题想问问 大神 ,cc.utils.ByteArrayVarint 里面有个调用了bit.lshift的方法.但是现在cc.uilts.bit 里面是这样bit.blshift 调用的。。这个运行时报错 怎么解决啊?

网络是独立线程负责的么?

mark一下 感谢楼主分享,弱弱的问一下 这是3.3的么?

楼主 找不到MsgType的实例啊… 在哪里定义的MsgType啊? 新手一枚…

求大神发送整个项目,学习,膜拜!!!!!!
306734753@qq.com:9::9::9::9:

大神求源码

感谢分享,又提供了一个很好的思路。

弱弱的问下:为什么我ba:writeChar(’@’)会报错呢?ba:writeChar(‘2’)又没事

MsgType是一个table,用来制定消息

怎么 检测是否断开连接 SocketTCP isConnected值改变

local __body, __status, __partial = self.tcp:receive("*a")

if __status == STATUS_CLOSED or __status == STATUS_NOT_CONNECTED then
self:close()
if self.isConnected then
self:_onDisconnect()
else
self:_connectFailure()
end
return
end

__status 的值一直都是 timeout

mark下,顶一顶楼主喽:13:

— Begin quote from ____

引用第15楼mainchar于2015-06-17 16:36发表的 :
怎么 检测是否断开连接 SocketTCP isConnected值改变

local __body, __status, __partial = self.tcp:receive("*a")

if __status == STATUS_CLOSED or __status == STATUS_NOT_CONNECTED then
http://www.cocoachina.com/bbs/job.php?action=topost&tid=281270&pid=1330409

— End quote

同样碰到了类似的问题, 这个怎么解~

请问你这种SocketTCP方式 是阻塞方式和是非阻赛方式。在程序中启动后 开始收数据和发数据会阻塞游戏主线程吗?

学习了:14::14::14::14::14: