socket 获取回传信息_Luat系列官方教程5:Socket代码详解
文章篇幅較長,代碼部分建議橫屏查看,或在PC端打開本文鏈接。文末依然為愛學習的你準備了專屬福利~
TCP和UDP除了在Lua代碼聲明時有一些不同,其他地方完全一樣,所以下面的代碼將以TCP長連接的數據收發作為示例,如果需要UDP連接,只需要改聲明對象時的三個字母即可。
閱讀本文需要具有的技能:
看過該系列前幾篇文章或明白前幾篇文章內容的
熟悉Lua語法,尤其是數組部分
可以明白字符串、字節碼之間的區別
可以自己實踐操作
對TCP/UDP通訊有基本的了解
各位想看MQTT解釋的,請等待下一篇文章,不過也可以順便看看這一篇,二者都差不多的。
1
Socket(TCP/UDP)
TCP和UDP除了在Lua代碼聲明時有一些不同,其他地方完全一樣,所以下面的代碼將以TCP長連接的數據收發作為示例,如果需要UDP連接,只需要改聲明對象時的三個字母即可。
先定義一個假裝能用來測試的TCP協議(需求)
客戶端每10秒發送一條字符串heart beat
客戶端接收到back開頭的數據要回復相同的數據
客戶端收到bin要回復二進制數組0x11 0x22 0x33
客戶端收到time要回復當前時間的時間戳字符串
示例時序如下:
2
代碼詳解
2.1 官方demo提供的示例代碼
在github的Luat_2G_RDA_8955/script_LuaTask/demo/socket/longConnection目錄或luatools的LuaTools 1.x.x\script\script_LuaTask\demo\socket\longConnection目錄找到
如果你能看懂官方例程,那么可以直接去使用,不需要再看本文了。
2.2? socket連接代碼的拆解分析
這一部分會將官方demo的代碼拆開來,只保留基礎部分,放到一個文件中來解釋。
2.2.1建立文件
首先先新建兩個文件,用于測試這個工程。
main.lua
PROJECT = "SOCKET-TEST"
VERSION = "1.0.0"
--根據固件判斷模塊類型
moduleType = string.find(rtos.get_version(),"8955") and 2 or 4
require "log"
LOG_LEVEL = log.LOGLEVEL_TRACE
require "sys"
--每1分鐘查詢一次GSM信號強度,每1分鐘查詢一次基站信息
require "net"
net.startQueryAll(60000, 60000)
--加載硬件看門狗功能模塊
--如果用的是720 4g模塊,請注釋掉這兩行
require "wdt"
wdt.setup(pio.P0_30, pio.P0_31)
--加載網絡指示燈功能模塊
require "netLed"
netLed.setup(true,moduleType == 2 and pio.P1_1 or pio.P2_0,moduleType == 2 and nil or pio.P2_1)
require"longlink"
--啟動系統框架
sys.init(0, 0)
sys.run()
longlink.lua
module(...,package.seeall)
require"socket"
--下面代碼一會兒寫
2.2.2找一個測試用的服務器
2G模塊Socket測試和Wi-Fi有著本質的區別:沒法使用內網來調試,必須要使用一個公網服務器來調試。
為了解決這個問題,Luat官方提供了一個TCP測試實驗室網站服務:http://tcplab.openluat.com/這個工具有一個壞處,就是三分鐘沒有客戶端連接的話就會被強行關閉服務。我們可以在本地用一個TCP調試工具提前連上,就不會被強制關閉服務了。
為了針對這種情況,我臨時寫了一個工具:https://github.com/chenxuuu/tcplab.openluat.com編譯好的文件可以點擊下載。
打開后可以直接獲取從服務器分配的ip、端口,還能接收客戶端數據、主動發送數據:
記住自己獲取到的ip和端口,在下面的代碼中會被使用到。
2.2.3建立socket線程
一般來說,socket連接都是異步運行的,何時應該發送數據,何時應該接收數據,這些邏輯應該讓socket收發的進程自己進行控制。
所以我們在longlink.lua中添加一個新的線程(看不懂的回去看前幾篇文章),文件改成如下(注意要自己改東西!):
longlink.lua
module(...,package.seeall)
require"socket"
--測試用的服務器信息,上一部分獲取到的那個
local testip,testport = "",""
--啟動socket客戶端任務
sys.taskInit(
function()
? ?while true do
--該區域的代碼會永久循環運行(除非出現語法錯誤)
end
end)
2.2.4進行socket連接
一般來說,我們會在模塊成功獲取基站分配的ip后,才會進行網絡的連接操作,所以我們需要使用socket.isReady()函數來判斷是否連接網絡,然后再進行網絡操作。
在成功獲取ip后,我們才能新建一個tcp對象,對其進行聯網操作,socket客戶端線程代碼改為如下:
--啟動socket客戶端任務
sys.taskInit(
function()
? ?while true do
? ? ? ?--是否獲取到了分配的ip(是否連上網)
? ? ? ?if socket.isReady() then
? ? ? ? ? ?--新建一個socket對象,如果是udp只需要把tcp改成udp即可
? ? ? ? ? ?local socketClient = socket.tcp()
--嘗試連接指定服務器
? ? ? ? ? ?if socketClient:connect(testip,testport) then
--連接成功
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect success")
else
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect fail")
--連接失敗
end
else
--沒連上網,原地等待一秒,一秒后會循環回去重試
? ? ? ? ? ?sys.wait(1000)
end
end
end)
2.2.5對連接失敗的處理
上述代碼只是一個簡單的連接服務器的代碼,并且連上之后沒有進行任何的其他操作。
為了增加代碼的穩健性,我們可以利用sys.waitUntil()函數,設置五分鐘內沒有獲取到ip就開啟飛行模式幾秒,再關閉,讓模塊重新去獲取GPRS連接:
--啟動socket客戶端任務
sys.taskInit(
function()
? ?while true do
? ? ? ?--是否獲取到了分配的ip(是否連上網)
? ? ? ?if socket.isReady() then
? ? ? ? ? ?--新建一個socket對象,如果是udp只需要把tcp改成udp即可
? ? ? ? ? ?local socketClient = socket.tcp()
--嘗試連接指定服務器
? ? ? ? ? ?if socketClient:connect(testip,testport) then
--連接成功
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect success")
else
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect fail")
--連接失敗
end
else
--沒連上網
? ? ? ? ? ?--等待網絡環境準備就緒,超時時間是5分鐘
? ? ? ? ? ?sys.waitUntil("IP_READY_IND",300000)
--等完了還沒連上?
? ? ? ? ? ?if not socket.isReady() then
? ? ? ? ? ? ? ?--進入飛行模式,20秒之后,退出飛行模式
? ? ? ? ? ? ? ?net.switchFly(true)
? ? ? ? ? ? ? ?sys.wait(20000)
? ? ? ? ? ? ? ?net.switchFly(false)
end
end
end
end)
同樣,我們也可以給socketClient:connect(testip,testport)的連接加上錯誤次數的判斷,連接錯誤超過五次,強制斷開socket連接,等待五秒后重試:
--啟動socket客戶端任務
sys.taskInit(
function()
? ?local retryConnectCnt = 0 ? --失敗次數統計
? ?while true do
? ? ? ?--是否獲取到了分配的ip(是否連上網)
? ? ? ?if socket.isReady() then
? ? ? ? ? ?--新建一個socket對象,如果是udp只需要把tcp改成udp即可
? ? ? ? ? ?local socketClient = socket.tcp()
--嘗試連接指定服務器
? ? ? ? ? ?if socketClient:connect(testip,testport) then
--連接成功
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect success")
? ? ? ? ? ? ? ?retryConnectCnt = 0 --失敗次數清零
else
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect fail")
--連接失敗
? ? ? ? ? ? ? ?retryConnectCnt = retryConnectCnt+1 --失敗次數加一
end
? ? ? ? ? ?socketClient:close() ? ?--斷開socket連接
? ? ? ? ? ?if retryConnectCnt>=5 then ?--失敗次數大于五次了
? ? ? ? ? ? ? ?link.shut() ? ? ? ? --強制斷開TCP/UDP連接
? ? ? ? ? ? ? ?retryConnectCnt=0 ? --失敗次數清零
end
? ? ? ? ? ?sys.wait(5000)
else
? ? ? ? ? ?retryConnectCnt = 0 ? ? --沒連上網,失敗次數清零
--沒連上網
? ? ? ? ? ?--等待網絡環境準備就緒,超時時間是5分鐘
? ? ? ? ? ?sys.waitUntil("IP_READY_IND",300000)
--等完了還沒連上?
? ? ? ? ? ?if not socket.isReady() then
? ? ? ? ? ? ? ?--進入飛行模式,20秒之后,退出飛行模式
? ? ? ? ? ? ? ?net.switchFly(true)
? ? ? ? ? ? ? ?sys.wait(20000)
? ? ? ? ? ? ? ?net.switchFly(false)
end
end
end
end)
2.2.6添加發送/接收處理函數
到了這一步,整個的socket線程只剩下循環處理接收和發送的數據這一部分與demo不同了,我們直接把這兩句話加到socket線程的代碼中吧:
--啟動socket客戶端任務
sys.taskInit(
function()
? ?local retryConnectCnt = 0 ? --失敗次數統計
? ?while true do
? ? ? ?--是否獲取到了分配的ip(是否連上網)
? ? ? ?if socket.isReady() then
? ? ? ? ? ?--新建一個socket對象,如果是udp只需要把tcp改成udp即可
? ? ? ? ? ?local socketClient = socket.tcp()
--嘗試連接指定服務器
? ? ? ? ? ?if socketClient:connect(testip,testport) then
--連接成功
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect success")
? ? ? ? ? ? ? ?retryConnectCnt = 0 --失敗次數清零
--循環處理接收和發送的數據
? ? ? ? ? ? ? ?while true do
? ? ? ? ? ? ? ? ? ?if not inMsgProcess(socketClient) then ?--接收消息處理函數
? ? ? ? ? ? ? ? ? ? ? ?log.error("longlink.inMsgProcess error")
break
end
? ? ? ? ? ? ? ? ? ?if not outMsgprocess(socketClient) then --發送消息處理函數
? ? ? ? ? ? ? ? ? ? ? ?log.error("longlink.outMsgprocess error")
break
end
end
else
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect fail")
--連接失敗
? ? ? ? ? ? ? ?retryConnectCnt = retryConnectCnt+1 --失敗次數加一
end
? ? ? ? ? ?socketClient:close() ? ?--斷開socket連接
? ? ? ? ? ?if retryConnectCnt>=5 then ?--失敗次數大于五次了
? ? ? ? ? ? ? ?link.shut() ? ? ? ? --強制斷開TCP/UDP連接
? ? ? ? ? ? ? ?retryConnectCnt=0 ? --失敗次數清零
end
? ? ? ? ? ?sys.wait(5000)
else
? ? ? ? ? ?retryConnectCnt = 0 ? ? --沒連上網,失敗次數清零
--沒連上網
? ? ? ? ? ?--等待網絡環境準備就緒,超時時間是5分鐘
? ? ? ? ? ?sys.waitUntil("IP_READY_IND",300000)
--等完了還沒連上?
? ? ? ? ? ?if not socket.isReady() then
? ? ? ? ? ? ? ?--進入飛行模式,20秒之后,退出飛行模式
? ? ? ? ? ? ? ?net.switchFly(true)
? ? ? ? ? ? ? ?sys.wait(20000)
? ? ? ? ? ? ? ?net.switchFly(false)
end
end
end
end)
可以看到,在接收和發送函數不返回false的情況下,接收和發送循環會一直進行下去;只有當兩個函數之一返回false時,才會觸發break導致退出該接收和發送循環。
inMsgProcess(socketClient)函數
這段的代碼相對來說比較簡單,我們可以直接使用socketClient:recv(毫秒數)來接收我們的TCP消息。
我們在合適的地方,新建一個inMsgProcess(socketClient)函數:
function inMsgProcess(socketClient)
? ?local result,data
? ?while true do
? ? ? ?result,data = socketClient:recv(2000)
--接收數據
? ? ? ?if result then ?--接收成功
? ? ? ? ? ?log.info("longlink.inMsgProcess",data)
? ? ? ? ? ?--處理data數據,現在還沒代碼,空著
? ? ? ?else ? ?--接收失敗
break
end
end
? ?--返回結果,處理成功返回true,處理出錯返回false
? ?return result or data=="timeout"
end
這段代碼就是循環獲取socket消息,如果沒獲取到,socketClient:recv(2000)就會返回false,"timeout";如果獲取到了,就會返回true,獲取到的數據字符串;如果返回了false,不為"timeout",則表示數據處理出錯,說明socket連接有了什么問題
細心的讀者可能看出來了,如果接收函數一直在2秒內有接收到數據,那么這段函數會永遠無限循環下去,沒辦法到達outMsgprocess(socketClient)函數進行發送數據的操作,所以我們先去講outMsgprocess(socketClient)函數的實現過程,再回來改進inMsgProcess(socketClient)函數
outMsgprocess(socketClient)函數
由于發送函數在socket線程中是一個循環的小部分,所以我們要建立一個消息發送的隊列:有要發送的發數據時,將數據放到這個隊列中;等運行到outMsgprocess(socketClient)函數時,將隊列中的數據一個一個發出去
首先我們要建一個放這種隊列的數組,在合適位置聲明一下這個數組:
--數據發送的消息隊列
local msgQuene = {}
接著我們構造一個可以往數組里插入數據的函數,table.insert()可以向數組添加數據,所以我們新建一個insertMsg函數:
local function insertMsg(data)
? ?table.insert(msgQuene,data)
end
還記得上面說過的消息接收函數函數會永遠無限循環下去的問題嗎?我們在合適的地方新建一個判斷發送消息隊列是否為空的函數:
function waitForSend()
? ?return #msgQuene > 0
end
在數組有數據時,這個函數會返回true,我們可以將inMsgProcess(socketClient)接收到數據后的代碼添加一行判斷發送隊列是否有數據的代碼,當檢測到發送隊列有數據時,就立即退出接收函數,轉而去進行發送動作,接收函數最終改為了這樣:
function inMsgProcess(socketClient)
? ?local result,data
? ?while true do
? ? ? ?result,data = socketClient:recv(2000)
--接收到數據
? ? ? ?if result then ?--接收成功
? ? ? ? ? ?log.info("longlink.inMsgProcess",data)
? ? ? ? ? ?--處理data數據,現在還沒代碼,空著
? ? ? ? ? ?--如果msgQuene中有等待發送的數據,則立即退出本循環
? ? ? ? ? ?if waitForSend() then return true end
? ? ? ?else ? ?--接收失敗
break
end
end
? ?--返回結果,處理成功返回true,處理出錯返回false
? ?return result or data=="timeout"
end
最后我們終于可以開始寫消息發送函數了,整體的函數就是檢查隊列是否為空,不為空的話就發一條消息并將其從隊列中刪除,然后重復這一操作,函數代碼如下:
function outMsgprocess(socketClient)
--隊列中有消息
? ?while #msgQuene>0 do
--獲取消息,并從隊列中刪除
? ? ? ?local outMsg = table.remove(msgQuene,1)
--發送這條消息,并獲取發送結果
? ? ? ?local result = socketClient:send(outMsg)
? ? ? ?--發送失敗的話立刻返回nil(等同于false)
? ? ? ?if not result then return end
end
? ?return true
end
2.2.7完成基本的socket線程
經過上述的更改,最終,longlink.lua已經實現了連接服務器并自動處理錯誤的功能,并且預留了消息接收以及向發送隊列添加數據的接口,文件的所有代碼如下:
longlink.lua
module(...,package.seeall)
require"socket"
--測試用的服務器信息
local testip,testport = "180.97.81.180","50798"
--數據發送的消息隊列
local msgQuene = {}
local function insertMsg(data)
? ?table.insert(msgQuene,data)
end
function waitForSend()
? ?return #msgQuene > 0
end
function outMsgprocess(socketClient)
--隊列中有消息
? ?while #msgQuene>0 do
--獲取消息,并從隊列中刪除
? ? ? ?local outMsg = table.remove(msgQuene,1)
--發送這條消息,并獲取發送結果
? ? ? ?local result = socketClient:send(outMsg)
? ? ? ?--發送失敗的話立刻返回nil(等同于false)
? ? ? ?if not result then return end
end
? ?return true
end
function inMsgProcess(socketClient)
? ?local result,data
? ?while true do
? ? ? ?result,data = socketClient:recv(2000)
--接收到數據
? ? ? ?if result then ?--接收成功
? ? ? ? ? ?log.info("longlink.inMsgProcess",data)
? ? ? ? ? ?--處理data數據,現在還沒代碼,空著
? ? ? ? ? ?--如果msgQuene中有等待發送的數據,則立即退出本循環
? ? ? ? ? ?if waitForSend() then return true end
? ? ? ?else ? ?--接收失敗
break
end
end
? ?--返回結果,處理成功返回true,處理出錯返回false
? ?return result or data=="timeout"
end
--啟動socket客戶端任務
sys.taskInit(
function()
? ?local retryConnectCnt = 0 ? --失敗次數統計
? ?while true do
? ? ? ?--是否獲取到了分配的ip(是否連上網)
? ? ? ?if socket.isReady() then
? ? ? ? ? ?--新建一個socket對象,如果是udp只需要把tcp改成udp即可
? ? ? ? ? ?local socketClient = socket.tcp()
--嘗試連接指定服務器
? ? ? ? ? ?if socketClient:connect(testip,testport) then
--連接成功
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect success")
? ? ? ? ? ? ? ?retryConnectCnt = 0 --失敗次數清零
--循環處理接收和發送的數據
? ? ? ? ? ? ? ?while true do
? ? ? ? ? ? ? ? ? ?if not inMsgProcess(socketClient) then ?--接收消息處理函數
? ? ? ? ? ? ? ? ? ? ? ?log.error("longlink.inMsgProcess error")
break
end
? ? ? ? ? ? ? ? ? ?if not outMsgprocess(socketClient) then --發送消息處理函數
? ? ? ? ? ? ? ? ? ? ? ?log.error("longlink.outMsgprocess error")
break
end
end
else
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect fail")
--連接失敗
? ? ? ? ? ? ? ?retryConnectCnt = retryConnectCnt+1 --失敗次數加一
end
? ? ? ? ? ?socketClient:close() ? ?--斷開socket連接
? ? ? ? ? ?if retryConnectCnt>=5 then ?--失敗次數大于五次了
? ? ? ? ? ? ? ?link.shut() ? ? ? ? --強制斷開TCP/UDP連接
? ? ? ? ? ? ? ?retryConnectCnt=0 ? --失敗次數清零
end
? ? ? ? ? ?sys.wait(5000)
else
? ? ? ? ? ?retryConnectCnt = 0 ? ? --沒連上網,失敗次數清零
--沒連上網
? ? ? ? ? ?--等待網絡環境準備就緒,超時時間是5分鐘
? ? ? ? ? ?sys.waitUntil("IP_READY_IND",300000)
--等完了還沒連上?
? ? ? ? ? ?if not socket.isReady() then
? ? ? ? ? ? ? ?--進入飛行模式,20秒之后,退出飛行模式
? ? ? ? ? ? ? ?net.switchFly(true)
? ? ? ? ? ? ? ?sys.wait(20000)
? ? ? ? ? ? ? ?net.switchFly(false)
end
end
end
end)
燒錄到模塊中,可以得到正常的連接結果:
2.3 實現協議需求
2.3.1心跳包需求
這個需求極其簡單,只需要建立一個新的線程,在聯網后往消息隊列中添加數據即可,代碼如下:
--啟動心跳包任務
sys.taskInit(
function()
? ?while true do
? ? ? ?if socket.isReady() then ? ?--連上網再開始運行
? ? ? ? ? ?insertMsg("heart beat") --隊列里塞個消息
? ? ? ? ? ?sys.wait(10000) ? ? ? ? --等待10秒
? ? ? ?else ? ?--沒連上網別忘了延時!不然會陷入while true死循環,導致模塊無法運行其他代碼
? ? ? ? ? ?sys.wait(1000) ? ? ? ? ?--等待1秒
end
end
end)
2.3.2收到back開頭的數據要回復相同的數據
這一條功能十分簡單,只需要在inMsgProcess()函數中,寫了--處理data數據,現在還沒代碼,空著這段注釋的地方添加相應代碼即可,代碼如下:
--處理data數據
if data:sub(1,4) == "back" then --收到back開頭的數據要回復相同的數據
? ?insertMsg(data)
end
2.3.3客戶端收到bin要回復二進制數組0x11 0x22 0x33
這個功能和上面差不多,返回的東西不一樣而已,拼接字節碼我們可以用pack,也可以直接用fromHex,下面兩種方法都示范一下:
pack方式:
if data == "bin" then --收到bin要回復二進制數組0x11 0x22 0x33
? ?insertMsg(pack.pack(">bbb",0x11,0x22,0x33))
end
fromHex方式:
if data == "bin" then --收到bin要回復二進制數組0x11 0x22 0x33
? ?insertMsg(string.fromHex("112233"))
end
2.3.4收到time要回復當前時間的時間戳字符串
進行這個操作,要在開機的時候先同步一下時間,我們可以使用demo中的同步ntp來實現。在main.lua中的啟動系統框架上方添加兩行同步代碼即可:
require"ntp"
ntp.timeSync()
接著和上面一樣,在消息接收處返回需要的數據即可:
if data == "time" then --收到time要回復當前時間的時間戳字符串
? ?insertMsg(tostring(os.time()))
end
2.4完整代碼
經過上面的刪刪改改,功能以及基本實現了,整個文件的代碼如下:
longlink.lua
module(...,package.seeall)
require"socket"
--測試用的服務器信息
local testip,testport = "180.97.81.180","50798"
--數據發送的消息隊列
local msgQuene = {}
local function insertMsg(data)
? ?table.insert(msgQuene,data)
end
function waitForSend()
? ?return #msgQuene > 0
end
function outMsgprocess(socketClient)
--隊列中有消息
? ?while #msgQuene>0 do
--獲取消息,并從隊列中刪除
? ? ? ?local outMsg = table.remove(msgQuene,1)
--發送這條消息,并獲取發送結果
? ? ? ?local result = socketClient:send(outMsg)
? ? ? ?--發送失敗的話立刻返回nil(等同于false)
? ? ? ?if not result then return end
end
? ?return true
end
function inMsgProcess(socketClient)
? ?local result,data
? ?while true do
? ? ? ?result,data = socketClient:recv(2000)
--接收到數據
? ? ? ?if result then ?--接收成功
? ? ? ? ? ?log.info("longlink.inMsgProcess",data)
? ? ? ? ? ?--處理data數據
? ? ? ? ? ?if data:sub(1,4) == "back" then --收到back開頭的數據要回復相同的數據
? ? ? ? ? ? ? ?insertMsg(data)
? ? ? ? ? ?elseif data == "bin" then --收到bin要回復二進制數組0x11 0x22 0x33
? ? ? ? ? ? ? ?insertMsg(string.fromHex("112233"))
? ? ? ? ? ?elseif data == "time" then --收到time要回復當前時間的時間戳字符串
? ? ? ? ? ? ? ?insertMsg(tostring(os.time()))
end
? ? ? ? ? ?--如果msgQuene中有等待發送的數據,則立即退出本循環
? ? ? ? ? ?if waitForSend() then return true end
? ? ? ?else ? ?--接收失敗
break
end
end
? ?--返回結果,處理成功返回true,處理出錯返回false
? ?return result or data=="timeout"
end
--啟動socket客戶端任務
sys.taskInit(
function()
? ?local retryConnectCnt = 0 ? --失敗次數統計
? ?while true do
? ? ? ?--是否獲取到了分配的ip(是否連上網)
? ? ? ?if socket.isReady() then
? ? ? ? ? ?--新建一個socket對象,如果是udp只需要把tcp改成udp即可
? ? ? ? ? ?local socketClient = socket.tcp()
--嘗試連接指定服務器
? ? ? ? ? ?if socketClient:connect(testip,testport) then
--連接成功
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect success")
? ? ? ? ? ? ? ?retryConnectCnt = 0 --失敗次數清零
--循環處理接收和發送的數據
? ? ? ? ? ? ? ?while true do
? ? ? ? ? ? ? ? ? ?if not inMsgProcess(socketClient) then ?--接收消息處理函數
? ? ? ? ? ? ? ? ? ? ? ?log.error("longlink.inMsgProcess error")
break
end
? ? ? ? ? ? ? ? ? ?if not outMsgprocess(socketClient) then --發送消息處理函數
? ? ? ? ? ? ? ? ? ? ? ?log.error("longlink.outMsgprocess error")
break
end
end
else
? ? ? ? ? ? ? ?log.info("longlink.socketClient","connect fail")
--連接失敗
? ? ? ? ? ? ? ?retryConnectCnt = retryConnectCnt+1 --失敗次數加一
end
? ? ? ? ? ?socketClient:close() ? ?--斷開socket連接
? ? ? ? ? ?if retryConnectCnt>=5 then ?--失敗次數大于五次了
? ? ? ? ? ? ? ?link.shut() ? ? ? ? --強制斷開TCP/UDP連接
? ? ? ? ? ? ? ?retryConnectCnt=0 ? --失敗次數清零
end
? ? ? ? ? ?sys.wait(5000)
else
? ? ? ? ? ?retryConnectCnt = 0 ? ? --沒連上網,失敗次數清零
--沒連上網
? ? ? ? ? ?--等待網絡環境準備就緒,超時時間是5分鐘
? ? ? ? ? ?sys.waitUntil("IP_READY_IND",300000)
--等完了還沒連上?
? ? ? ? ? ?if not socket.isReady() then
? ? ? ? ? ? ? ?--進入飛行模式,20秒之后,退出飛行模式
? ? ? ? ? ? ? ?net.switchFly(true)
? ? ? ? ? ? ? ?sys.wait(20000)
? ? ? ? ? ? ? ?net.switchFly(false)
end
end
end
end)
--啟動心跳包任務
sys.taskInit(
function()
? ?while true do
? ? ? ?if socket.isReady() then ? ?--連上網再開始運行
? ? ? ? ? ?insertMsg("heart beat") --隊列里塞個消息
? ? ? ? ? ?sys.wait(10000) ? ? ? ? --等待10秒
? ? ? ?else ? ?--沒連上網別忘了延時!不然會陷入while true死循環,導致模塊無法運行其他代碼
? ? ? ? ? ?sys.wait(1000) ? ? ? ? ?--等待1秒
end
end
end)
main.lua
PROJECT = "SOCKET-TEST"
VERSION = "1.0.0"
require "log"
LOG_LEVEL = log.LOGLEVEL_TRACE
require "sys"
--每1分鐘查詢一次GSM信號強度,每1分鐘查詢一次基站信息
require "net"
net.startQueryAll(60000, 60000)
--加載硬件看門狗功能模塊
require "wdt"
wdt.setup(pio.P0_30, pio.P0_31)
--加載網絡指示燈功能模塊
require "netLed"
netLed.setup(true,pio.P1_1)
require"longlink"
require"ntp"
ntp.timeSync()
--啟動系統框架
sys.init(0, 0)
sys.run()
3
驗證功能
把最終代碼燒錄進去,按需求測試即可:
很明顯,功能符合預期。
今天的內容就講到這里,如有錯誤或疑問請在文后留言,感謝大家的關注!
更多福利,敬請期待Luat相關教程文章:
Luat系列官方教程1:下載調試工具LuaTools的使用指南
Luat系列官方教程2:控制LED小燈
Luat系列官方教程3:Luat程序的基本時序
Luat系列官方教程4:學會使用并看懂Luatools的trace信息
Luat小企業系列原創文章:
小企業怎么尋找生意的藍海?
小企業2B新產品怎樣定價?
小企業的2B業務怎么獲客(一)?
合宙Luat將陸續推出小企業系列原創作品,敬請關注!
▼Luat熱文推薦▼>小企業怎么尋找生意的藍海?
>NB-IoT,未來的物聯網脊梁,還是扶不起的阿斗?
>2019年最值得工作和落戶的幾個城市,有你的家鄉嗎?
>為什么說『 物聯網通信模塊業務』沒有前途?
>4G模塊價格進入2位數時代,合宙Air720模塊正式量產發貨
>NB向左,GPRS向右,誰會率先突破百億連接數?
>GPRS模塊為什么會低至十幾元?我所經歷的物聯網模塊國產化過程
總結
以上是生活随笔為你收集整理的socket 获取回传信息_Luat系列官方教程5:Socket代码详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何批量修改文件后缀名如何批量修改文件后
- 下一篇: 化脓性扁桃体炎能导致前列腺炎吗