cocos2dx lua socket 使用

18k 词

从事cocos2dx也有好几年了,从开始的懵懂到现在(不知道如何评价自己,至少能把游戏做出来) 中途磕磕碰碰 想分享下tcp socket在lua中的使用 首先还是引入socket库和定义class和状态码 参考了quick的simple tcp 使用方法

	local gameSocket = LuaTcpSocket:new():init()
	local function onConnectStatus( code, msg )
<span class="k">end</span>
<span class="n">gameSocket</span><span class="p">:</span><span class="n">setConnectCallback</span><span class="p">(</span><span class="n">onConnectStatus</span><span class="p">)</span>
<span class="n">gameSocket</span><span class="p">:</span><span class="n">connect</span><span class="p">(</span><span class="n">ip</span><span class="p">,</span><span class="n">port</span><span class="p">)</span>

下面贴代码

local scheduler = cc.Director:getInstance():getScheduler()
local socket = require "socket"

local SOCKET_CONNECT_FAIL_TIMEOUT = 3 – socket failure timeout

local LuaTcpSocket = class("LuaTcpSocket")

local NET_STATUS = {
unconnected = 1,
connected = 2,
lostConnection = 3,
}

–初始化
function LuaTcpSocket:init()
self.socket = nil
self.session = 0
self.tickScheduler = nil
self.status = NET_STATUS.unconnected
self.lastContent = ""
return self
end
– 判断ipv6 苹果强烈要求
function LuaTcpSocket:isIpv6( host )
local result = socket.dns.getaddrinfo(host)
local ipv6 = false
if result then
for k,v in pairs(result) do
if v.family == "inet6" then
ipv6 = true
break
end
end
end
return ipv6
end

– 连接服务区,ip可以是域名,ipv6环境
function LuaTcpSocket:connect( ip, port )
local v6 = self:isIpv6(ip)
self.lastIp = ip
self.lastPort = port

<span class="k">if</span> <span class="n">v6</span> <span class="k">then</span>
	<span class="n">self</span><span class="p">.</span><span class="n">socket</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">tcp6</span><span class="p">()</span>
<span class="k">else</span>
	<span class="n">self</span><span class="p">.</span><span class="n">socket</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">tcp</span><span class="p">()</span>
<span class="k">end</span>
<span class="n">self</span><span class="p">.</span><span class="n">socket</span><span class="p">:</span><span class="n">settimeout</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="c1">--异步模式</span>

<span class="n">self</span><span class="p">:</span><span class="n">checkConnect</span><span class="p">()</span>

end

function LuaTcpSocket:realConnect()
local succ, status = self.socket:connect(self.lastIp, self.lastPort)
– print("LuaTcpSocket.realConnect:", succ, status)
return succ 1 or status STATUS_ALREADY_CONNECTED
end

function LuaTcpSocket:checkConnect()
self:stopConnectScheduler()
self.waitConnect = 0

<span class="n">self</span><span class="p">.</span><span class="n">connectTimeTickScheduler</span> <span class="o">=</span> <span class="n">scheduler</span><span class="p">:</span><span class="n">scheduleScriptFunc</span><span class="p">(</span><span class="k">function</span> <span class="p">(</span> <span class="n">dt</span> <span class="p">)</span>
	<span class="n">self</span><span class="p">.</span><span class="n">waitConnect</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">waitConnect</span> <span class="o">+</span> <span class="n">dt</span>
	<span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">waitConnect</span> <span class="o">&gt;=</span> <span class="n">SOCKET_CONNECT_FAIL_TIMEOUT</span> <span class="k">then</span>
		<span class="n">self</span><span class="p">.</span><span class="n">waitConnect</span> <span class="o">=</span> <span class="mi">0</span>
		<span class="n">self</span><span class="p">:</span><span class="n">close</span><span class="p">()</span>
		<span class="n">self</span><span class="p">:</span><span class="n">onConnectFail</span><span class="p">()</span>
		<span class="k">return</span>
	<span class="k">end</span>
	<span class="k">if</span> <span class="n">self</span><span class="p">:</span><span class="n">realConnect</span><span class="p">()</span> <span class="k">then</span>
		<span class="n">self</span><span class="p">:</span><span class="n">stopConnectScheduler</span><span class="p">()</span>
		<span class="n">self</span><span class="p">:</span><span class="n">onConnected</span><span class="p">()</span>
	<span class="k">end</span>
<span class="k">end</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="kc">false</span><span class="p">)</span>

end

function LuaTcpSocket:stopConnectScheduler()
if self.connectTimeTickScheduler then
scheduler:unscheduleScriptEntry(self.connectTimeTickScheduler)
end
self.connectTimeTickScheduler = nil
end

function LuaTcpSocket:close()
self:disconnect(NET_STATUS.unconnected)
end

function LuaTcpSocket:isConnected()
return self.status == NET_STATUS.connected
end

function LuaTcpSocket:onConnectFail()
if self.connectCallback ~= nil then
self.connectCallback(-1,"time out")
end
end

function LuaTcpSocket:onConnected()
self.status = NET_STATUS.connected
self:tick()
if self.connectCallback ~= nil then
self.connectCallback(0,"sucess")
end
end

function LuaTcpSocket:setConnectCallback( connectCallback )
self.connectCallback = connectCallback
end

function LuaTcpSocket:tick()
self.tickScheduler = scheduler:scheduleScriptFunc(function ( dt )
if self.status == NET_STATUS.connected then
local chunck, status, partial = self.socket:receive("*a")
– print("chunck",type(chunck),chunck) --nil nil
– print("status",type(status),status) --string timeout
– print("partial",type(status),partial) --string len=0

		<span class="k">if</span> <span class="n">status</span> <span class="ow">and</span> <span class="n">status</span> <span class="o">~=</span> <span class="s2">&#34;timeout&#34;</span> <span class="k">then</span>
			<span class="nb">print</span><span class="p">(</span><span class="s2">&#34;net status&#34;</span><span class="p">,</span><span class="n">status</span><span class="p">)</span>
			<span class="nb">print</span><span class="p">(</span><span class="s2">&#34;chunck&#34;</span><span class="p">,</span><span class="n">chunck</span><span class="p">)</span>
			<span class="nb">print</span><span class="p">(</span><span class="s2">&#34;partial&#34;</span><span class="p">,</span><span class="n">partial</span><span class="p">)</span>
			<span class="n">self</span><span class="p">:</span><span class="n">disconnect</span><span class="p">(</span><span class="n">NET_STATUS</span><span class="p">.</span><span class="n">lostConnection</span><span class="p">)</span>
			<span class="k">return</span>
		<span class="k">end</span>

		<span class="k">if</span> <span class="p">(</span> <span class="n">chunck</span> <span class="ow">and</span> <span class="o">#</span><span class="n">chunck</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">)</span> <span class="ow">or</span> <span class="p">(</span> <span class="n">partial</span> <span class="ow">and</span> <span class="o">#</span><span class="n">partial</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">)</span> <span class="k">then</span>
			<span class="c1">-- print(&#34;no data return 111&#34;)</span>
			<span class="k">return</span>
		<span class="k">end</span>

		<span class="k">if</span> <span class="n">partial</span> <span class="ow">and</span> <span class="o">#</span><span class="n">partial</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">then</span>
			<span class="n">self</span><span class="p">.</span><span class="n">lastContent</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">lastContent</span> <span class="o">..</span> <span class="n">partial</span>
		<span class="k">elseif</span> <span class="n">chunck</span> <span class="ow">and</span> <span class="o">#</span><span class="n">chunck</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">then</span>
			<span class="n">self</span><span class="p">.</span><span class="n">lastContent</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">lastContent</span> <span class="o">..</span> <span class="n">chunck</span>
		<span class="k">end</span>
		

		<span class="kd">local</span> <span class="n">flag</span><span class="p">,</span> <span class="n">remain</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">self</span><span class="p">:</span><span class="n">unpackage</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">lastContent</span><span class="p">)</span>
		<span class="c1">-- print(&#34;flag,remain,err&#34;,flag,remain,err)</span>
		<span class="k">if</span> <span class="n">flag</span> <span class="k">then</span>
			<span class="n">self</span><span class="p">.</span><span class="n">lastContent</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
		<span class="k">else</span>
			<span class="k">if</span> <span class="n">err</span> <span class="o">~=</span> <span class="kc">nil</span> <span class="k">then</span>
				<span class="nb">print</span><span class="p">(</span><span class="s2">&#34;why happen????&#34;</span><span class="p">,</span><span class="n">err</span><span class="p">)</span>
				<span class="n">self</span><span class="p">:</span><span class="n">disconnect</span><span class="p">(</span><span class="n">NET_STATUS</span><span class="p">.</span><span class="n">lostConnection</span><span class="p">)</span>
				<span class="k">return</span>
			<span class="k">end</span>
			<span class="n">self</span><span class="p">.</span><span class="n">lastContent</span> <span class="o">=</span> <span class="n">remain</span>
		<span class="k">end</span>
	
	<span class="k">else</span>
		<span class="c1">-- print(&#34;error tick&#34;,self.status)</span>
	<span class="k">end</span>

<span class="k">end</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="kc">false</span><span class="p">)</span>

end

– return sucess, content, err
– 这里用自己的字节流实现包的解压缩,需要注意半包,多包
function LuaTcpSocket:unpackage( content )
end

– 发生数据,也是用字节流
function LuaTcpSocket:send( data )
if not self:isConnected() then
self:disconnect(NET_STATUS.lostConnection)
return
end

<span class="kd">local</span> <span class="n">i</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">socket</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="c1">-- print(&#34;send,i err&#34;,i,err)</span>

<span class="k">if</span> <span class="n">err</span> <span class="k">then</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">==</span> <span class="s2">&#34;closed&#34;</span> <span class="k">then</span>
		<span class="n">self</span><span class="p">:</span><span class="n">disconnect</span><span class="p">(</span><span class="n">NET_STATUS</span><span class="p">.</span><span class="n">lostConnection</span><span class="p">)</span>
	<span class="k">end</span>
<span class="k">end</span>

end

function LuaTcpSocket:disconnect( status )
self.status = status
if self.socket then
self.socket:close()
end
self.socket = nil
self.lastContent = ""
self:stopTickScheduler()
self:stopConnectScheduler()
end

function LuaTcpSocket:stopTickScheduler()
if self.tickScheduler ~= nil then
scheduler:unscheduleScriptEntry(self.tickScheduler)
end
self.tickScheduler = nil
end

function LuaTcpSocket:reconnect()
return self:connect(self.lastIp,self.lastPort)
end