4G模块连接TCP

作者:如果能编程回忆

最后修改时间:2020年6月12日

概述

Air724模组内置TCP/IP协议栈,提供TCP客户端和服务器端服务(PS:模块没有公网IP所以服务端模式多用于专属VPN网络)。可使用AT指令,LUAT二次开发,CSDK,开源DTU等多种方式开发,开发者根据实际需求合理选择开发方式。

AT指令

通过AT指令使用TCP服务主要包含设备联网,配置连接,建立连接,发送数据等步骤,具体流程如图高清版TCP流程图.pdf

![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAyMC9qcGVnLzE1OTAyMDgvMTU5MTk0Mjc0OTQ2OC03MDI1Y2FkZC02NGJjLTRhZmItOGQwZS1jMTlmZWNjMmI4MTEuanBlZw?x-oss-process=image/format,png#align=left&display=inline&height=964&margin=[object Object]&originHeight=964&originWidth=648&size=0&status=done&style=none&width=648)

从连接方式上可分为SSL与非SSL,从连接路数可分为单路连接和多路连接,从数据收发方式可分为透传与非透传。

连接网络

开机

通过拉低powerkey2秒进行开机,开机以后通过串口循环发送AT直到收到OK,如果90秒没有收到OK请拉低 RESET_IN_N 引脚 150ms 以上。或使用其他方法见开关机章节

查询卡状态

AT+CPIN?查询卡状态,直到收到+CPIN: READY,如果10s内没有收到建议重启模块

查询网络注册情况

AT+CGATT?查询是否注册网络收到+CGATT: 1值是1即为注册成功,正常情况下注册时间不会超过两分钟,如果超过两分钟没有注册可以进入飞行模式五秒后退出再查询,或者直接重启模块。

激活网络

AT+CSTT配置网络,非私有APN以外Cat1的固件支持根据卡自动配置APN,直接输入AT+CSTT即可,模块会按照自动获取的APN设置CSTT的APN。

AT+CIICR激活网络,在IP START的状态使用AT+CIICR激活网络,激活以后通过AT+CIFSR查询是否获取IP,如果成功就可以开始配置TCP连接了,如果不成功使用AT+CIPSHUT关闭移动网络,从AT+CSTT重新进行。

连接TCP

此处使用的是非SSL连接,SSL见相关章节

AT+CIPSTART建立连接

命令类型语法返回和说明
设置命令单 路 连 接 (+CIPMUX=0)时:AT+CIPSTART=,, 或 AT+CIPSTART=,,
多路连接(+CIPMUX=1)时:AT+CIPSTART=,,< IP address>, 或 AT+CIPSTART=,,,如 果 格 式 正 确 且 处 于 IP INITIAL 或 者 IP STATUS或TCP/UDP CLOSE状态,返回: OK 否则返回: +CME ERROR

紧接着会有URC上报,上报内容如下:
如果连接已经存在,返回: ALREADY CONNECT
如果连接成功(非透传),返回: CONNECT OK 如果连接成功(透传),返回: CONNECT
否则返回: STATE: <sl_state>
CONNECT FAIL如果格式正确且处于 IP STATUS或IP PROCESSING时,返回: OK 否则返回: +CME ERROR
紧接着会有URC上报,上报内容如下:
如果连接已经存在, 返回: ,ALREADY CONNECT
如果连接成功,返回: ,CONNECT OK 否则返回: ,CONNECT FAIL |
| 测试命令 | AT+CIPSTART=? | 单路连接(+CIPMUX=0)时返回: +CIPSTART: (取值列表),(IP address range),(port range)? +CIPSTART: (取值列表),(domain name),(port range)
OK 多路连接(+CIPMUX=1)时返回: +CIPSTART: ( 取 值 列 表 ),( 取 值 列 表 ),(IP addressrange),(port range) +CIPSTART: (取值列表),( 取值 列表),(domain name),(portrange)
OK |
| 注意事项 | 此命令应用于建立 TCP/UDP 连接;
当前状态可用 AT+CIPSTATUS 查询;
单路连接时只当前状态为 IP INITIAL 或者 IP STATUS 或 TCP/UDP CLOSE 时可执行,多路连接时当 前状态为 IP STATUS 或 IP PROCESSING 时可执行;
在当前状态不是上述可执行状态时,需执行 AT+CIPSHUT 后再开始建立连接;
多路连接时,设置此命令前,必须先执行 AT+CSTT, AT+CIICR,AT+CIFSR 这三个命令。 |
|

参数定义

参数参数取值对取值的说明
Link No.0~5整数型,表示连接序号
连接类型,字符串型
(双引号可加可不加)“TCP”
“UDP”建立TCP连接
建立UDP连接
远端服务器 IP 地址最大32个字节字符串参数(双引号可加可不加)
远端服务器域名最大 32 个字节字符串参数(双引号可加可不加)
远端服务端口1~65535整数型

示例

AT+CIPSTART=“TCP”,“120.76.201.131”,2000

返回

CONNECT OK表示连接成功

发送数据

AT+CIPSEND发送不定长数据,收到>以后就可以发送数据,然后发送十六进制1A结束发送,发送完1A以后设备会向服务器发送1A之前的所有数据。

接收数据

当连接服务器成功以后默认配置是服务器下发的数据会通过串口自动上报,直接就可以接收数据。

状态机

![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAyMC9wbmcvMTU5MDIwOC8xNTkxOTQyNzQ5NDc3LTQzYzhiZWMwLTE4MzItNDg1ZS1hNmVkLWQ4OTgwODM2YWFlMy5wbmc?x-oss-process=image/format,png#align=left&display=inline&height=416&margin=[object Object]&originHeight=416&originWidth=736&size=0&status=done&style=none&width=736)

◆输入 AT+CIICR,会马上进入 IPCONFIG 状态,当返回 OK 后,会进入到 IPGPRSACT 状态;

◆输入 AT+CIPSTART 后,会立马进入 IP/UDPCONNECTING 状态,如果后续模块上报 CONNECTOK 这个 URC,
表明连接服务器成功,此时进入 CONNECTOK 状态;

◆输入 AT+CIPCLOSE 后,立马进入 TCP/UDPCLOSING 状态,此时如果模块上报 CLOSEOK,则表明关闭与服务 器的连接成功,此时模块进入 TCP/UDPCLOSED 状态;

◆如果模块上报+PDPDEACT 这个 URC,则标志着模块释放 PDP 上下文,并进入了 PDPDEACT 状态;

◆在 IPGPRSACT,IPSTATUS,CONNECT OK 以及 TCP/UDPCLOSED 状态下,输入 AT+CGATT=0,则也可以使模 块释放上下文,进入 PDPDEACT 状态;

◆模块进入 PDPDEACT 状态,仍需要输入 AT+CIPSHUT,进入 IPINITIAL 状态; ◆模块在各个状态下均可以输入 AT+CIPSHUT,进入 IPINITIAL 状态。

其他说明

最新的AT固件支持开机直接发送AT+CIPSTART联网,不过不推荐使用,推荐根据状态机一步一步实现

LUAT

luat连接相比AT更为简单,只需要简单的配置即可连接,还可以灵活的对数据进行处理。

需要从官网或者github下载luatask的脚本包,或者使用luatoolsv2会自动下载脚本资源,在工具根目录的\resource\8910_script中脚本资源会随官网同步更新,具体版本可能和本文不同,不过功能都是一致的。

文档中用到的API接口见wiki的API章节。

在脚本目录的demo/socket文件夹里有两种示例代码,async是异步socket,sync是同步socket

同步:

同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。

异步:

将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。

同步和异步本身是相对的

同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户使用起来会有不友好。

异步就是,当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。

存在就有其道理 异步虽然好 但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据在进行操作的。这些是异步所无法解决的。

所以请根据实际需求选择。

连接服务器

luat的socket操作是一个面向对象的操作所以首先使用socket.tcp(ssl, cert)创建一个对象

传入值类型释义
bool可选参数,默认为nil,ssl,是否为ssl连接,true表示是,其余表示否
table可选参数,默认为nil,cert,ssl连接需要的证书配置,只有ssl参数为true时,才参数才有意义,cert格式如下: { caCert = “ca.crt”, --CA证书文件(Base64编码 X.509格式),如果存在此参数,则表示客户端会对服务器的证书进行校验;不存在则不校验 clientCert = “client.crt”, --客户端证书文件(Base64编码 X.509格式),服务器对客户端的证书进行校验时会用到此参数 clientKey = “client.key”, --客户端私钥文件(Base64编码 X.509格式) clientPassword = “123456”, --客户端证书文件密码[可选] }

c = socket.tcp()成功则c就是新建的对象。

然后使用mt:connect(address, port, timeout)连接服务器

  • 参数
    | 传入值类型 | 释义 |
    | — | — |
    | string | address 服务器地址,支持ip和域名 |
    | param | port string或者number类型,服务器端口 |
    | number | 可选参数,默认为120,timeout 可选参数,连接超时时间,单位秒 |

  • 返回值

bool result true - 成功,false - 失败 string ,id ‘0’ – ‘8’ ,返回通道ID编号

mt:表示对象,也就是我们前面通过socket.tcp()新建的c

使用c:connect()即可连接服务器。

接收数据

同步方式

同步方式采用mt:recv(timeout, msg, msgNoResume)这个接口阻塞操作,程序运行到这里会进入等待直到满足条件才会退出。

  • 参数
    | 传入值类型 | 释义 |
    | — | — |
    | number | 可选参数,默认为0,timeout 可选参数,接收超时时间,单位毫秒 |
    | string | 可选参数,默认为nil,msg 可选参数,控制socket所在的线程退出recv阻塞状态 |
    | bool | 可选参数,默认为nil,msgNoResume 可选参数,控制socket所在的线程退出recv阻塞状态,false或者nil表示“在recv阻塞状态,收到msg消息,可以退出阻塞状态”,true表示不退出 |

  • 返回值

result 数据接收结果,true表示成功,false表示失败 data 如果成功的话,返回接收到的数据;超时时返回错误为"timeout";msg控制退出时返回msg的字符串 param 如果是msg返回的false,则data的值是msg,param的值是msg的参数

以demo的socket\sync\sendInterruptRecv\testSocket.lua为例,r就是result当退出原因是服务器下发数据时为true,其他情况均为false,s是data,当r是true的时候,data表示参数,当r为false时,data表示退出阻塞的原因,一种是timeout,一种是配置的msg ,当值为msg 的时候,p表示msg携带的参数。

while true do
            r, s, p = c:recv(120000, "pub_msg")
            if r then
                recv_cnt = recv_cnt + #s
                log.info("这是收到的服务器下发的数据统计:", recv_cnt, "和前30个字节:", s:sub(1, 30))
            elseif s == "pub_msg" then
                send_cnt = send_cnt + #p
                log.info("这是收到别的线程发来的数据消息!", send_cnt, "和前30个字节", p:sub(1, 30))
                if not c:send(p) then break end
            elseif s == "timeout" then
                log.info("这是等待超时发送心跳包的显示!")
                if not c:send("ping") then break end
            else
                log.info("这是socket连接错误的显示!")
                break
            end
        end

在连接服务器成功以后,代码进入这个死循环,recv(120000, “pub_msg”)里的第一个参数表示最长阻塞时间,这个时间的主要作用是用于心跳维持连接,因为timeout退出阻塞的前提是在这个时间内没有发送和接收数据;第二个参数是控制退出的字符串,其原理类似于sys.subscribe(id, callback)msg就是id,用于订阅来自其他协程的数据,发送数据的方法就是sys.publish(…)触发时rev会退出并携带参数;

异步方式

异步采用mt:asyncRecv()接口接收数据,相对于同步方式,异步的参数及返回值相对简单,使用时无需传递参数,返回值直接就是收到的数据。

发送数据

同步方式

使用mt:send(data)接口即可发送数据,因为同步方式大多数时间都是阻塞在接收部分的,所以根据前文同步接收数据的说明可以通过配置msg退出阻塞,然后发送数据。可以参考demo做法。在rev配置msg为pub_msg然后通过其他协程使用sys.publish向pub_msg发送数据,退出阻塞以后直接发送。

-- 测试代码,用于发送消息给socket
sys.taskInit(function()
    while not socket.isReady() do sys.wait(2000) end
    sys.wait(10000)
    -- 这是演示用sys.publish()发送数据
    for i = 1, 10 do
        sys.publish("pub_msg", string.rep("0123456789", 1024))
        sys.wait(500)
    end
end)

异步方式

异步方式也相对简单直接使用mt:asyncSend(data)发送即可。需要说明的一件事是异步方式没有timeout所以心跳需要自己维护或者使用mt:asyncSelect(keepAlive, pingreq)配置心跳时间及内容。

CSDK

csdk请参考demo目录下的demo_socket.c

相关教程可见csdk的tcp教程

DTU固件

对于只需要使用模块进行透传数据的常见,推荐使用合宙开源的dtu固件,只需要一条指令就可实现网络连接和服务器状态维护,还可使用web配置参数,方便又简单。

相关教程

SmartDTU 是集成远程物联网控制功能的固件,只需要配置几下就可以实现大部分场景所需要的功能和逻辑,方便传统业务快速联网。手册和固件下载在群文件!
WEB配置:http://dtu.openluat.com
注意:请用chrome或firefox等兼容浏览器。如果联网请求参数失败,请把ERP账号和IMEI给我添加。SmartDTU是什么:https://ask.openluat.com/article/997
B站教程:https://www.bilibili.com/video/av41012302
硬件教程:https://www.bilibili.com/video/av45341487
工具教程:https://www.bilibili.com/video/av50453083
Luat开发教程:https://www.bilibili.com/video/av50827315
看懂Luat日志:https://ask.openluat.com/article/15
源码:https://gitee.com/hotdll/iRTU

©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页