小編給大家分享一下TCP連接的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

創(chuàng)新互聯(lián)建站作為成都網(wǎng)站建設(shè)公司,專注網(wǎng)站建設(shè)公司、網(wǎng)站設(shè)計,有關(guān)企業(yè)網(wǎng)站設(shè)計方案、改版、費用等問題,行業(yè)涉及水電改造等多個領(lǐng)域,已為上千家企業(yè)服務(wù),得到了客戶的尊重與認(rèn)可。
luat連接相比AT更為簡單,只需要簡單的配置即可連接,還可以靈活的對數(shù)據(jù)進(jìn)行處理。
需要從官網(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ìn)行操作的。這些是異步所無法解決的。
所以請根據(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ù)器的證書進(jìn)行校驗;不存在則不校驗 clientCert = "client.crt", --客戶端證書文件(Base64編碼 X.509格式),服務(wù)器對客戶端的證書進(jìn)行校驗時會用到此參數(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)這個接口阻塞操作,程序運行到這里會進(jìn)入等待直到滿足條件才會退出。
參數(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ù)器成功以后,代碼進(jìn)入這個死循環(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所以心跳需要自己維護(hù)或者使用mt:asyncSelect(keepAlive, pingreq)配置心跳時間及內(nèi)容。
相關(guān)實例程序在腳本庫的demo\socket文件夾下,包含同步異步以及tcp到串口透傳實例。可以根據(jù)實際需要選擇demo進(jìn)行研究。
以\script_LuaTask_V2.3.2\demo\socket\sync\sendInterruptRecv目錄的demo作為基礎(chǔ)進(jìn)行修改。demo中在開機以后進(jìn)入正式應(yīng)用的一開始使用了一個while進(jìn)行循環(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è)備。可以進(jìn)行如下修改。
--等待網(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對象,后面的操作都基于這個對象進(jìn)行。 然后使用c:connect(ip, port)**開始連接,實例程序比較激進(jìn)如果連接不成功會反復(fù)重試,實際項目中可以選擇連接多少次不成功進(jìn)入飛行模式重試。
c = socket.tcp() while not c:connect(ip, port) do sys.wait(2000) end
連接成功以后進(jìn)入死循環(huán),根據(jù)rev的返回條件判斷模塊所處狀態(tài)進(jìn)行業(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ā)送心跳進(jìn)行保活,心跳包內(nèi)容可以根據(jù)自己需要寫;當(dāng)s為其他的值的時候就可以從其他線程向socket線程傳遞消息以此達(dá)到發(fā)送數(shù)據(jù)的目的,demo使用的是pub_msg,當(dāng)其他線程通過sys.publish接口向pub_msg發(fā)消息的時候socket線程的rev就會退出阻塞,然后根據(jù)s判斷是來自其他線程的消息進(jìn)行處理,此時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)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
新聞名稱:TCP連接的示例分析
網(wǎng)站鏈接:http://www.chinadenli.net/article24/piioje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、微信小程序、自適應(yīng)網(wǎng)站、網(wǎng)站排名、服務(wù)器托管、微信公眾號
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)