溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

TCP連接的示例分析

發(fā)布時間:2021-12-30 16:58:36 來源:億速云 閱讀:154 作者:小新 欄目:互聯(lián)網(wǎng)科技

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

1 概述

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ù)實際需求選擇。

2 API說明

2.1 連接服務(wù)器

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ù)

傳入值類型釋義
stringaddress 服務(wù)器地址,支持ip和域名
paramport 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ù)器。

2.2 接收數(shù)據(jù)

2.2.1 同步方式

同步方式采用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ù);

2.2.2 異步方式

異步采用mt:asyncRecv()接口接收數(shù)據(jù),相對于同步方式,異步的參數(shù)及返回值相對簡單,使用時無需傳遞參數(shù),返回值直接就是收到的數(shù)據(jù)。

2.3 發(fā)送數(shù)據(jù)

2.3.1 同步方式

使用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)

2.3.2 異步方式

異步方式也相對簡單直接使用mt:asyncSend(data)發(fā)送即可。需要說明的一件事是異步方式?jīng)]有timeout所以心跳需要自己維護或者使用mt:asyncSelect(keepAlive, pingreq)配置心跳時間及內(nèi)容。

3 luat示例程序

相關(guān)實例程序在腳本庫的demo\socket文件夾下,包含同步異步以及tcp到串口透傳實例??梢愿鶕?jù)實際需要選擇demo進行研究。

3.1 開機與連接網(wǎng)絡(luò)

以\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

3.2 連接服務(wù)器

我這里使用的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ù)處理。

3.3 socket發(fā)送與接收消息

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
)

4 相關(guān)資料以及購買鏈接

SOCKETAPI說明

相關(guān)開發(fā)板購買鏈接 Air724UG開發(fā)板 Air724 開發(fā)板使用說明

5 常見問題

  1. 連接服務(wù)器失敗

    1. 服務(wù)器必須是公網(wǎng)地址

    2. 使用PC上的TCP UDP測試工具客戶端、或者mqtt.fx,連接服務(wù)器確認(rèn)一下是否可以連接成功,排除服務(wù)器故障

    3. 如果連接ssl服務(wù)器,確認(rèn)下core文件是否支持ssl功能(例如2G模塊的某些core文件不支持ssl功能)

    4. 2G模塊不要使用中國聯(lián)通卡

    5. 檢查下模塊信號、網(wǎng)絡(luò)注冊、網(wǎng)絡(luò)附著、PDP激活狀態(tài)

    6. 檢查下SIM卡是否欠費【4G模塊有一種欠費表現(xiàn):無法注冊4G網(wǎng)絡(luò),可以注冊2G網(wǎng)絡(luò)】

  2. 最多同時支持多少個連接 非ssl的socket最多8個連接,ssl的不超過內(nèi)存即可。

  3. socket異常的情況排查

    1. 搜索socket,如果出現(xiàn)socket:connect: core sock conn error或者socket:connect: connect fail,則表示socket連接失敗

    2. 搜索socket,如果出現(xiàn)send fail則表示發(fā)送失敗

    3. 搜索socket,如果出現(xiàn)socket.rtos.MSG_SOCK_CLOSE_IND則表示socket'被動關(guān)閉

以上是“TCP連接的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(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)容。

tcp
AI