您好,登錄后才能下訂單哦!
小編給大家分享一下TCP連接的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
luat連接相比AT更為簡單,只需要簡單的配置即可連接,還可以靈活的對數(shù)據(jù)進行處理。
需要從官網(wǎng)或者github下載luatask的腳本包,或者使用luatoolsv2會自動下載腳本資源,在工具根目錄的\resource\8910_script中腳本資源會隨官網(wǎng)同步更新,具體版本可能和本文不同,不過功能都是一致的。
文檔中用到的API接口見wiki的API章節(jié)。
在腳本目錄的demo/socket文件夾里有兩種示例代碼,async是異步socket,sync是同步socket
同步:
同步的思想是:所有的操作都做完,才返回給用戶。這樣用戶在線等待的時間太長,給用戶一種卡死了的感覺(就是系統(tǒng)遷移中,點擊了遷移,界面就不動了,但是程序還在執(zhí)行,卡死了的感覺)。這種情況下,用戶不能關(guān)閉界面,如果關(guān)閉了,即遷移程序就中斷了。
異步:
將用戶請求放入消息隊列,并反饋給用戶,系統(tǒng)遷移程序已經(jīng)啟動,你可以關(guān)閉瀏覽器了。然后程序再慢慢地去寫入數(shù)據(jù)庫去。這就是異步。但是用戶沒有卡死的感覺,會告訴你,你的請求系統(tǒng)已經(jīng)響應(yīng)了。你可以關(guān)閉界面了。
同步和異步本身是相對的
同步就相當(dāng)于是 當(dāng)客戶端發(fā)送請求給服務(wù)端,在等待服務(wù)端響應(yīng)的請求時,客戶端不做其他的事情。當(dāng)服務(wù)端做完了才返回到客戶端。這樣的話客戶端需要一直等待。用戶使用起來會有不友好。
異步就是,當(dāng)客戶端發(fā)送給服務(wù)端請求時,在等待服務(wù)端響應(yīng)的時候,客戶端可以做其他的事情,這樣節(jié)約了時間,提高了效率。
存在就有其道理 異步雖然好 但是有些問題是要用同步用來解決,比如有些東西我們需要的是拿到返回的數(shù)據(jù)在進行操作的。這些是異步所無法解決的。
所以請根據(jù)實際需求選擇。
luat的socket操作是一個面向?qū)ο蟮牟僮魉允紫仁褂胹ocket.tcp(ssl, cert)創(chuàng)建一個對象
傳入值類型 | 釋義 |
---|---|
bool | 可選參數(shù),默認(rèn)為nil ,ssl,是否為ssl連接,true表示是,其余表示否 |
table | 可選參數(shù),默認(rèn)為nil ,cert,ssl連接需要的證書配置,只有ssl參數(shù)為true時,才參數(shù)才有意義,cert格式如下: { caCert = "ca.crt", --CA證書文件(Base64編碼 X.509格式),如果存在此參數(shù),則表示客戶端會對服務(wù)器的證書進行校驗;不存在則不校驗 clientCert = "client.crt", --客戶端證書文件(Base64編碼 X.509格式),服務(wù)器對客戶端的證書進行校驗時會用到此參數(shù) clientKey = "client.key", --客戶端私鑰文件(Base64編碼 X.509格式) clientPassword = "123456", --客戶端證書文件密碼[可選] } |
c = socket.tcp()成功則c就是新建的對象。
然后使用mt:connect(address, port, timeout)連接服務(wù)器
參數(shù)
傳入值類型 | 釋義 |
---|---|
string | address 服務(wù)器地址,支持ip和域名 |
param | port string或者number類型,服務(wù)器端口 |
number | 可選參數(shù),默認(rèn)為120 ,timeout 可選參數(shù),連接超時時間,單位秒 |
返回值
bool result true - 成功,false - 失敗 string ,id '0' -- '8' ,返回通道ID編號
mt:表示對象,也就是我們前面通過socket.tcp()新建的c
使用c:connect()即可連接服務(wù)器。
同步方式采用mt:recv(timeout, msg, msgNoResume)這個接口阻塞操作,程序運行到這里會進入等待直到滿足條件才會退出。
參數(shù)
傳入值類型 | 釋義 |
---|---|
number | 可選參數(shù),默認(rèn)為0 ,timeout 可選參數(shù),接收超時時間,單位毫秒 |
string | 可選參數(shù),默認(rèn)為nil ,msg 可選參數(shù),控制socket所在的線程退出recv阻塞狀態(tài) |
bool | 可選參數(shù),默認(rèn)為nil ,msgNoResume 可選參數(shù),控制socket所在的線程退出recv阻塞狀態(tài),false或者nil表示“在recv阻塞狀態(tài),收到msg消息,可以退出阻塞狀態(tài)”,true表示不退出 |
返回值
result 數(shù)據(jù)接收結(jié)果,true表示成功,false表示失敗 data 如果成功的話,返回接收到的數(shù)據(jù);超時時返回錯誤為"timeout";msg控制退出時返回msg的字符串 param 如果是msg返回的false,則data的值是msg,param的值是msg的參數(shù)
以demo的socket\sync\sendInterruptRecv\testSocket.lua為例,r就是result當(dāng)退出原因是服務(wù)器下發(fā)數(shù)據(jù)時為true,其他情況均為false,s是data,當(dāng)r是true的時候,data表示參數(shù),當(dāng)r為false時,data表示退出阻塞的原因,一種是timeout,一種是配置的msg ,當(dāng)值為msg 的時候,p表示msg攜帶的參數(shù)。
while true do r, s, p = c:recv(120000, "pub_msg") if r then recv_cnt = recv_cnt + #s log.info("這是收到的服務(wù)器下發(fā)的數(shù)據(jù)統(tǒng)計:", recv_cnt, "和前30個字節(jié):", s:sub(1, 30)) elseif s == "pub_msg" then send_cnt = send_cnt + #p log.info("這是收到別的線程發(fā)來的數(shù)據(jù)消息!", send_cnt, "和前30個字節(jié)", p:sub(1, 30)) if not c:send(p) then break end elseif s == "timeout" then log.info("這是等待超時發(fā)送心跳包的顯示!") if not c:send("ping") then break end else log.info("這是socket連接錯誤的顯示!") break end end
在連接服務(wù)器成功以后,代碼進入這個死循環(huán),recv(120000, "pub_msg")里的第一個參數(shù)表示最長阻塞時間,這個時間的主要作用是用于心跳維持連接,因為timeout退出阻塞的前提是在這個時間內(nèi)沒有發(fā)送和接收數(shù)據(jù);第二個參數(shù)是控制退出的字符串,其原理類似于sys.subscribe(id, callback)msg就是id,用于訂閱來自其他協(xié)程的數(shù)據(jù),發(fā)送數(shù)據(jù)的方法就是sys.publish(...)觸發(fā)時rev會退出并攜帶參數(shù);
異步采用mt:asyncRecv()接口接收數(shù)據(jù),相對于同步方式,異步的參數(shù)及返回值相對簡單,使用時無需傳遞參數(shù),返回值直接就是收到的數(shù)據(jù)。
使用mt:send(data)接口即可發(fā)送數(shù)據(jù),因為同步方式大多數(shù)時間都是阻塞在接收部分的,所以根據(jù)前文同步接收數(shù)據(jù)的說明可以通過配置msg退出阻塞,然后發(fā)送數(shù)據(jù)。可以參考demo做法。在rev配置msg為pub_msg然后通過其他協(xié)程使用sys.publish向pub_msg發(fā)送數(shù)據(jù),退出阻塞以后直接發(fā)送。
-- 測試代碼,用于發(fā)送消息給socket sys.taskInit(function() while not socket.isReady() do sys.wait(2000) end sys.wait(10000) -- 這是演示用sys.publish()發(fā)送數(shù)據(jù) for i = 1, 10 do sys.publish("pub_msg", string.rep("0123456789", 1024)) sys.wait(500) end end)
異步方式也相對簡單直接使用mt:asyncSend(data)發(fā)送即可。需要說明的一件事是異步方式?jīng)]有timeout所以心跳需要自己維護或者使用mt:asyncSelect(keepAlive, pingreq)配置心跳時間及內(nèi)容。
相關(guān)實例程序在腳本庫的demo\socket文件夾下,包含同步異步以及tcp到串口透傳實例??梢愿鶕?jù)實際需要選擇demo進行研究。
以\script_LuaTask_V2.3.2\demo\socket\sync\sendInterruptRecv目錄的demo作為基礎(chǔ)進行修改。demo中在開機以后進入正式應(yīng)用的一開始使用了一個while進行循環(huán)阻塞判斷。socket.isReady()表示網(wǎng)絡(luò)連接是否可用,可用即為true,不可以為false。
-- tcp test sys.taskInit(function() local r, s, p local recv_cnt, send_cnt = 0, 0 while true do while not socket.isReady() do sys.wait(1000) end c = socket.tcp() while not c:connect(ip, port) do sys.wait(2000) end
有些情況下可能由于欠費等原因設(shè)備socket可能一直不可用,所以可以加一個異常機制,當(dāng)開機以后socket長時間不可用就重啟設(shè)備??梢赃M行如下修改。
--等待網(wǎng)絡(luò)連接的超時時間 local timeout = 90 -- tcp test sys.taskInit( function() local r, s, p local recv_cnt, send_cnt, con_cnt = 0, 0, 0 while true do while not socket.isReady() do sys.wait(1000) if con_cnt == timeout then sys.restart("網(wǎng)絡(luò)初始化失敗!") end con_cnt = con_cnt + 1 end con_cnt = 0
我這里使用的windows系統(tǒng),直接使用網(wǎng)絡(luò)調(diào)試助手作為server,沒有的也可以用http://tcplab.openluat.com/測試。
注意:無論2G還是4G模塊連接的服務(wù)器必須是公網(wǎng)的,局域網(wǎng)ip無法使用 首先通過**socket.tcp()創(chuàng)建一個新的tcp對象,后面的操作都基于這個對象進行。 然后使用c:connect(ip, port)**開始連接,實例程序比較激進如果連接不成功會反復(fù)重試,實際項目中可以選擇連接多少次不成功進入飛行模式重試。
c = socket.tcp() while not c:connect(ip, port) do sys.wait(2000) end
連接成功以后進入死循環(huán),根據(jù)rev的返回條件判斷模塊所處狀態(tài)進行業(yè)務(wù)處理。
while true do r, s, p = c:recv(120000, "pub_msg") if r then recv_cnt = recv_cnt + #s log.info("這是收到的服務(wù)器下發(fā)的數(shù)據(jù)統(tǒng)計:", recv_cnt, "和前30個字節(jié):", s:sub(1, 30)) elseif s == "pub_msg" then send_cnt = send_cnt + #p log.info("這是收到別的線程發(fā)來的數(shù)據(jù)消息!", send_cnt, "和前30個字節(jié)", p:sub(1, 30)) if not c:send(p) then break end elseif s == "timeout" then log.info("這是等待超時發(fā)送心跳包的顯示!") if not c:send("ping") then break end else log.info("這是socket連接錯誤的顯示!") break end end
當(dāng)?shù)谝粋€返回值r是true的時候,數(shù)據(jù)來自服務(wù)器。當(dāng)r非true,s是內(nèi)部消息,這個消息一是來自socket對象內(nèi)部的timeout,當(dāng)timeout成立表示在阻塞的這個時間內(nèi)無消息收發(fā),那么這時候就需要發(fā)送心跳進行?;?,心跳包內(nèi)容可以根據(jù)自己需要寫;當(dāng)s為其他的值的時候就可以從其他線程向socket線程傳遞消息以此達到發(fā)送數(shù)據(jù)的目的,demo使用的是pub_msg,當(dāng)其他線程通過sys.publish接口向pub_msg發(fā)消息的時候socket線程的rev就會退出阻塞,然后根據(jù)s判斷是來自其他線程的消息進行處理,此時p就代表傳遞的消息的參數(shù)。開發(fā)者可以在此次增加消息判斷處理不同消息,例如可以根據(jù)消息主動退出socket連接。通過其他線程發(fā)消息的接口如下面代碼
-- 測試代碼,用于發(fā)送消息給socket sys.taskInit( function() while not socket.isReady() do sys.wait(2000) end sys.wait(10000) -- 這是演示用sys.publish()發(fā)送數(shù)據(jù) for i = 1, 10 do sys.publish("pub_msg", string.rep("0123456789", 1024)) sys.wait(500) end end )
SOCKETAPI說明
相關(guān)開發(fā)板購買鏈接 Air724UG開發(fā)板 Air724 開發(fā)板使用說明
連接服務(wù)器失敗
服務(wù)器必須是公網(wǎng)地址
使用PC上的TCP UDP測試工具客戶端、或者mqtt.fx,連接服務(wù)器確認(rèn)一下是否可以連接成功,排除服務(wù)器故障
如果連接ssl服務(wù)器,確認(rèn)下core文件是否支持ssl功能(例如2G模塊的某些core文件不支持ssl功能)
2G模塊不要使用中國聯(lián)通卡
檢查下模塊信號、網(wǎng)絡(luò)注冊、網(wǎng)絡(luò)附著、PDP激活狀態(tài)
檢查下SIM卡是否欠費【4G模塊有一種欠費表現(xiàn):無法注冊4G網(wǎng)絡(luò),可以注冊2G網(wǎng)絡(luò)】
最多同時支持多少個連接 非ssl的socket最多8個連接,ssl的不超過內(nèi)存即可。
socket異常的情況排查
搜索socket,如果出現(xiàn)socket:connect: core sock conn error或者socket:connect: connect fail,則表示socket連接失敗
搜索socket,如果出現(xiàn)send fail則表示發(fā)送失敗
搜索socket,如果出現(xiàn)socket.rtos.MSG_SOCK_CLOSE_IND則表示socket'被動關(guān)閉
以上是“TCP連接的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。