本示例实现的功能是:基于TCP的socket透传demo项目,uart1透传数据到指定服务器。

功能描述:

1、数据网络准备就绪后,连接后台

2、连接成功后,循环“读取mcu通过串口发送过来的数据,每次最多发送1K字节”

3、与后台保持长连接,断开后主动再去重连,连接成功仍然按照第2条发送数据

4、收到后台的数据时,在rcv函数中打印出来,并且通过串口透传给mcu

测试时请搭建自己的服务器,并且修改下面的PROT,ADDR,PORT,支持域名和IP地址

此例子为长连接,只要是软件上能够检测到的网络异常,可以自动去重新连接

1.本功能需要socket和uart两个模块,所以分为两个文件来实现。实现sockt功能,在编辑工具建立一个sck.lua的文件(不一定叫这个名字,用户可以自己随便取名)

2.设置本文件被全体可见。也就意味着,一旦test被某一文件加载,则test在任何文件中均可被看见,即test中全局变量和函数均可被任何文件调用。

module(...,package.seeall)

3.test文件头需要 require "xxx" 模块。加载后,就可以调用xxx.lua库文件中的全局变量和函数了

require"socket"

4.定义print函数,调试用

local function print(...)

_G.print("sck",...)

end

5.定义相关参数

local ssub,schar,smatch,sbyte,slen = string.sub,string.char,string.match,string.byte,string.len

--测试时请搭建自己的服务器

local SCK_IDX,PROT,ADDR,PORT = 1,"TCP","120.26.196.195",9999

--linksta:与后台的socket连接状态

local linksta

--一个连接周期内的动作:如果连接后台失败,会尝试重连,重连间隔为RECONN_PERIOD秒,最多重连RECONN_MAX_CNT次

--如果一个连接周期内都没有连接成功,则等待RECONN_CYCLE_PERIOD秒后,重新发起一个连接周期

--如果连续RECONN_CYCLE_MAX_CNT次的连接周期都没有连接成功,则重启软件

local RECONN_MAX_CNT,RECONN_PERIOD,RECONN_CYCLE_MAX_CNT,RECONN_CYCLE_PERIOD = 3,5,3,20

--reconncnt:当前连接周期内,已经重连的次数

--reconncyclecnt:连续多少个连接周期,都没有连接成功

--一旦连接成功,都会复位这两个标记

--conning:是否在尝试连接

local reconncnt,reconncyclecnt,conning = 0,0

--正在发送的数据

local sndingdata = ""

6.创建到后台服务器的连接

--[[创建到后台服务器的连接;

如果数据网络已经准备好,会理解连接后台;否则,连接请求会被挂起,等数据网络准备就绪后,自动去连接后台 ntfy:socket状态的处理函数

rcv:socket接收数据的处理函数]]--

function connect()

socket.connect(SCK_IDX,PROT,ADDR,PORT,ntfy,rcv)

conning = true

end

7.socket状态的处理函数

--[[

函数名:ntfy

功能 :socket状态的处理函数

参数 :

idx:number类型,socket.lua中维护的socket idx,跟调用socket.connect时传入的第一个参数相同,程序可以忽略不处理

evt:string类型,消息事件类型

result: bool类型,消息事件结果,true为成功,其他为失败

item:table类型,{data=,para=},消息回传的参数和数据,目前只是在SEND类型的事件中用到了此参数,例如调用socket.send时传入的第2个和第3个参数分别为dat和par,则item={data=dat,para=par}

返回值:无

]]

function ntfy(idx,evt,result,item)

print("ntfy",evt,result,item)

--连接结果(调用socket.connect后的异步事件)

if evt == "CONNECT" then

conning = false

--连接成功

if result then

reconncnt,reconncyclecnt,linksta = 0,0,true

--停止重连定时器

sys.timer_stop(reconn)

--发送mcu通过串口传过来的数据到后台

sndmcuartdata()

--连接失败

else

--RECONN_PERIOD秒后重连

sys.timer_start(reconn,RECONN_PERIOD*1000)

end

--数据发送结果(调用socket.send后的异步事件)

elseif evt == "SEND" then

if item then

sndcb(item,result)

end

--发送失败,RECONN_PERIOD秒后重连后台,不要调用reconn,此时socket状态仍然是CONNECTED,会导致一直连不上服务器

--if not result then sys.timer_start(reconn,RECONN_PERIOD*1000) end

if not result then link.shut() end

--连接被动断开

elseif evt == "STATE" and result == "CLOSED" then

linksta = false

reconn()

--连接主动断开(调用link.shut后的异步事件)

elseif evt == "STATE" and result == "SHUTED" then

linksta = false

reconn()

--连接主动断开(调用socket.disconnect后的异步事件)

elseif evt == "DISCONNECT" then

linksta = false

reconn()

end

--其他错误处理,断开数据链路,重新连接

if smatch((type(result)=="string") and result or "","ERROR") then

--RECONN_PERIOD秒后重连,不要调用reconn,此时socket状态仍然是CONNECTED,会导致一直连不上服务器

--sys.timer_start(reconn,RECONN_PERIOD*1000)

link.shut()

end

end

--[[

函数名:rcv

功能 :socket接收数据的处理函数

参数 :

idx :socket.lua中维护的socket idx,跟调用socket.connect时传入的第一个参数相同,程序可以忽略不处理

data:接收到的数据

返回值:无

]]

function rcv(idx,data)

print("rcv",slen(data)>200 and slen(data) or data)

--抛出SVR_TRANSPARENT_TO_MCU消息,携带socket收到的数据

sys.dispatch("SVR_TRANSPARENT_TO_MCU",data)

end

8.发送函数,sndmcuartdata()的具体实现,以及对应的回调函数。

--[[

函数名:snd

功能 :调用发

送接口发送数据

参数 :

data:发送的数据,在发送结果事件处理函数ntfy中,会赋值到item.data中

para:发送的参数,在发送结果事件处理函数ntfy中,会赋值到item.para中

返回值:调用发送接口的结果(并不是数据发送是否成功的结果,数据发送是否成功的结果在ntfy中的SEND事件中通知),true为成功,其他为失败

]]

function snd(data,para)

return socket.send(SCK_IDX,data,para)

end

--[[

函数名:sndmcuartdata

功能 :如果还有等待发送的mcu通过串口传过来的数据,则继续发送

参数 :无

返回值:无

]]

local function sndmcuartdata()

if sndingdata=="" then

sndingdata = mcuart.resumesndtosvr()

end

if linksta and sndingdata~="" then snd(sndingdata,"TRANSPARENT") end

end

--[[

函数名:sndcb

功能 :数据发送结果处理

参数 :

item:table类型,{data=,para=},消息回传的参数和数据,例如调用socket.send时传入的第2个和第3个参数分别为dat和par,则item={data=dat,para=par}

result: bool类型,发送结果,true为成功,其他为失败

返回值:无

]]

local function sndcb(item,result)

print("sndcb",item.para,result)

if not item.para then return end

if item.para=="TRANSPARENT" then

--发送成功,继续发送下包数据

if result then

sndingdata = ""

--sys.dispatch("SND_TO_SVR_CNF",true)

sndmcuartdata()

end

end

end

9.断线自动重连

--[[

函数名:reconn

功能 :重连后台处理

一个连接周期内的动作:如果连接后台失败,会尝试重连,重连间隔为RECONN_PERIOD秒,最多重连RECONN_MAX_CNT次

如果一个连接周期内都没有连接成功,则等待RECONN_CYCLE_PERIOD秒后,重新发起一个连接周期

如果连续RECONN_CYCLE_MAX_CNT次的连接周期都没有连接成功,则重启软件

参数 :无

返回值:无

]]

local function reconn()

print("reconn",reconncnt,conning,reconncyclecnt)

--conning表示正在尝试连接后台,一定要判断此变量,否则有可能发起不必要的重连,导致reconncnt增加,实际的重连次数减少

if conning then return end

--一个连接周期内的重连

if reconncnt = RECONN_CYCLE_MAX_CNT then

sys.restart("connect fail")

end

sys.timer_start(reconn,RECONN_CYCLE_PERIOD*1000)

end

end

10.定时器启动connect()函数以及消息注册

connect()

--消息处理函数列表

local procer =

{

SND_TO_SVR_REQ = sndmcuartdata,

}

--注册消息处理函数列表

sys.regapp(procer)

11.实现uart功能,在编辑工具建立一个mcuart.lua的文件(不一定叫这个名字,用户可以自己随便取名),同理参照2,3,4步骤。

module(...,package.seeall)

require"pm"

local function print(...)

_G.print("mcuart",...)

end

12.定义相关参数

--串口ID,1对应uart1

local UART_ID = 1

--SND_UNIT_MAX:每次发送最大的字节数,只要累积收到的数据大于等于这个最大字节数,并且没有正在发送数据到后台,则立即发送前SND_UNIT_MAX字节数据给后台

--SND_DELAY:每次串口收到数据时,重新延迟SND_DELAY毫秒后,没有收到新的数据,并且没有正在发送数据到后台,则立即发送最多前SND_UNIT_MAX字节数据给后台

--这两个变量配合使用,只要任何一个条件满足,都会触发发送动作

--例如:SND_UNIT_MAX,SND_DELAY = 1024,1000,有如下几种情况

--串口收到了500字节数据,接下来的1000毫秒没有收到数据,并且没有正在发送数据到后台,则立即发送这500字节数据给后台

--串口收到了500字节数据,800毫秒后,又收到了524字节数据,此时没有正在发送数据到后台,则立即发送这1024字节数据给后台

local SND_UNIT_MAX,SND_DELAY = 1024,1000

--sndingtosvr:是否正在发送数据到后台

local sndingtosvr

--unsndbuf:还没有发送的数据

--sndingbuf:正在发送的数据

local readbuf--[[,sndingbuf]] = ""--[[,""]]

13.串口发送数据

--s:要发送的数据

function write(s)

print("write",s)

uart.write(UART_ID,s)

end

14.读取串口接收到的数据

--通知数据发送功能模块,串口数据已准备好,可以发送

local function sndtosvr()

--print("sndtosvr",sndingtosvr)

if not sndingtosvr then

sys.dispatch("SND_TO_SVR_REQ")

end

end

--[[

函数名:proc

功能 :处理串口接收到的数据

参数 :

data:当前一次读取到的串口数据

返回值:无

]]

local function proc(data)

if not data or string.len(data) == 0 then return end

--追加到未发送数据缓冲区末尾

readbuf = readbuf..data

if string.len(readbuf)>=SND_UNIT_MAX then sndtosvr() end

sys.timer_start(sndtosvr,SND_DELAY)

end

--读取串口接收到的数据

local function read()

local data = ""

--底层core中,串口收到数据时:

--如果接收缓冲区为空,则会以中断方式通知Lua脚本收到了新数据;

--如果接收缓冲器不为空,则不会通知Lua脚本

--所以Lua脚本中收到中断读串口数据时,每次都要把接收缓冲区中的数据全部读出,这样才能保证底层core中的新数据中断上来,此read函数中的while语句中就保证了这一点

while true do

data = uart.read(UART_ID,"*l",0)

if not data or string.len(data) == 0 then break end

--print("read",string.len(data)--[[data,common.binstohexs(data)]])

proc(data)

end

end

15.消息注册处理

--消息处理函数列表

local procer =

{

SVR_TRANSPARENT_TO_MCU = write,

--SND_TO_SVR_CNF = sndcnf,

}

--注册消息处理函数列表

sys.regapp(procer)

--保持系统处于唤醒状态,不会休眠

pm.wake("mcuart")

--注册串口的数据接收函数,串口收到数据后,会以中断方式,调用read接口读取数据

sys.reguart(UART_ID,read)

--配置并且打开串口

uart.setup(UART_ID,9600,8,uart.PAR_NONE,uart.STOP_1)

16.在编辑工具中建立一个名为main.lua的文件。lua脚本的执行从main.lua开始,main.lua是入口文件(注意:main.lua只能有一个)。在main.lua中把test加载进去就好了。sys.init()是对系统初始化,sys.run()是系统主程序。这两句必须有。

--重要提醒:必须在这个位置定义MODULE_TYPE、PROJECT和VERSION变量

--MODULE_TYPE:模块型号,目前仅支持Air201、Air202、Air800

--PROJECT:ascii string类型,可以随便定义,只要不使用,就行

--VERSION:ascii string类型,如果使用Luat物联云平台固件升级的功能,必须按照"X.X.X"定义,X表示1位数字;否则可随便定义

MODULE_TYPE = "Air202"

PROJECT = "SOCKET_LONG_CONNECTION_TRANSPARENT"

VERSION = "1.0.0"

require"sys"

require"mcuart"

require"sck"

if MODULE_TYPE=="Air201" then

require"wdt"

end

sys.init(0,0)

sys.run()

!!!attention

一个工程只有一个main.lua

luat c语言开发例程,Luat实例教程:tcp透传相关推荐

  1. AutoCAD ObjectARX(VC)开发基础与实例教程2014版光盘镜像

    AutoCAD ObjectARX(VC)开发基础与实例教程2014,最新版,光盘镜像 作者:张帆 朱文俊 编著 出版社:中国电力出版社 出版时间:2014年6月 点击一下 转载于:https://w ...

  2. yum安装ruby_CentOS 7下配置Ruby语言开发环境的方法教程

    本文跟大家分享的是在CentOS 7下配置Ruby语言开发环境的方法教程,分享出来供大家参考学习,下面来看看详细的介绍: 安装Ruby 2.2 CentOS7存储库中的Ruby版本为2.0,但如果需要 ...

  3. ObjectArx(VC)开发基础及实例教程-源码链接

    <ObjectArx(VC)开发基础及实例教程>的光盘 https://gitee.com/Presscad/ObjectArcVC

  4. python开发游戏教程_Python开发星际游戏实例教程

    这篇文章主要为大家详细介绍了Python外星人入侵游戏编程完整的实现思路,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 PYTHON游戏编程外星人入侵的完整实现思路,具体内容如下 准备工作:下载p ...

  5. 1 Go语言开发环境搭建详细教程+go常见bug合集【Go语言教程】

    Go语言开发环境搭建[Win.Linux.Mac] 1 SDK下载 官网地址:golang.org,因为一些原因国内可能无法访问.可以使用下面第二个链接. 国内地址访问:https://golang. ...

  6. 使用vs2008c++语言开发activex控件教程,使用VS2010 C#开发ActiveX控件(上)

    要开发Web版的读卡程序,大体思路如下: 1.使用C#对原始的Dll进行封装,这里要封装两部分内容,一部分是串口通信的功能,一部分是对卡读写的功能. 2.开发ActiveX控件调用封装后的Dll,使用 ...

  7. 使用vs2008c++语言开发activex控件教程,使用VS2008C 开发ActiveX控件.pdf

    使用VS2008C 开发ActiveX控件 VS2008 C#ActiveX VS2008 C#ActiveX VVSCC##AAccttiivveeXX控件开发总结 ------EagleInSky ...

  8. 使用vs2008c++语言开发activex控件教程,使用VS2008C_开发ActiveX控件.pdf

    VS2008 C#ActiveX VS2008 C#ActiveX VVSCC##AAccttiivveeXX控件开发总结 ------EagleInSky ------2010-1-13 一. 前言 ...

  9. java开发cms视频教程下载地址_Java + MySQL 开发CMS系统实例教程

    cms 教程列表: [李腾飞-领航致远]cms_050-利用MyBatis来实现对Article对象的插入操作 [李腾飞-领航致远]cms_048-MyBatis基本例子的演示之三:如何使用MyBat ...

最新文章

  1. mybatis中的resultMap与resultType、parameterMap与 parameterType的区别
  2. synchronized与Lock的区别与使用
  3. python学完可以干啥-Python学完可以做什么
  4. C字节对齐与C++类对象内存布局
  5. 【计算机网络】因特网结构
  6. “一张图”解释特色小镇发展历程
  7. 开发者论坛一周精粹(第十七期) :【漏洞预警】Windows再被爆SMB服务0day漏洞,阿里云提示您关注并修复...
  8. Intel Sandy Bridge/Ivy Bridge架构/微架构/流水线 (2) - 流水线概述框图
  9. vim - multiple windows
  10. 放弃 802.11 命名方式,Wi-Fi 6 标准公布,速度快 37%
  11. HDU1290 重建希望小学【递推+打表】
  12. C语言经典例题(菜鸟教程100例)
  13. Embarcadero.ERStudio安装
  14. “敬老孝亲颂家风 做美德传承人”主题实践
  15. python是一种语言吗-python是一种什么类型的语言
  16. Groovy Xml解析
  17. Voyager下的Dashboard Widgets
  18. [ERP]IQC,IPQC,PQC,FQC,OQC是什么意思?是干什么的?
  19. meng-科学计算包-numpy
  20. Unity如何驱动打印机打印

热门文章

  1. js文字转图片,使用画布绘制
  2. linux rm、rm -f、rm -r的区别
  3. 信息安全工程师学习笔记《第四章》
  4. ChatGPT聊天机器人如何发图片????
  5. JS中出现三个点(...)的作用是什么
  6. Android全面屏最大纵横比适配
  7. 利用cobaltstrike加sqlmap拿下一个网站并提权
  8. EDIUS和Premiere两款视频剪辑软件哪个好
  9. app,h5落地页实现跳转快应用,可用于抖音,快手,头条投放链接
  10. 你不知道的水浒好汉,在这里!