LuatOS 多网卡设备模式和路由模式
作者:魏健强 | 最后修改:2026-03-17
Hello,大家好,我是魏健强。
欢迎大家来到合宙 LuatOS 直播课堂,一起学习 LuatOS 课程。
第一部分:LuatOS 课程背景
因为今天是我们 LuatOS 系列课程的第十二讲,所以在这里我就不重复讲解整个 LuatOS 课程的背景了; 如果您还不清楚 LuatOS 课程背景,可以访问:LuatOS 课程背景 这个链接,进行了解;
第二部分:LuatOS 网卡课程讲哪些内容
本课程主要包含以下五个部分: 1.网卡相关理论基础 2.相关核心概念讲解 3.api 详解 4.应用 5.问题分析与解决
第三部分:网卡相关理论基础部分
3.1 TCP/IP
IP 协议:互联网的“邮政编码系统”
更详细的内容可以查看第三部分:TCP/IP 总体介绍
你可以把互联网想象成一个全球性的邮政系统。如果你要给另一个城市的朋友寄一封信,你需要:
IP 协议就是这个系统中的“地址系统”,它负责解决一个最根本的问题:如何把数据从一台设备准确送到另一台设备?
想象一栋巨大的办公楼(一台服务器或你的设备),它有唯一的街道地址(IP 地址)。
数据包就像寄往这栋楼的快递。快递员(网络协议)根据 IP 地址把包裹送到楼下,但大楼里有成千上万个公司(不同的应用程序)。端口号就是告诉大楼物业,这个包裹应该具体送到哪个房间。
3.2 DHCP
3.2.1 定义
DHCP(Dynamic Host Configuration Protocol) 即动态主机配置协议,是一种网络管理协议,用于自动为网络中的设备分配 IP 地址和其他网络配置参数。
3.2.2 核心作用
自动分配 IP 地址及相关网络参数(如子网掩码、默认网关、DNS 服务器等)给网络设备,实现集中化、自动化的 IP 管理。
3.2.3 网络角色
3.2.4 工作流程
模块使用 wifi STA 模式/以太网 WAN 模式时,开启 DHCP 客户端,向路由器 DHCP 服务器获取 ip,子网掩码、默认网关、DNS 服务器等数据,4G 网络由核心网激活默认承载(下发 IP、网关、DNS)
具体工作流程

3.2.5 DHCP 报文格式

- Message type: Boot Request (1) 解析:表示这是一个 DHCP 请求报文(DHCP Request)。
- Hardware type: Ethernet (0x01) 解析:指明了硬件类型为以太网(Ethernet),值为 0x01 是标准的以太网类型。
- Hardware address length: 6 解析:硬件地址(MAC 地址)的长度为 6 字节,这是标准以太网 MAC 地址的长度。
- Hops: 0 解析:表示该报文还没有经过任何中继代理(DHCP Relay),直接从客户端发送到服务器。
- Transaction ID: 0xe18dfb7a 解析:事务 ID,用于客户端和服务器之间匹配请求和响应。每个 DHCP 事务都有一个唯一的事务 ID。
- Seconds elapsed: 0 解析:客户端发起请求以来所经过的时间,单位为秒。这里为 0,表示刚发起请求。
- Bootp flags: 0x0000 (Unicast) 解析:BOOTP 标志,值为 0x0000 表示这是一个单播(Unicast)报文。
- Client IP address: 0.0.0.0 解析:客户端的 IP 地址,0.0.0.0 表示客户端当前没有有效的 IP 地址。
- Your (client) IP address: 0.0.0.0 解析:分配给客户端的 IP 地址,这里为 0.0.0.0,表示还未分配。
- Next server IP address: 0.0.0.0 解析:下一个服务器的 IP 地址,这里为 0.0.0.0,通常在初始请求时为 0.0.0.0。
- Relay agent IP address: 0.0.0.0 解析:中继代理的 IP 地址,这里为 0.0.0.0,表示没有使用中继代理。
- Client MAC address: de:62:0f:5a:62:fc 解析:客户端的 MAC 地址,用于唯一标识网络中的设备。
- Client hardware address padding: 0000000000000000 解析:客户端硬件地址的填充,用于将硬件地址填充到固定长度。
3.2.6 常用 DHCP 选项

3.2.7 应用
netdrv.dhcp(socket.LWIP_ETH, true) 开启指定网卡的 dhcp 功能
3.2.8 与静态 ip 对比
3.2.9 常见问题与调试
dhcp 成功后会见到下图中的打印 常见问题 1: 解决方案: 常见问题 2:
3.3 DNS
3.3.1 定义与基本作用
DNS (Domain Name System):域名系统 核心作用:将人类可读的域名(如 http://www.example.com)转换为计算机可识别的 IP 地址(如 192.0.2.1) 解决的问题:避免记忆复杂的 IP 地址,提供更友好的网络访问方式
3.3.2 工作原理
wifi 以太网流程顺序:
1.获取配置:模块→(DHCP 请求)→ 路由器→(分配 IP、网关、DNS 服务器地址)→ 模块。
2.域名解析:模块→(DNS 查询:xxx.com)→ 路由器→(转发查询)→ 互联网DNS服务器→(返回 IP:x.x.x.x)→ 路由器→ 模块。
3.访问服务:模块→(HTTP 请求,目标 IP:x.x.x.x)→ 路由器(进行 NAT 转发)→ 目标服务器→(HTTP 响应)→ 路由器→ 模块。
4G 流程顺序:
- 4G 模块 → 基站: 注册网络 激活默认承载(下发 IP、网关、DNS)
- 4G 模块 →DNS 服务器: DNS 查询请求, DNS 服务器 →4G 模块: 返回目标服务器 IP
- 4G 模块 → 目标 HTTP 服务器: HTTP 请求(通过 PGW 网关转发),目标 HTTP 服务器 →4G 模块: HTTP 响应

3.3.3 协议细节

- QR(Response):查询请求/响应的标志信息。查询请求时,值为 0;响应时,值为 1。
- Opcode:操作码。其中,0 表示标准查询;1 表示反向查询;2 表示服务器状态请求。
- AA(Authoritative):授权应答,该字段在响应报文中有效。值为 1 时,表示名称服务器是权威服务器;值为 0 时,表示不是权威服务器。
- TC(Truncated):表示是否被截断。值为 1 时,表示响应已超过 512 字节并已被截断,只返回前 512 个字节。
- RD(Recursion Desired):期望递归。该字段能在一个查询中设置,并在响应中返回。该标志告诉名称服务器必须处理这个查询,这种方式被称为一个递归查询。如果该位为 0,且被请求的名称服务器没有一个授权回答,它将返回一个能解答该查询的其他名称服务器列表。这种方式被称为迭代查询。
- RA(Recursion Available):可用递归。该字段只出现在响应报文中。当值为 1 时,表示服务器支持递归查询。
- Z:保留字段,在所有的请求和应答报文中,它的值必须为 0。
- rcode(Reply code):返回码字段,表示响应的差错状态。当值为 0 时,表示没有错误;
3.3.4 应用
- http 请求时,一般填写的都是域名,此时就会自动运行 dns 解析出 ip 地址后发起连接,日志如下: dns_run 676: xxxxx.com state 0 id 2 ipv6 0 use dns server2, try 0 开始请求 dns dns_run 693:dns all done ,now stop dns 响应完成 connet 192.xxx.xxx.xxx tcp 发起请求
- socket.setDNS(adapter, 1, "223.5.5.5") 可以使用接口自定义 dns 解析服务器
3.3.5 常见问题与调试
dns 无响应,日志如下: xxxxx.com state 0 id 4 ipv6 0 use dns server2, try0 xxxxx.com state 0 id 4 ipv6 0 use dns server2, try1 xxxxx.com state 0 id 4 ipv6 0 use dns server2, try2 xxxxx.com state 0 id 4 ipv6 0 use dns server2, try0 xxxxx.com state 0 id 4 ipv6 0 use dns server2, try1 xxxxx.com state 0 id 4 ipv6 0 use dns server2, try2 解决方法:
3.3.6 公共 DNS 服务推荐
阿里 DNS(223.5.5.5) 腾讯 DNS(119.29.29.29) 114DNS(114.114.114.114) 百度查询所在省份的 dns 服务器
3.4 NAPT
3.4.1 定义
NAPT (Network Address Port Translation):网络地址端口转换,也称为 PAT (Port Address Translation),是 NAT 的高级形式,不仅转换 IP 地址,还转换端口号 核心价值:解决 IPv4 地址不足问题,允许多个内部设备共享一个外部 IP 地址
3.4.2 作用
3.4.2.1 wifi 局域网下的设备可以通过 4G 网卡接入互联网

3.4.2.2 以太网局域网下的设备可以通过 4G 网卡接入互联网

3.4.2.3 wifi 局域网下的设备可以通过以太网网卡接入互联网

3.4.2.4 以太网局域网下的设备可以通过 wifi 网卡接入互联网

3.4.3 工作原理

- 内网发起请求
内网设备 (
192.168.1.100) 的某个应用程序(端口5000)要访问公网 Web 服务器 (203.0.113.5:80)。 它发出数据包:源地址192.168.1.100:5000-> 目标地址203.0.113.5:80。 - NAPT 设备进行源地址转换
数据包到达 NAPT 路由器(公网网卡 IP 为
203.0.113.1)。 关键操作:路由器检查会话表,发现没有现有映射,于是: 将修改后的数据包发出。 - 公网服务器响应
Web 服务器看到请求来自
203.0.113.1:15000,于是将响应发往该地址。 响应数据包:源地址203.0.113.5:80-> 目标地址203.0.113.1:15000。 - NAPT 设备进行目标地址转换
路由器收到目标为
203.0.113.1:15000的数据包。 关键操作:查询会话表,找到匹配记录[192.168.1.100:5000] <--> [203.0.113.1:15000]。 逆向修改数据包:将目标地址从203.0.113.1:15000还原为192.168.1.100:5000。 将还原后的数据包转发给内网设备。
3.4.5 应用
exnetif 扩展库实现多网融合功能(如 4G 作为数据出口供 WiFi/以太网设备上网)
3.5 pcap 日志,wireshark 软件抓包分析
第四部分 LuatOS 网络协议栈介绍
| TCP/IP五层模型 | LuatOS支持的TCP/IP协议 | LuatOS上的编程接口 | 备注 |
| 应用层 | HTTP,MQTT,FTP,WebSocket,DNS,NTP,DHCP SSL/TLS:从OSI七层模型来看,和表示层最接近,所以此处把SSL/TLS放到TCP/IP模型中应用层 | socket核心库/libnet扩展库 http核心库/httpplus扩展库/httpsrv核心库 mqtt核心库 ftp核心库 websocket核心库 httpdns扩展库 dhcpsrv扩展库 udpsrv扩展库 | 应用层提供的这些编程接口和LuatOS项目应用开发关系最为密切; 这些核心库和扩展库的API文档参考: [LuatOS API手册](https://docs.openluat.com/osapi/) 在后续直播课程中,我们会逐一进行讲解 |
| 传输层 | TCP,UDP | socket核心库/libnet扩展库 | |
| 网络层 | IP,ICMP | socket核心库exnetif扩展库IP_READY、IP_LOSE | 在这里重点说一下exnetif扩展库,exnetif扩展库有两项核心功能: 1、LuatOS产品做为设备模式来使用,可以配置使用4G网卡,以太网网卡,WiFi网卡中的一种或者多种来上网,使用多种网卡上网时,可以配置使用的多种网卡优先级; 2、LuatOS产品做为路由器模式来使用,支持以下三大类网络路由场景: (1) 4G网卡连接外网,WiFi设备通过WiFi AP热点接入上网,以太网设备通过LAN口接入上网; (2) WiFi网卡连接外网,WiFi设备通过WiFi AP热点接入上网,以太网设备通过LAN口接入上网; (3) 以太网WAN口连接外网,WiFi设备通过WiFi AP热点接入上网,以太网设备通过LAN口接入上网; |
| 数据链路层 | 以太网,WiFi,4G 等网络各自的数据链路层协议 以太网的IEEE 802.3系列 WiFi网络的IEEE 802.11系列 4G网络的PDCP、RLC、MAC等协议 | ||
| 物理层 | 双绞线,无线电波等传输介质 |
具体在本篇文章中,介绍了网络层中的 IP 协议,传输层中的 TCP/UDP 协议,应用层中的 DHCP、DNS、HTTP 等协议,以及工作在网络层和应用层之间的 NAPT 网络地址转换技术
第五部分核心概念详解
5.1 网卡/网络适配器
4G 网卡:通过 SIM 卡接入移动网络 WiFi 网卡:支持 IEEE 802.11 协议的无线网络 以太网网卡:通过网线接入有线网络 在使用 tcp,http,mqtt 等协议时都是使用特定网卡收发数据,可以手动指定想要使用的网卡,或者不填写使用默认的网卡。 socket.create(adapter, task_name) http.request(method, url, headers, body, opts 中的 adapter 参数 server_ca_cert, client_cert, client_key, client_password) mqtt.create(adapter, host, port, ssl, isipv6)
5.2 netdrv 库
- 概述: netdrv 是指网络设备,用于初始化并管理不同的网络设备。如:4G,以太网,WIFI。还可以提供路由功能.把各种联网方式融合起来,如:4G 连接外部网络,支持以太网 LAN 模式为其他以太网设备提供接入,模块最多同时挂载 5 个以太网网口,支持 LAN,WAN 随意组合使用
- 示例 https://docs.openluat.com/air8000/luatos/app/socket/netdrv/
5.3 exnetif 扩展库
- 概述 exnetif 扩展库用于简化多网络环境下的优先级管理,例如(以太网 > WiFi > 4G)和多网融合操作;通过设置网络优先级,模块自动选择最优网卡上网,并支持配置网络代理实现多网融合功能(如 4G 作为数据出口供 WiFi/以太网设备上网)模块最多同时挂载 5 个以太网网口,支持 LAN,WAN 随意组合使用;
- 示例 https://docs.openluat.com/air8000/luatos/app/network_routing/
5.4 设备模式
- 单网卡 模块只使用 4G 网卡,Wi-Fi 网卡,以太网网卡中的一种网卡
- 多网 模块同时使用 4G 网卡,Wi-Fi 网卡,以太网网卡中的两种或以上网卡 可以手动指定网卡或者使用 exnetif.set_priority_order(networkConfigs)接口设置优先级,自动切换当前可用的优先级最高的网卡
5.5 路由模式
- 概述
网络转发,为局域网内的设备提供互联网数据交互能力
如:4G 连接外部网络,生成 WiFi 热点为 WiFi 终端设备提供接入,支持以太网 lan 模式为其他以太网设备提供接入

- 示例 https://docs.openluat.com/air8000/luatos/app/network_routing/
第六部分 API 详解部分
netdrv 核心库
netdrv.setup(id, tp, opts)
功能
初始化指定 netdrv 设备;
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.setup(socket.LWIP_ETH);
tp
参数含义:实现方式,如果是设备自带的硬件,那就不需要传, 外挂设备需要传,当前支持CH390H/D;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如netdrv.CH390;
是否必选:可选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=0,cs=8});
opts
参数含义:外挂方式,需要额外的参数,参考示例;
opts = {
-- 参数含义:外挂的spi_id;
-- 数据类型:number;
-- 取值范围:0/1;
-- 是否必选:必选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
spi,
-- 参数含义:外挂的spi片选引脚(GPIO号);
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
cs,
-- 参数含义:irq中断引脚;
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:支持CH390H的中断模式, 能提供响应速度,实测对总网速没有帮助, 轻负载时 能降低功耗, 让模组能进入低功耗模式;
-- 参数示例:
irq
}
数据类型:table;
取值范围:暂无;
是否必选:可选;
注意事项:无;
参数示例:netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=0,cs=8,irq=20});
返回值
local res = netdrv.setup(id, tp, opts) log.info("netdrv",res)
res
含义说明:初始化指定netdrv设备的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
-- Air8101初始化内部以太网控制器
netdrv.setup(socket.LWIP_ETH)
-- Air8000/Air780EPM初始化CH390H/D作为LAN/WAN
-- 支持多个CH390H, 使用不同的CS脚区分不同网口
netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=0,cs=8})
-- 支持CH390H的中断模式, 能提供响应速度, 但是需要外接中断引脚
-- 实测对总网速没有帮助, 轻负载时能降低功耗, 让模组能进入低功耗模式
netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=0,cs=8,irq=20})
-- Air780EPM外挂Air8101时,使用虚拟网卡的方式初始化网络
netdrv.setup(socket.LWIP_USER0, netdrv.WHALE)
netdrv.dhcp(id, enable)
功能
在指定的网络适配器上开启或者关闭 DHCP,仅作为数据出口的网卡使用,以太网 lan 模式和 wifi ap 模式需要使用 netdrv.ipv4 接口手动设置。 如果需要 netdrv.ipv4 设置静态 ip,就不要调用本接口; [DHCP]设备自动获取 ip 地址和网关信息;
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.dhcp(socket.LWIP_ETH, true);
enable
参数含义:开启或关闭DHCP;
数据类型:boolean;
取值范围:true/false;
是否必选:必选;
注意事项:推荐使用dhcp获取ip。如果需要设置静态ip,就不要调用本接口;
参数示例: netdrv.dhcp(socket.LWIP_ETH, true);
返回值
local res = netdrv.dhcp(id, enable) log.info("netdrv",res)
res
含义说明:开启或关闭DHCP的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
netdrv.dhcp(socket.LWIP_ETH, true)
netdrv.mac(id)
功能
获取指定网络适配器的 MAC;
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.mac(socket.LWIP_ETH);
返回值
local mac = netdrv.mac(id) log.info("netdrv",mac)
mac
含义说明:指定网络适配器的MAC;
数据类型:string;
取值范围:无;
注意事项:需要等netdrv.setup成功之后再获取mac地址;
返回示例:"3CAB724406E8";
示例
-- 获取MAC地址
log.info("netdrv", "mac addr", netdrv.mac(socket.LWIP_ETH))
-- 暂不支持设置
netdrv.ipv4(id, addr, mark, gw)
功能
设置或读取 ipv4 地址,不填写 addr, mark, gw 参数是读取,填写的是设置功能, 使用 netdrv.ipv4 手动设置参数时需要保持 dhcp 功能是关闭的状态,不可以 netdrv.dhcp 开启 dhcp 功能;
注意:不是所有 netdrv 都支持设置的, 尤其 4G Cat.1 自带的 netdrv 就不能设置 ipv4 当前设置 ip 但 ip 值非法, 不返回任何东西 如果设置 ip 且 ip 值合法, 会返回 ip, mask, gw
[DHCP]设备自动获取 ip 地址和网关信息;
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.ipv4(socket.LWIP_USER0, "192.168.111.2", "255.255.255.0", "192.168.111.1");
addr
参数含义:静态ipv4地址;
数据类型:string;
取值范围:暂无;
是否必选:可选,如果是读取就不需要传此参数;
注意事项:需要填写正确的ipv4地址;
参数示例:netdrv.ipv4(socket.LWIP_USER0, "192.168.111.2", "255.255.255.0", "192.168.111.1");
mark
参数含义:子网掩码;
数据类型:string;
取值范围:暂无;
是否必选:可选,如果是读取就不需要传此参数;
注意事项:需要填写正确的掩码;
参数示例:netdrv.ipv4(socket.LWIP_USER0, "192.168.111.2", "255.255.255.0", "192.168.111.1");
gw
参数含义:网关;
数据类型:string;
取值范围:暂无;
是否必选:可选,如果是读取就不需要传此参数;
注意事项:需要填写正确的ipv4网关;
参数示例:netdrv.ipv4(socket.LWIP_USER0, "192.168.111.2", "255.255.255.0", "192.168.111.1");
返回值
local ipv4,mark, gw = netdrv.ipv4(id, addr, mark, gw) log.info("ipv4", ipv4,mark, gw)
ipv4
含义说明:ip地址;
数据类型:string;
取值范围:暂无;
注意事项:无;
返回示例:"192.168.111.2";
mark
含义说明:子网掩码;
数据类型:string;
取值范围:暂无;
注意事项:无;
返回示例:"255.255.255.0";
gw
含义说明:网关;
数据类型:string;
取值范围:暂无;
注意事项:无;
返回示例:"192.168.111.1";
示例
-- 注意, 不是所有netdrv都支持设置的, 尤其4G Cat.1自带的netdrv就不能设置ipv4
-- 注意, 设置ipv4时, DHCP要处于关闭状态!!
-- 当前设置ip但ip值非法, 不返回任何东西
-- 如果设置ip且ip值合法, 会返回ip, mask, gw
-- 设置
log.info("静态ip",netdrv.ipv4(socket.LWIP_USER0, "192.168.111.2", "255.255.255.0", "192.168.111.1"))
-- 读取
log.info("静态ip",netdrv.ipv4(socket.LWIP_USER0))
netdrv.napt(id)
功能
在指定的网络适配器上开启或关闭 NAPT
专业术语: NAPT - 网络地址端口转换, 也是家用路由器的最基础功能
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:当前接口填写-1为关闭所有网络适配器的napt功能;
参数示例:netdrv.napt(socket.LWIP_GP);
返回值
local res = netdrv.napt(id) log.info("netdrv",res)
res
含义说明:开启或关闭NAPT的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
-- 使用4G网络作为主网关出口
netdrv.napt(socket.LWIP_GP)
-- 关闭napt功能
netdrv.napt(-1)
netdrv.link(id)
功能
获取指定的网络适配器的物理连接状态,如以太网网线接入和断开; 以太网网线接入,或者使用 wifi,4G 网络 netdrv.link(id)会返回 true 第一次获取到 ip 会上报"IP_READY"消息, ip 状态正常 netdrv.ready(id)会返回 true,等同于 socket.adapter 接口
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.link(socket.LWIP_GP);
返回值
local res = netdrv.link(id) log.info("netdrv",res)
res
含义说明:netdrv的物理连接状态,如以太网网线接入和断开;
数据类型:boolean;
取值范围:true/false;
注意事项:已连接返回true, 否则返回false. 如果id对应的netdrv不存在,返回nil;
返回示例:true;
示例
-- 注意, 本函数仅支持读取连接状态, 不能查询ip状态, 不能判断是否可以联网
-- 查询4G网卡状态
netdrv.link(socket.LWIP_GP)
netdrv.ready(id)
功能
获取指定的网络适配器的 IP 状态; 以太网网线接入,或者 wifi,4G 网络 netdrv.link(id)会返回 true 第一次获取到 ip 会上报"IP_READY"消息, ip 状态正常 netdrv.ready(id)会返回 true,等同于 socket.adapter 接口
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.ready(socket.LWIP_GP);
返回值
local res = netdrv.ready(id) log.info("netdrv",res)
res
含义说明:netdrv的网络状态;
数据类型:boolean;
取值范围:true/false;
注意事项:已连接返回true, 否则返回false. 如果id对应的netdrv不存在,返回nil;
返回示例:true;
示例
-- 注意, 本函数仅支持读取连接状态, 不能判断是否可以联网
-- 查询4G网卡状态
netdrv.ready(socket.LWIP_GP)
netdrv.ctrl(id, cmd, arg)
功能
给具体的网络适配器发送控制指令;
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.ctrl(socket.LWIP_ETH, netdrv.CTRL_RESET, netdrv.RESET_HARD);
cmd
参数含义:指令, 例如 netdrv.CTRL_RESET;
数据类型:number;
取值范围:netdrv.CTRL_RESET;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.ctrl(socket.LWIP_ETH, netdrv.CTRL_RESET, netdrv.RESET_HARD);
arg
参数含义:指令cmd携带的参数;
数据类型:number;
取值范围:netdrv.RESET_HARD/netdrv.RESET_SOFT;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.ctrl(socket.LWIP_ETH, netdrv.CTRL_RESET, netdrv.RESET_HARD);
返回值
local res = netdrv.ctrl(id, cmd, arg) log.info("netdrv",res)
res
含义说明:发送控制指令的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
-- 硬件重启网卡, 仅CH390H支持, 其他网络设备暂不支持
-- 本函数于 2025.4.14 新增
netdrv.ctrl(socket.LWIP_ETH, netdrv.CTRL_RESET, netdrv.RESET_HARD)
netdrv.debug(id, enable)
功能
指定的网络适配器调试信息输出开关(开启后会增加一些相关日志输出);
参数
id
参数含义:网络适配器编号;如果传0就是全局调试开关,适用于所有网络适配器;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.debug(socket.LWIP_ETH, true);
enable
参数含义:是否开启调试信息输出;
数据类型:boolean;
取值范围:true/false;
是否必选:必选;
注意事项:无;
参数示例: netdrv.debug(socket.LWIP_ETH, true);
返回值
local res = netdrv.debug(id, enable) log.info("netdrv",res)
res
含义说明:设置调试模式的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
-- 打开netdrv全局调试开关
netdrv.debug(0, true)
netdrv.ping(id, ip, len)
功能
在指定的网络适配器上发起 PING 请求;如果发起成功,会有异步消息"PING_RESULT"通知 PING 结果, 在代码中可以通过 sys.subscribe 和 sys.waitUntil 两种方式订阅处理异步消息"PING_RESULT",处理代码如下: sys.subscribe("PING_RESULT", function(id, time, dst) log.info("ping", id, time, dst); --获取到响应结果 end) 或 sys.waitUntil("PING_RESULT")
参数
id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.ping(socket.LWIP_GP, "121.14.77.221");
ip
参数含义:要ping的目标ip地址;
数据类型:string;
取值范围:暂无;
是否必选:必选;
注意事项:需要填写正确的ipv4地址;
参数示例:netdrv.ping(socket.LWIP_GP, "121.14.77.221");
len
参数含义:ping包大小;
测试网络性能和吞吐量
小包(例如 32 或 64 字节):主要用来测试网络延迟(Latency/Ping值)。数据包很小,几乎瞬间 就能完成传输,所以返回的时间(如 20ms)更能真实地反映信号传输和处理的开销。
大包(例如 1024, 2048 或更大):用来测试网络带宽(Bandwidth) 和吞吐量(Throughput)。 发送大量数据需要更多时间,此时返回的时间会显著增加。通过计算单位时间内成功传输的数据量,可 以粗略估算网络带宽。如果大包延迟急剧增加或丢包,可能表明网络存在拥塞或带宽不足。
数据类型:number;
取值范围:暂无;
是否必选:可选;
注意事项:默认128字节;
参数示例:netdrv.ping(socket.LWIP_GP, "121.14.77.221",128);
返回值
local res = netdrv.ping(id, ip, len) log.info("netdrv",res)
res
含义说明:发起ping的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:true仅代表发送成功,不代表服务器已经响应;
返回示例:true;
示例
-- 本功能在2025.9.3新增
local function ping_test()
-- 要等联网了才能ping
sys.waitUntil("IP_READY")
while 1 do
-- 必须指定使用哪个网卡
netdrv.ping(socket.LWIP_GP, "121.14.77.221")
sys.waitUntil("PING_RESULT", 3000)
sys.wait(3000)
end
end
local function ping_res(id, time, dst)
log.info("ping", id, time, dst); --获取到响应结果
end
sys.taskInit(ping_test)
sys.subscribe("PING_RESULT", ping_res)
netdrv.on(adapter_id, event_type, callback)
功能
订阅指定的网络适配器上的网络事件; 使用网卡联网时,获取网络事件,如果有 error 或 timeout 事件可以切换其他可用网卡
参数
adapter_id
参数含义:网络适配器编号;
数据类型:number;
取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.on(socket.LWIP_ETH, netdrv.EVT_SOCKET, func_cb);
event_type
参数含义:事件类型;
数据类型:number;
取值范围:netdrv.EVT_SOCKET;
是否必选:必选;
注意事项:参考第三部分常量详解;
参数示例:netdrv.on(socket.LWIP_ETH, netdrv.EVT_SOCKET, func_cb);
callback
参数含义:回调函数;
回调函数接收以下两个参数:
-- 参数含义:网络适配器编号;
-- 数据类型:number;
-- 取值范围:常量详解章节中的“网络适配器类型的常量”,例如socket.LWIP_ETH;
-- 是否必选:必选;
-- 注意事项:参考第三部分常量详解;
id
-- 参数含义:事件;
-- 数据类型:string;
-- 取值范围:-- "create" 创建socket对象
-- "release" 释放socket对象
-- "connecting" 正在连接, 域名解析成功后出现
-- "connected" 连接成功, TCP三次握手成功后出现
-- "closed" 连接关闭
-- "remote_close" 远程关闭, 网络中断,或者服务器主动断开
-- "timeout" dns解析超时,或者tcp连接超时
-- "error" 错误,包括一切异常错误;
-- 是否必选:必选;
-- 注意事项:无;
event
-- 参数含义:参数表;
-- 数据类型:table;
-- 取值范围:-- params.remote_ip 远端ip地址,未必存在 数据类型:string;
-- params.remote_port 远端端口,未必存在 数据类型:number;
-- params.online_ip 实际连接的ip地址,未必存在 数据类型:string;
-- params.domain_name 远端域名,如果是通过域名连接的话, release时没有这个值, create时也没有 数据类型:string;
-- 是否必选:必选;
-- 注意事项:无;
params
数据类型:function;
取值范围:暂无;
是否必选:必选;
注意事项:无;
参数示例:netdrv.on(socket.LWIP_ETH, netdrv.EVT_SOCKET, func_cb);
返回值
local res = netdrv.on(adapter_id, event_type, callback) log.info("netdrv",res)
res
含义说明:订阅网络事件的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
local function socket_event(id, event, params)
log.info("netdrv", "socket event", id, event, json.encode(params or {}))
if params then
-- params里会有remote_ip, remote_port等信息, 可按需获取
local remote_ip = params.remote_ip
local remote_port = params.remote_port
local domain_name = params.domain_name
log.info("netdrv", "socket event", "remote_ip", remote_ip, "remote_port", remote_port, "domain_name", domain_name)
end
end
netdrv.on(socket.LWIP_ETH, netdrv.EVT_SOCKET, socket_event)
netdrv.mreport(config, value)
功能
设置遥测功能,仅 2025 年 10 月 9 日之后发布的固件版本支持;
参数
config
参数含义:配置项;
数据类型:string;
取值范围:"enable"/"custom";
是否必选:必选;
注意事项:无;
参数示例:netdrv.mreport("enable", true);
config
参数含义:配置项;
数据类型:boolean/table;
取值范围:true/false/自定义table;
是否必选:必选;
注意事项:无;
参数示例:netdrv.mreport("custom", {abc=1234});
返回值
local res = netdrv.mreport(config, value) log.info("netdrv",res)
res
含义说明:设置遥测功能的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
-- 设置开启与关闭
netdrv.mreport("enable", true)
netdrv.mreport("enable", false)
-- 立即上报一次, 无参数的方式调用
netdrv.mreport()
-- 设置自定义数据
netdrv.mreport("custom", {abc=1234})
-- 清除自定义数据
netdrv.mreport("custom")
wlan 核心库
wlan.init()
功能
初始化 wlan;
参数
无
返回值
local res = wlan.init() log.info("wlan", res)
res
含义说明:初始化wlan的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
wlan.init()
wlan.setMode(mode)
功能
设置 wifi 模式、单 STA、单 AP、STATIONAP(混合模式);
参数
mode
参数含义:wifi模式;
数据类型:number;
取值范围:wlan.AP/wlan.STATION/wlan.STATIONAP;
是否必选:是;
注意事项:参考第三节常量详解;
参数示例:wlan.setMode(wlan.STATIONAP);
返回值
local res = wlan.setMode(mode) log.info("wlan", res)
res
含义说明:设置wifi模式的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
wlan.setMode(wlan.STATIONAP)
wlan.ready()
功能
作为 STATION 时,是否已经连接上 AP,且获取 IP 成功;
参数
无
返回值
local res = wlan.ready() log.info("wlan", res)
res
含义说明:连接wifi的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
log.info("wlan", wlan.ready())
wlan.connect(ssid, password, auto_reconnect, bssid)
功能
作为 STATION 时,连接到指定 wifi;
参数
ssid
参数含义:wifi名称;
数据类型:string;
取值范围:暂无;
是否必选:必选;
注意事项:暂无;
参数示例:wlan.connect("myap", "12345678")
password
参数含义:wifi密码;
数据类型:string;
取值范围:暂无;
是否必选:可选;
注意事项:暂无;
参数示例:wlan.connect("myap", "12345678")
auto_reconnect
参数含义:是否自动重连;
数据类型:number;
取值范围:0/1;
是否必选:可选,默认开启;
注意事项:0关闭自动重连,1开启自动重连,当前强制开启自动重连,配置为0,实际上也是自动重连;
参数示例:wlan.connect("myap", "12345678", 1)
bssid
参数含义:mac地址;
数据类型:string;
取值范围:暂无;
是否必选:可选;
注意事项:接入点(AP)或无线路由器的MAC地址(或虚拟MAC地址),一般用于区分同名Wi-Fi;
参数示例:local bssid = string.fromHex("00182946365f")
wlan.connect("myap", "12345678", 1, bssid)
返回值
local res = wlan.connect(ssid, password) log.info("wlan", res)
res
含义说明:发起连接的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表发起成功,不代表连接AP成功!!,false代表失败;
返回示例:true;
示例
wlan.connect("myap", "12345678")
wlan.disconnect()
功能
作为 STATION 时,断开 wifi 连接。主动断开连接后不会再自动重连,wlan.connect 重新连接后自动重连生效。
参数
无
返回值
无
示例
wlan.disconnect()
wlan.scan()
功能
扫描附近 wifi 信息;
参数
无
返回值
无
示例
-- 注意, wlan.scan()是异步API,启动扫描后会马上返回
-- wifi扫描成功后, 会有WLAN_SCAN_DONE消息, 读取即可
local function scan_cb()
local results = wlan.scanResult()
log.info("scan", "results", #results)
for k,v in pairs(results) do
log.info("scan", v["ssid"], v["rssi"], (v["bssid"]:toHex()))
end
end
sys.subscribe("WLAN_SCAN_DONE", scan_cb)
-- 开启wifi扫描
local function start_scan()
wlan.init()
while 1 do
wlan.scan()
sys.wait(15000) -- 注意, 尤其是Air780系列, 这个时间只能更长不能短
end
end
sys.taskInit(start_scan)
wlan.scanResult()
功能
获取 wifi 扫描结果(异步);
参数
无
返回值
local results = wlan.scanResult() log.info("scan", "results", #results) for k,v in pairs(results) do log.info("scan", v["ssid"], v["rssi"], (v["bssid"]:toHex())) end
results
含义说明:存储wifi信息的table,包含有一个或者多个这样的子table;
{{
含义说明:wifi名称;
数据类型:string;
取值范围:无;
注意事项:无;
返回示例:"test";
ssid
含义说明:信号强度;
数据类型:number;
取值范围:无;
注意事项:无;
返回示例:-89;
rssi
含义说明:mac地址;
数据类型:string;
取值范围:无;
注意事项:无;
返回示例:0xF01122334455。hex字符串,直接打印的话会是乱码,需要tohex();
bssid
}}
数据类型:table;
取值范围:无;
注意事项:无;
返回示例:无;
示例
-- 注意, wlan.scan()是异步API,启动扫描后会马上返回
-- wifi扫描成功后, 会有WLAN_SCAN_DONE消息, 读取即可
sys.subscribe("WLAN_SCAN_DONE", function ()
local results = wlan.scanResult()
log.info("scan", "results", #results)
for k,v in pairs(results) do
log.info("scan", v["ssid"], v["rssi"], (v["bssid"]:toHex()))
end
end)
-- 下面演示的是初始化wifi后定时扫描,请按实际业务需求修改
sys.taskInit(function()
sys.wait(1000)
wlan.init()
while 1 do
wlan.scan()
sys.wait(15000)
end
end)
wlan.smartconfig(mode)
功能
开启配网功能;
参数
mode
参数含义:配网方式;
数据类型:number;
取值范围:wlan.ESPTOUCH/wlan.AIRKISS/wlan.ESPTOUCH_V2;
是否必选:可选,默认esptouch;
注意事项:详见第三部分常量说明;
参数示例:wlan.smartconfig(wlan.AIRKISS);
返回值
local res = wlan.smartconfig(mode) log.info("wlan", res)
res
含义说明:发起配网的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表发起成功,false代表失败;
返回示例:true;
示例
wlan.smartconfig()
wlan.getMac(mode, hexstr)
功能
获取 mac;
参数
mode
参数含义:获取什么类型的mac,AP或STA;
数据类型:number;
取值范围:wlan.AP/wlan.STATION;
是否必选:必选;
注意事项:暂无;
参数示例:wlan.getMac(wlan.STATION);
hexstr
参数含义:是否转HEX字符, 默认是true,即输出hex字符串;
数据类型:boolean;
取值范围:true/false;
是否必选:可选;
注意事项:无;
参数示例:wlan.getMac(wlan.STATION,true)
返回值
local mac = wlan.getMac() log.info("wlan", mac)
mac
含义说明:mac地址;
数据类型:string;
取值范围:无;
注意事项:无;
返回示例:"F01122334455";
示例
wlan.getMac(wlan.STATION)
wlan.getMac(wlan.AP)
wlan.setMac(mode, mac)
功能
设置 mac;
参数
mode
参数含义:设置什么类型的mac,AP或STA;
数据类型:number;
取值范围:wlan.AP/wlan.STATION;
是否必选:必选;
注意事项:暂无;
参数示例:wlan.setMac(tp, mac);
mac
参数含义:mac地址;
数据类型:string;
取值范围:无;
是否必选:必选;
注意事项:无;
参数示例:wlan.setMac(tp, mac)
返回值
local res = setMac(mode, mac) log.info("wlan", res)
res
含义说明:设置的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
wlan.setMac(wlan.AP, (string.fromHex("C81234567890")))
wlan.getIP()
功能
获取做为 station 使用时的 ip,仅 STATION 或 APSTA 模式下有意义;
参数
无
返回值
local ipv4 = wlan.getIP() log.info("wlan", ipv4)
ipv4
含义说明:ip地址;
数据类型:string;
取值范围:无;
注意事项:无;
返回示例: "192.168.1.25";
示例
wlan.getIP()
wlan.createAP(ssid, passwd, gateway, netmask, channel, opts)
功能
开启 AP 热点;
参数
ssid
参数含义:AP热点名称;
数据类型:string;
取值范围:暂无;
是否必选:必选;
注意事项:暂无;
参数示例:wlan.createAP("luatos1234")
password
参数含义:AP热点密码,无需密码时可以不填写当前参数;
数据类型:string;
取值范围:暂无;
是否必选:可选;
注意事项:暂无;
参数示例:wlan.createAP("luatos1234", "12341234")
gateway
参数含义:网关;
数据类型:string;
取值范围:0/1;
是否必选:可选;
注意事项:无;
参数示例:wlan.createAP("luatos1234", "12341234", "192.168.4.1")
netmask
参数含义:网关掩码;
数据类型:string;
取值范围:暂无;
是否必选:可选;
注意事项:无;
参数示例:wlan.createAP("luatos1234", "12341234", "192.168.4.1")
channel
参数含义:AP建立的通道;
数据类型:number;
取值范围:1-13;
是否必选:可选;
注意事项:默认值为6;
参数示例:wlan.createAP("luatos1234", "12341234", "192.168.4.1", "255.255.255.0", 6)
opts
参数含义:配置项;
{
-- 参数含义:AP是否隐藏SSID, 默认false,不隐藏;
-- 数据类型:boolean;
-- 取值范围:true/false;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
hidden = false,
-- 参数含义:AP最大客户端数量;
-- 数据类型:number;
-- 取值范围:1-4;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
max_conn = 4
}
数据类型:table;
取值范围:暂无;
是否必选:可选;
注意事项:无;
参数示例:wlan.createAP("luatos1234", "12341234", "192.168.4.1", "255.255.255.0", 6 ,{ hidden = false, max_conn = 4 })
返回值
local res = wlan.createAP(ssid, passwd, gateway, netmask, channel, opts) log.info("wlan", res)
res
含义说明:开启的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
wlan.createAP("luatos1234", "12341234")
wlan.stopAP()
功能
关闭 AP 热点;
参数
无
返回值
local res = wlan.stopAP() log.info("wlan", res)
res
含义说明:关闭的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
wlan.stopAP()
wlan.getInfo()
功能
获取 wifi 热点的信息,连接 wifi 热点后获取;
参数
无
返回值
local res = wlan.getInfo() log.info("wlan", "info", json.encode(res))
res
含义说明:wifi信息;
数据类型:table;
取值范围:无;
注意事项:连接wifi后获取;
返回示例:{
bssid = "F01122334455",
rssi = -89,
gw = "192.168.1.1"
};
示例
log.info("wlan", "info", json.encode(wlan.getInfo()))
wlan.hostname(id, new_name)
功能
读取或设置 Hostname; 不填写 new_name 参数时是读取;
参数
id
参数含义:STA填0, AP填1;
数据类型:number;
取值范围:0/1;
是否必选:必选;
注意事项:暂无;
参数示例:wlan.hostname(1, "myhost");
new_name
参数含义:新的hostname,可选, 传入就是设置,不传是读取;
数据类型:string;
取值范围:无;
是否必选:可选;
注意事项:无;
参数示例:wlan.hostname(1, "myhost")
返回值
local hostname = wlan.hostname(id) log.info("wlan", hostname)
hostname
含义说明:名字;
数据类型:string;
取值范围:无;
注意事项:无;
返回示例:"myhost";
示例
wlan.hostname(1, "myhost") --设置AP的hostname
wlan.hostname(0) -- 获取STA的hostname
wlan.staIp(dhcp_enable, ip, netmask, gateway)
功能
设置 Station 模式下的 IP 获取模式(dhcp 或静态 ip);
参数
dhcp_enable
参数含义:是否使用dhcp;
数据类型:boolean;
取值范围:true/false;
是否必选:必选;
注意事项:无;
参数示例:wlan.staIp(true);
addr
参数含义:静态ip地址;
数据类型:string;
取值范围:暂无;
是否必选:可选,如果是dhcp就不需要传此参数;
注意事项:需要填写正确的ipv4地址;
参数示例:wlan.staIp(false, "192.168.2.200", "255.255.255.0", "192.168.2.1");
mark
参数含义:子网掩码;
数据类型:string;
取值范围:暂无;
是否必选:可选,如果是dhcp就不需要传此参数;
注意事项:需要填写正确的掩码;
参数示例:wlan.staIp(false, "192.168.2.200", "255.255.255.0", "192.168.2.1");
gw
参数含义:网关;
数据类型:string;
取值范围:暂无;
是否必选:可选,如果是dhcp就不需要传此参数;
注意事项:需要填写正确的ipv4网关;
参数示例:wlan.staIp(false, "192.168.2.200", "255.255.255.0", "192.168.2.1");
返回值
local res = wlan.staIp(dhcp_enable, ip, netmask, gateway) log.info("wlan", res)
res
含义说明:设置的结果;
数据类型:boolean;
取值范围:true/false;
注意事项:返回值为true代表成功,false代表失败;
返回示例:true;
示例
wlan.staIp(true)
exnetif 扩展库
exnetif.set_priority_order(networkConfigs)
功能
设置网络优先级并初始化网络;
注意事项
可以开启单网络或多网优先级,单网时不会判断网络连通性,多网络时根据 table 中的顺序确定联网优先级;
参数
networkConfigs
含义说明:网络配置表,按优先级从高到低排序;
-- 多网络模式,填写多个网络:
{
-- 参数含义:配置WiFi参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:根据位置决定优先级顺序,当前wifi优先级最高;
-- 参数示例:
{
WIFI = {
-- 参数含义:WiFi名称;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:暂无;
-- 参数示例:
ssid = "your_ssid",
-- 参数含义:WiFi密码;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:暂无;
-- 参数示例:
password = "your_pwd",
-- 参数含义:是否需要通过ping来测试网络的连通性;
-- 数据类型:boolean/nil;
-- 取值范围:true/false;
-- 是否必选:可选;
-- 注意事项:-- 在没有ping测试环境的项目中,需要将这个参数为false,表示不需要ping测试网络连通,
-- 仅根据IP READYip地址)来判断网络环网络连通性则无法保证
-- 如果没有设置此参数,默认为true
-- 在有ping测试环境要将这个参数设置为true
-- 参数示例:
need_ping = true,
-- 参数含义:局域网模式(选填参数),设置为true时,exnetif会自动将ping_ip设置为网卡的网ip;
-- 数据类型:boolean/nil;
-- 取值范围:true/false;
-- 是否必选:可选;
-- 注意事项:-- 用户不需要传入ping_ip参数,即使传入了,也无效;
-- 这个模式的使用场景,仅适用于局域网环境;可以访问外网时,不要使用
-- 参数示例:
local_network_mode = true,
-- 参数含义:连通性检测IP(选填参数),默认使用httpdns获取baidu.com的ip作为判断条件;
-- 数据类型:string/nil;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:-- 注:如果填写ip,则ping通作为判断网络是否可用的条件,
-- 所以需要根据网络环境填写内网或者外网ip,
-- 填写外网ip的话要保证外网ip始终可用,
-- 填写局域网ip的话要确保相应ip固定且能够被ping通
-- 参数示例:
ping_ip = "112.125.89.8",
-- 参数含义:填写ping_ip且未ping通时的检测间隔(ms, 可选,默认为10秒);
-- 数据类型:number/nil;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:定时ping将会影响模块功耗,使用低功耗模式的话可以适当延迟间隔时间
-- 参数示例:
ping_time = 10000
}
},
-- 参数含义:配置以太网参数,Air8000系列SPI方式,780EXX系列SPI方式,8101RMII方式;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:根据位置决定优先级顺序,当前以太网优先级排第二;
-- 参数示例:
{
ETHERNET = {
-- 参数含义:供电使能引脚(GPIO号);
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:控制以太网模块供电使能;
-- 参数示例:
pwrpin = 140,
-- 参数含义:网卡芯片型号;
-- 数据类型:常量,可参考第三章节常量详解;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
tp = netdrv.CH390,
-- 参数含义:外挂方式,需要额外的参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
opts = {
-- 参数含义:外挂的spi_id;
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
spi = 1,
-- 参数含义:外挂的spi片选引脚(GPIO号);
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
cs = 12
},
-- 参数含义:手动设置静态IP;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:选填参数,不填默认使用dhcp获取IP;
-- 参数示例:
static_ip = {
-- 参数含义:ip参数;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:使用static_ip配置静态ip是必填参数;
-- 参数示例:
ipv4 = "192.168.5.100",
-- 参数含义:子网掩码;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:使用static_ip配置静态ip是必填参数;
-- 参数示例:
mark = "255.255.255.0",
-- 参数含义:网关参数;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:使用static_ip配置静态ip是必填参数;
-- 参数示例:
gw = "192.168.5.1"
},
--同上
need_ping = true,
--同上
local_network_mode = true,
--同上
ping_ip = "112.125.89.8",
}
},
-- 参数含义:配置以太网参数,8101SPI方式;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:根据位置决定优先级顺序,当前外挂spi以太网优先级排第三;
-- 参数示例:
{
ETHUSER1 = {
--同上
pwrpin = 13,
--同上
tp = netdrv.CH390,
--同上
opts = { spi = 0, cs = 15 },
--同上
need_ping = true,
--同上
local_network_mode = true,
--同上
ping_ip = "112.125.89.8",
--同上
static_ip = {
ipv4 = "192.168.5.100",
mark = "255.255.255.0",
gw = "192.168.5.1"
}
}
},
-- 参数含义:是否开启4G;
-- 数据类型:boolean/nil;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:根据位置决定优先级顺序,当前4G优先级最低;
-- 参数示例:
{
LWIP_GP = true
}
}
-- 单网络模式:
-- 单网络模式下只使用WIFI网络
{
-- 参数含义:配置单wifi参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:无优先级概念,不检测网络连通性;
-- 参数示例:
{
WIFI = {
ssid = "test",
password = "HZ88888888",
}
}
}
-- 单网络模式下只使用SPI以太网网络
{
-- 参数含义:配置单以太网参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:暂无;注意事项:无优先级概念,不检测网络连通性;
-- 参数示例:
{
ETHUSER1 = {
pwrpin = 140,
tp = netdrv.CH390,
opts = {spi = 1, cs = 12}
}
}
}
-- 单网络模式下只使用RMII以太网网络
{
-- 参数含义:配置单以太网参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:暂无;注意事项:无优先级概念,不检测网络连通性;
-- 参数示例:
{
ETHERNET = { -- 以太网配置
pwrpin = 13, -- 供电使能引脚(number)
}
}
}
-- 4G单网模式下,不需要require "exnetif",减少不必要的功能模块加载
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:按照表格中的顺序确定优先级;
-- 参数示例:;
{
{
ETHUSER1 = {
pwrpin = 140,
tp = netdrv.CH390,
opts = {spi = 1, cs = 12}
}
}
}
数据类型:table;
取值范围:暂无;
是否必选:必选;
注意事项:根据位置决定优先级顺序,当前wifi优先级最高;
参数示例: exnetif.set_priority_order(
{{
ETHERNET = {
pwrpin = 13,
need_ping = true,
local_network_mode = true
}
}, {
WIFI = {
ssid = "your_ssid",
password = "your_pwd"
}
}, {
LWIP_GP = true
}})
返回值:
true:成功,false:失败 示例:
exnetif.set_priority_order({
{
ETHUSER1 = {
pwrpin = 140,
tp = netdrv.CH390,
opts = {spi = 1, cs = 12}
}
}
})
exnetif.notify_status(cb_fnc)
功能
设置网络状态变化回调函数;
注意事项
可选配置,设置回调函数后可以通过回调函数获取网络状态的变化;
参数
cb_fnc
参数含义:设置网络状态变化回调函数;
回调函数接收以下两个参数,
-- 参数含义: 网络类型字符串(如"Ethernet");
-- 数据类型:string;
-- 取值范围:无限制;
-- 是否必选:必选;
-- 注意事项:暂无;
net_type
-- 参数含义: 网络适配器ID(如socket.LWIP_ETH);
-- 数据类型:string;
-- 取值范围:无限制;
-- 是否必选:必选;
-- 注意事项:暂无;
adapter
数据类型:function;
取值范围:回调函数本身无取值范围这一说法;
是否必选:必选;
注意事项:每次调用会覆盖之前注册的回调函数;
参数示例:
local function netdrv_multiple_notify_cbfunc(net_type,adapter)
if type(net_type)=="string" then
log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
elseif type(net_type)=="nil" then
log.warn("netdrv_multiple_notify_cbfunc", "no available adapter", net_type, adapter)
else
log.warn("netdrv_multiple_notify_cbfunc", "unknown status", net_type, adapter)
end
end
触发条件:
- 网卡切换时返回当前网卡类型和 ID
- 所有网卡断网时返回
nil, -1示例:
local function netdrv_multiple_notify_cbfunc(net_type,adapter)
if type(net_type)=="string" then
log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
elseif type(net_type)=="nil" then
log.warn("netdrv_multiple_notify_cbfunc", "no available adapter", net_type, adapter)
else
log.warn("netdrv_multiple_notify_cbfunc", "unknown status", net_type, adapter)
end
end
exnetif.notify_status(netdrv_multiple_notify_cbfunc)
exnetif.setproxy(adapter, main_adapter, other_configs)
功能
配置网络代理实现多网融合;
注意事项
填写 other_configs 参数时需要注意区分 adapter 和 main_adapter 的参数,参考下文参数中的说明;
参数
adapter
参数含义:使用网络的网卡;
数据类型:常量;
取值范围:取值范围参考第三部分常量详解;
是否必选:必选;
注意事项:暂无;
参数示例:socket.LWIP_AP
main_adapter
参数含义:提供网络的网卡;
数据类型:常量;
取值范围:取值范围参考第三部分常量详解;
是否必选:必选;
注意事项:暂无;
参数示例:socket.LWIP_ETH
other_configs
参数含义:开启网卡所需的配置参数;
{
-- 参数含义:AP热点名称,网卡包含wifi时填写;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
ssid = "test2",
-- 参数含义:AP热点密码,网卡包含wifi时填写;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
password = "HZ88888888",
-- 参数含义:AP模式下配置项;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
ap_opts = {
-- 参数含义:AP是否隐藏SSID, 默认false,不隐藏;
-- 数据类型:boolean;
-- 取值范围:true/false;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
hidden = false,
-- 参数含义:AP最大客户端数量;
-- 数据类型:number;
-- 取值范围:1-4;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
max_conn = 4 },
-- 参数含义:AP建立的通道;
-- 数据类型:number;
-- 取值范围:1-13;
-- 是否必选:可选;
-- 注意事项:暂无;
-- 参数示例:
channel = 6,
-- 参数含义:自定义LWIP_AP网卡的ip地址;
-- 数据类型:string;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:需要自定义ip和网关ip时填写
-- 参数示例:
adapter_addr = "192.168.5.1",
-- 参数含义:自定义LWIP_AP网卡的网关地址;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:需要自定义ip和网关ip时填写
-- 参数示例:
adapter_gw = { 192, 168, 5, 1 },
-- 参数含义:提供网络的网卡开启参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:暂无;
-- 参数示例:
main_adapter = {
-- 参数含义:供电使能引脚(GPIO号);
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:控制以太网模块供电使能
-- 参数示例:
pwrpin = 140,
-- 参数含义:网卡芯片型号;
-- 数据类型:常量,可参考第三部分常量详解;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:暂无;仅spi方式外挂以太网时需要填写;
-- 参数示例:
tp = netdrv.CH390,
-- 参数含义:外挂方式,需要额外的参数;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:暂无;仅spi方式外挂以太网时需要填写;
-- 参数示例:
opts = {
-- 参数含义:外挂的spi_id;
-- 数据类型:number;
-- 取值范围:0/1;
-- 是否必选:必选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
spi = 1,
-- 参数含义:外挂的spi片选引脚(GPIO号);
-- 数据类型:number;
-- 取值范围:暂无;
-- 是否必选:必选;
-- 注意事项:仅spi方式外挂以太网时需要填写;
-- 参数示例:
cs = 12
}
}
}
数据类型:table;
取值范围:暂无;
是否必选:必选;
注意事项:暂无;
参数示例:
{
ssid = "test2",
password = "HZ88888888",
main_adapter = {
ethpower_en = 13
}
}
返回值:
true:成功,false:失败 示例:
exnetif.setproxy(socket.LWIP_AP, socket.LWIP_ETH, {
ssid = "test2",
password = "HZ88888888",
main_adapter = {
ethpower_en = 140,
tp = netdrv.CH390,
opts = {spi = 1, cs = 12}
}
})
exnetif.check_network_status(interval)
dhcpsrv 扩展库
dhcpsrv.create(opts)
功能
创建一个 dhcp 服务器;
注意事项
无;
参数
opts
参数含义:dhcp参数设置;
{
-- 参数含义:网络适配器;
-- 数据类型:number;
-- 取值范围:参考第三节常量详解;
-- 是否必选:必选;
-- 注意事项:无;
-- 参数示例: socket.LWIP_AP
adapter,
-- 参数含义:网络掩码;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选,默认{255, 255, 255, 0};
-- 注意事项:无;
-- 参数示例: {255, 255, 255, 0}
mark,
-- 参数含义:网关;
-- 数据类型:table;
-- 取值范围:暂无;
-- 是否必选:可选,默认自动获取网卡IP,如果获取失败则使用 {192, 168, 4, 1};
-- 注意事项:无;
-- 参数示例: {192, 168, 4, 1}
gw,
-- 参数含义:分配的网段内的起始ip;
-- 数据类型:number;
-- 取值范围:2-255,不能使用网关的IP,不能超过ip_end;
-- 是否必选:可选.默认100;
-- 注意事项:无;
-- 参数示例: 100
ip_start,
-- 参数含义:分配的网段内的结束ip;
-- 数据类型:number;
-- 取值范围:ip_start 至 255;
-- 是否必选:可选,默认200;
-- 注意事项:无;
-- 参数示例: 200
ip_end,
-- 参数含义:客户端连接模块时的回调函数;
function(ip, mac)
log.info("ack_cb", "new client", ip, mac)
end
回调函数接收以下两个参数:
-- 参数含义:ip;
-- 数据类型:string;
-- 取值范围:无;
-- 是否必选:必选;
-- 参数示例:"192.168.4.100";
ip,
-- 参数含义:mac;
-- 数据类型:string;
-- 取值范围:无;
-- 是否必选:必选;
-- 参数示例:"2E4EDBB1A054";
mac
-- 数据类型:function;
-- 取值范围:暂无;
-- 是否必选:可选;
-- 注意事项:ack回调, 有客户端连接上来时触发, ip和mac地址会传进来;
-- 参数示例:
ack_cb
}
数据类型:table;
取值范围:暂无;
是否必选:可选;
注意事项:无;
参数示例:dhcpsrv.create({adapter=socket.LWIP_AP})
返回值:
local mydhcpsrv = dhcpsrv.create(ops) for ip, client in pairs(mydhcpsrv.clients) do log.info("client", ip, client.mac:toHex(), client.tm, client.stat) end
mydhcpsrv
含义说明:客户端列表;
{
clients =
{
-- 含义说明:ip的最后一段数字;
-- 数据类型:number;
-- 取值范围:2-255;
-- 注意事项:非完整ip;
-- 返回示例:100;
ip =
{
-- 含义说明:mac地址;
-- 数据类型:string;
-- 取值范围:无;
-- 注意事项:返回原始mac地址,打印时建议使用client.mac:toHex()转换成HEX字符串;
-- 返回示例:0x2E4EDBB1A054;
mac = 0x2E4EDBB1A054,
-- 含义说明:客户端连接的时间。设备开机到连接时的运行秒数;
-- 数据类型:number;
-- 取值范围:无;
-- 注意事项:会动态变化,出现重连时会更新数据;
-- 返回示例:6;
tm = 6,
-- 含义说明:客户端状态;
-- 数据类型:number;
-- 取值范围:1/3 1:已分配ip但未确认 3:已分配ip且已确认;
-- 注意事项:无;
-- 返回示例:1;
stat = 1
}
}
}
数据类型:table;
取值范围:无;
注意事项:-- clients是一个table, 包含MAC和IP的对应关系, 注意, IP只记录了最后一段数字, 非完整IP
-- 注意, clients是动态变化的过程, mydhcpsrv对象的其他属性切勿修改, 仅提供clients的只读功能;
返回示例:{ 100 = {mac = 0x2E4EDBB1A054 , tm = 6 , stat = 1}};
示例:
-- 创建一个dhcp服务器, 最简单的版本
dhcpsrv.create({adapter=socket.LWIP_AP})
-- 详细的版本
-- 创建一个dhcp服务器
local dhcpsrv_opts = {
adapter=socket.LWIP_AP, -- 监听哪个网卡, 必须填写
mark = {255, 255, 255, 0}, -- 网络掩码, 默认 255.255.255.0
gw = {192, 168, 4, 1}, -- 网关, 默认自动获取网卡IP,如果获取失败则使用 192.168.4.1
ip_start = 100, -- ip起始地址, 默认100
ip_end = 200, -- ip结束地址, 默认200
ack_cb = function(ip, mac)
log.info("ack_cb", "new client", ip, mac)
end -- ack回调, 有客户端连接上来时触发, ip和mac地址会传进来
}
local mydhcpsrv = dhcpsrv.create(dhcpsrv_opts)
-- 以下是一个打印客户端列表的例子, 非必选, 仅供参考
-- clients是一个table, 包含MAC和IP的对应关系, 注意, IP只记录了最后一段数字, 非完整IP
-- 注意, clients是动态变化的过程, mydhcpsrv对象的其他属性切勿修改, 仅提供clients的只读功能
local function get_client()
while true do
sys.wait(10000)
-- 这里可以打印一下当前的客户端列表
for ip, client in pairs(mydhcpsrv.clients) do
log.info("client", ip, client.mac:toHex(), client.tm, client.stat)
end
end
end
-- 以下是一个打印客户端列表的例子, 非必选, 仅供参考
-- clients是一个table, 包含MAC和IP的对应关系, 注意, IP只记录了最后一段数字, 非完整IP
-- 注意, clients是动态变化的过程, mydhcpsrv对象的其他属性切勿修改, 仅提供clients的只读功能
sys.taskInit(get_client)
-- 自动分配网段功能说明:
-- 如果不指定gw参数,系统会自动获取网卡IP作为网关地址
-- 这样可以确保DHCP分配的IP与网卡IP在同一网段
dnsproxy 扩展库
** dnsproxy.setup(adapter, main_adapter)**
功能
开启 dns 代理转发功能,用于不同网卡间转发 DNS 查询请求;
注意事项
无;
参数
adapter
参数含义:其他需要上网的设备连接到的合宙SOC网卡;
数据类型:number;
取值范围:参考第三节的常量详解;
是否必选:必选;
注意事项:无;
参数示例:socket.LWIP_AP
main_adapter
参数含义:合宙SOC用于连接互联网或内网的网卡;
数据类型:number;
取值范围:参考第三节的常量详解;
是否必选:必选;
注意事项:无;
参数示例:socket.LWIP_GP
返回值:
local res = dnsproxy.setup(adapter, main_adapter) log.info("dnsproxy.setup",res)
res
含义说明:创建结果;
数据类型:boolean;
取值范围:true/nil;
注意事项:返回值为true代表成功,nil代表创建失败;
返回示例:true;
示例:
dnsproxy.setup(socket.LWIP_AP, socket.LWIP_GP)
第七部分实战应用部分
单网卡:
完整 demo 代码可查看 https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/netdrv
以太网 LAN 模式配置(局域网通信)
演示模块以太网 LAN 模式,连接 PC 电脑开启的 TCP 服务器。
开发板以太网网口通过网线连接电脑
数据通过网线传播,模块需要初始化以太网
方式一,使用 netdrv 库开启 CH390(以太网传输芯片):
log.info("ch390", "打开LDO供电")
gpio.setup(140, 1, gpio.PULLUP) -- 打开ch390供电
local result = spi.setup(0, nil, 0, 0, 8 ,25600000) -- 开启spi
-- 初始化ch390网卡
netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {
spi = 1,
cs = 12
})
方式二,使用 exnetif 库开启 CH390(以太网传输芯片):
res = exnetif.setproxy(socket.LWIP_ETH, socket.LWIP_GP, {
ethpower_en = 140, -- 以太网模块的pwrpin引脚(gpio编号)
tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
opts = { spi = 1, cs = 12 }, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
adapter_addr = "192.168.4.1", -- 自定义LWIP_ETH网卡的ip地址(选填),需要自定义ip和网关ip时填写
adapter_gw = { 192, 168, 4, 1 } -- 自定义LWIP_ETH网卡的网关地址(选填),需要自定义ip和网关ip时填写
})
设置 ip
netdrv.ipv4(socket.LWIP_ETH, "192.168.4.1", "255.255.255.0", "192.168.4.1")
开启 dhcp 服务器
-- 模块开启dhcp服务器
dhcpsrv.create({
adapter = socket.LWIP_ETH
})
电脑打开 llcom 工具,开启 TCP 服务器。选择 ip,填写一个端口号。
模块连接电脑开启的 tcp 服务器进行数据收发
-- 创建客户端(指定网卡)
socket.create(socket.LWIP_ETH, TASK_NAME)
-- 设置客户端参数
result = socket.config(socket_client)
-- 连接服务器
result = libnet.connect(TASK_NAME, 15000, socket_client, SERVER_ADDR, SERVER_PORT)
以太网 WAN 模式配置
流程顺序:
1.获取配置:模块→(DHCP 请求)→ 路由器→(分配 IP、网关、DNS 服务器地址)→ 模块。
2.域名解析:模块→(DNS 查询:xxx.com)→ 路由器→(转发查询)→ 互联网DNS服务器→(返回 IP:x.x.x.x)→ 路由器→ 模块。
3.访问服务:模块→(HTTP 请求,目标 IP:x.x.x.x)→ 路由器(进行 NAT 转发)→ 目标服务器→(HTTP 响应)→ 路由器→ 模块。

方式一,使用 netdrv 库开启 CH390(以太网传输芯片):
这种方式仅帮助理解工作原理使用,在实际编程中不要使用这种方式,直接使用 exnetif 的第二种方式
log.info("ch390", "打开LDO供电")
gpio.setup(140, 1, gpio.PULLUP) -- 打开ch390供电
local result = spi.setup(0, nil, 0, 0, 8 ,25600000) -- 开启spi
-- 初始化ch390网卡
netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {
spi = 1,
cs = 12
})
-- 使用dhcp动态获取ip地址
netdrv.dhcp(socket.LWIP_ETH, true)
方式二,使用 exnetif 库开启 CH390(以太网传输芯片):
exnetif.set_priority_order({
{
ETHERNET = { -- 以太网配置
pwrpin = 140, -- 供电使能引脚(number)
tp = netdrv.CH390, -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
opts = {spi = 1, cs = 12}, -- 外挂方式,需要额外的参数(选填参数),仅spi方式外挂以太网时需要填写。
}
}
})
等待网卡初始化成功发起 http 请求
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("http_app_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
log.info("http", http.request("GET", "http://httpbin.air32.cn/bytes/4096", nil, nil, {
adapter = socket.LWIP_ETH
}).wait()) -- adapter指定为以太网联网方式
WiFi STA 模式配置
流程顺序:
1.获取配置:模块→(DHCP 请求)→ 路由器→(分配 IP、网关、DNS 服务器地址)→ 模块。
2.域名解析:模块→(DNS 查询:xxx.com)→ 路由器→(转发查询)→ 互联网DNS服务器→(返回 IP:x.x.x.x)→ 路由器→ 模块。
3.访问服务:模块→(HTTP 请求,目标 IP:x.x.x.x)→ 路由器(进行 NAT 转发)→ 目标服务器→(HTTP 响应)→ 路由器→ 模块。
wlan.connect("茶室-降功耗,找合宙!", "Air123456")
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("http_app_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
log.info("http", http.request("GET", "http://httpbin.air32.cn/bytes/4096", nil, nil, {
adapter = socket.LWIP_STA
}).wait()) -- adapter指定为wifi联网方式
WiFi AP 模式配置(局域网通信)
开启 wifi_ap
wlan.createAP("test2", "HZ88888888")
电脑打开 llcom 工具,开启 TCP 服务器。选择 ip,填写一个端口号。
模块建立 TCP 连接(指定 wifi_ap 网卡)
-- 创建客户端(指定网卡)
socket.create(socket.LWIP_STA, TASK_NAME)
-- 设置客户端参数
result = socket.config(socket_client)
-- 连接服务器
result = libnet.connect(TASK_NAME, 15000, socket_client, SERVER_ADDR, SERVER_PORT)
4G 模式配置
4G 流程顺序:
- 4G 模块 → 基站: 注册网络 激活默认承载(下发 IP、网关、DNS)
- 4G 模块 →DNS 服务器: DNS 查询请求, DNS 服务器 →4G 模块: 返回目标服务器 IP (通过 PGW 网关转发)
- 4G 模块 → 目标 HTTP 服务器: HTTP 请求,目标 HTTP 服务器 →4G 模块: HTTP 响应 (通过 PGW 网关转发)
插卡,等待联网成功后发起 http 请求
多网卡:
完整 demo 代码可查看 https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/socket https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/network_routing
双网卡同时工作
两路 tcp 连接同时进行:
wifi 以太网流程顺序:
1.获取配置:模块→(DHCP 请求)→ 路由器→(分配 IP、网关、DNS 服务器地址)→ 模块。
2.域名解析:模块→(DNS 查询:xxx.com)→ 路由器→(转发查询)→ 互联网DNS服务器→(返回 IP:x.x.x.x)→ 路由器→ 模块。
3.访问服务:模块→(HTTP 请求,目标 IP:x.x.x.x)→ 路由器(进行 NAT 转发)→ 目标服务器→(HTTP 响应)→ 路由器→ 模块。
4G 流程顺序:
- 4G 模块 → 基站: 注册网络 激活默认承载(下发 IP、网关、DNS)
- 4G 模块 →DNS 服务器: DNS 查询请求, DNS 服务器 →4G 模块: 返回目标服务器 IP
- 4G 模块 → 目标 HTTP 服务器: HTTP 请求(通过 PGW 网关转发),目标 HTTP 服务器 →4G 模块: HTTP 响应

-- 插卡,自动注册网络、
-- 连接wifi
wlan.connect("test3", "HZ88888888")
-- 开启两个tcp客户端
local function main_task()
require "tcp_client_main"
require "tcp_client_2"
end
4G 的 tcp 客户端
-- 等待4G网卡联网成功
while not socket.adapter(socket.LWIP_GP) do
log.warn("GP_SOCKET", "wait IP_READY", socket.LWIP_GP)
sys.waitUntil("IP_READY", 1000)
end
-- 使用4G网卡创建tcp连接
socket_client = socket.create(socket.LWIP_GP, TASK_NAME)
wifi 的 tcp 客户端
-- 等待wifi连接成功
while not socket.adapter(socket.LWIP_STA) do
log.warn("WIFI_SOCKET", "wait IP_READY", socket.LWIP_STA)
sys.waitUntil("IP_READY", 1000)
end
-- 使用wifi网卡创建tcp连接
socket_client = socket.create(socket.LWIP_STA, TASK_NAME)
记得修改不同的 taskname
tcp_client_sender.TASK_NAME = "tcp_client_wifi"
tcp_client_sender.TASK_NAME = "tcp_client_4G"
电脑的 wifi 热点抓包
4G 模块底层日志导出网络包

多网卡优先级功能
首先 exnetif 开启后会初始化所有设置了优先级的网卡,并根据设置的优先级依次判断网卡是否可用,确认可用的最高优先级的网卡为默认网卡,在 socket.create(nil, TASK_NAME)时,网卡参数填写 nil,就会使用默认网卡进行连接
开启网络优先级功能
exnetif.set_priority_order(
{
-- WIFI STA网卡
{
WIFI = {
-- 要连接的WIFI路由器名称
ssid = "茶室-降功耗,找合宙!",
-- 要连接的WIFI路由器密码
password = "Air123456",
-- 连通性检测ip(选填参数);
-- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
-- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
-- ping_ip = "填入可靠的并且可以ping通的ip地址",
}
},
-- 4G网卡
{
LWIP_GP = true
}
}
)
进入网页点击打开 tcp
标题右侧会相应显示端口号_34058_

- 建立 TCP 连接 1(不指定网卡,exnetif 库自动确认使用网卡)
-- 创建客户端(指定网卡)
socket.create(nil, TASK_NAME)
-- 设置客户端参数
result = socket.config(socket_client)
-- 连接服务器
result = libnet.connect(TASK_NAME, 15000, socket_client, SERVER_ADDR, SERVER_PORT)
多网融合功能(NAPT)
多网融合功能,支持的场景如下:
注:图中的内网是指无法访问外部互联网,只能在一个局域网内通讯,或使用专网卡或专线在多个局域网中通讯
1.需要联网的设备连接模块 wifi 热点,模块内部使用 napt 功能将 4G 网卡作为数据出口实现互联网访问功能
2.需要联网的设备使用网线连接模块网口,模块内部使用 napt 功能将 4G 网卡作为数据出口实现互联网访问功能
3.需要联网的设备使用网线连接模块网口,模块内部使用 napt 功能将 WIFI STA 网卡作为数据出口实现互联网访问功能
4.需要联网的设备连接模块热点,模块内部使用 napt 功能将以太网 LAN 网卡作为数据出口实现互联网访问功能
这里演示使用 exnetif 扩展库开启多网融合功能,将 wifi 热点的数据通过 4G 网络作为数据出口连接互联网
进入网页 https://iot.luatos.com/并使用 iot 账户注册登录
点击页面中的打开 tcp 按钮,会创建一个 tcp 服务端并给出端口号
第八部分问题分析与解决
8.1 问题排查流程
- 硬件排查:确认网线、天线、SIM 卡等物理连接正常, netdrv.link(网卡)确认网卡是否初始化正常
- 是否成功获取到 ip,网关,dns 等信息,或手动配置了正确的信息。日志中会有相关的打印,或 log.info("静态 ip",netdrv.ipv4(网卡))手动打印信息。
- 远程服务器信息是否正确填写,连接服务器失败时,可以使用我们的测试服务器对比测试下,确认是服务器或网络的问题。
8.2 日志抓取与分析
8.2.1 使用以太网,报错读取 vid/pid 失败,检查接线。
可能的原因:
1.ch390 芯片供电未打开
2.设置了错误的 spi id 或 cs
3.如果是核心板 + 扩展板的组合使用杜邦线连接,可以更换 5cm 线长的杜邦线测试减少干扰
8.2.2 dns 解析失败
可能的原因:
1.自动获取的 dns 解析服务器已失效
2.手动设置时设置了错误的 dns 解析服务器

8.2.3 网络正常,但 mqtt,http,tcp 等连接失败
可能的原因:
1.填写了错误的域名或 ip
2.使用专网卡但未设置白名单
3.需要使用 tls 加密连接,代码未修改
