socket - 网络接口
作者:王城钧
一、概述
socket 库作为网络通信的核心工具,socket 库本身是异步非阻塞 api,提供了跨平台、多协议支持的标准化编程接口,能够高效实现设备间基于 TCP/UDP 协议的数据可靠传输或实时交互。与之对应的 libnet 库是在 socket 库基础上的同步阻塞 api,socket 库本身是异步非阻塞 api,开发 socket 应用程序时,强烈推荐优先使用 libnet 的同步接口,我们的 demo 也是以使用 libnet 的同步接口为主。
libnet 扩展库 api 文档链接:libnet
二、核心示例
1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/socket/client/long_connection
注意:如下演示的为 TCP 的 client 端 demo
-- 关于本库的一些说明:本文中的描述内容,使用了网卡和网络适配器这两种概念,这两种概念所表达的意思完全一样;
-- 本库用于网络通信, 支持TCP, UDP, 也支持TLS加密传输;
-- 支持加密传输版本有 TLS 1.0/1.1/1.2/1.3, DTLS 1.0/1.2, 当前不支持TLS 1.3;
-- 不支持 SSL 3.0, 该协议已经被废弃, 也不安全;
-- 支持的加密算法有 RSA, ECC, AES, 3DES, SHA1, SHA256, MD5 等等;
-- 完整的加密套件列表, 可通过 crypto.cipher_suites() 获取;
-- 本库的函数, 除非特别说明, 都是立即返回的非阻塞函数;
-- 这意味着, 函数调用成功, 并不代表网络操作成功, 只代表网络操作已经开始;
PROJECT = "SOCKET_CONNECTION"
VERSION = "001.000.000"
local libnet = require "libnet"
local SERVER_ADDR = "112.125.89.8" -- 根据实际修改
local SERVER_PORT = 47826 -- 根据实际修改
local TASK_NAME = "socket_connect_task"
local send_queue = {}
local TCP_SENDER_TASK_NAME = "tcp_send_task"
local recv_buff = nil
local function send_data_req_proc_func(tag, data, cb)
table.insert(send_queue, {data = "send from "..tag..": "..data, cb = cb})
sys.sendMsg(TCP_SENDER_TASK_NAME, socket.EVENT, 0)
end
function tcp_clientc_sender_proc(task_name, socket_client)
while #send_queue > 0 do
local send_item = table.remove(send_queue, 1)
-- 发送这条数据,超时时间15秒钟
local result = libnet.tx(task_name, 15000, socket_client, send_item.data)
-- 发送失败
if not result then
log.error("tcp_client_sender.proc", "libnet.tx error")
-- 如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(false, send_item.cb.para)
end
return false
end
log.info("tcp_client_sender.proc", "send success")
-- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
if send_item.cb and send_item.cb.func then
send_item.cb.func(true, send_item.cb.para)
end
end
return true
end
function tcp_client_sender_exception_proc()
while #send_queue > 0 do
local send_item = table.remove(send_queue, 1)
if send_item.cb and send_item.cb.func then
send_item.cb.func(false, send_item.cb.para)
end
end
end
sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
function tcp_client_receiver_proc(socket_client)
-- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
if recv_buff == nil then
recv_buff = zbuff.create(1024)
end
while true do
local result = socket.rx(socket_client, recv_buff)
if not result then
log.error("tcp_client_receiver_proc", "socket.rx error")
return false
end
-- 如果读取到了数据, used()就必然大于0, 进行处理
if recv_buff:used() > 0 then
log.info("tcp_client_receiver_proc", "recv data len", recv_buff:used())
-- 读取socket数据接收缓冲区中的数据,赋值给data
local data = recv_buff:query()
-- 将数据data通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
sys.publish("RECV_DATA_FROM_SERVER", "recv from tcp server: ", data)
recv_buff:del()
else
break
end
end
return true
end
local function tcp_client_main_task_func()
local socket_client
local result, para1, para2
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
while not socket.adapter(socket.dft()) do
log.warn("tcp_client_main_task_func", "wait IP_READY", socket.dft())
sys.waitUntil("IP_READY", 1000)
end
-- 检测到了IP_READY消息
log.info("tcp_client_main_task_func", "recv IP_READY", socket.dft())
-- 创建socket client对象
socket_client = socket.create(nil, TASK_NAME)
-- 如果创建socket client对象失败
if not socket_client then
log.error("tcp_client_main_task_func", "socket.create error")
goto EXCEPTION_PROC
end
-- 配置socket client对象为tcp client
result = socket.config(socket_client)
-- 如果配置失败
if not result then
log.error("tcp_client_main_task_func", "socket.config error")
goto EXCEPTION_PROC
end
-- 连接server
result = libnet.connect(TASK_NAME, 15000, socket_client, SERVER_ADDR, SERVER_PORT)
-- 如果连接server失败
if not result then
log.error("tcp_client_main_task_func", "libnet.connect error")
goto EXCEPTION_PROC
end
log.info("tcp_client_main_task_func", "libnet.connect success")
while true do
if not tcp_client_receiver_proc(socket_client) then
log.error("tcp_client_main_task_func", "tcp_client_receiver_proc error")
break
end
if not tcp_clientc_sender_proc(TASK_NAME, socket_client) then
log.error("tcp_client_main_task_func", "tcp_client_sender_proc error")
break
end
result, para1, para2 = libnet.wait(TASK_NAME, 15000, socket_client)
log.info("tcp_client_main_task_func", "libnet.wait", result, para1, para2)
if not result then
log.warn("tcp_client_main_task_func", "connection exception")
break
end
end
-- 出现异常
::EXCEPTION_PROC::
-- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
tcp_client_sender_exception_proc()
-- 如果存在socket client对象
if socket_client then
-- 关闭socket client连接
libnet.close(TASK_NAME, 5000, socket_client)
-- 释放socket client对象
socket.release(socket_client)
socket_client = nil
end
sys.wait(5000)
end
end
sys.taskInitEx(tcp_client_main_task_func, TASK_NAME)
sys.run()
三、常量详解
核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
关于网络适配器类型的常量:
注意:目前除 8101 系列产品默认网络适配器为 socket.LWIP_STA,其他主流模组默认网络适配器为 socket.LWIP_GP。
socket.LWIP_GP
常量含义:通过蜂窝网络实现数据传输,
使用LWIP协议栈的移动蜂窝模块,值为1;
数据类型:number;
取值范围:暂无;
示例代码:socket.localIP(socket.LWIP_GP);
socket.LWIP_STA
常量含义:设备作为 Wi-Fi 客户端,连接到现有无线路由器或热点,
使用LWIP协议栈的WIFI STA,值为2;
数据类型:number;
取值范围:暂无;
示例代码:socket.localIP(socket.LWIP_STA);
socket.LWIP_AP
常量含义:设备作为无线热点,供其他设备连接,
使用LWIP协议栈的WIFI AP,值为3;
数据类型:number;
取值范围:暂无;
示例代码:socket.localIP(socket.LWIP_AP);
socket.LWIP_ETH
常量含义:软件模拟的以太网接口,依赖 LWIP 协议栈实现网络通信,
使用LWIP协议栈的以太网卡,值为4;
数据类型:number;
取值范围:暂无;
示例代码:socket.localIP(socket.LWIP_ETH);
socket.ETH0
常量含义:指设备内置的以太网控制器,直接通过硬件协议栈处理网络数据,无需额外软件模拟,
带硬件协议栈的 ETH0 接口,值为5;
数据类型:number;
取值范围:暂无;
示例代码:socket.localIP(socket.ETH0);
socket.USB
常量含义:通过 USB 接口模拟以太网功能(如 RNDIS 协议),
使用LWIP协议栈的USB网卡,值为6;
数据类型:number;
取值范围:暂无;
示例代码:socket.localIP(socket.USB);
socket.LWIP_USER0
常量含义:使用LWIP协议栈的自定义网卡0,值为0;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER1
常量含义:使用LWIP协议栈的自定义网卡1,值为1;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER2
常量含义:使用LWIP协议栈的自定义网卡2,值为2;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER3
常量含义:使用LWIP协议栈的自定义网卡3,值为3;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER4
常量含义:使用LWIP协议栈的自定义网卡4,值为4;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER5
常量含义:使用LWIP协议栈的自定义网卡5,值为5;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER6
常量含义:使用LWIP协议栈的自定义网卡6,值为6;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_USER7
常量含义:使用LWIP协议栈的自定义网卡7,值为7;
数据类型:number;
取值范围:暂无;
示例代码:暂无;
socket.LWIP_GP_GW
常量含义:4G代理网关;
数据类型:number;
取值范围:暂无;
示例代码:netdrv.setup(socket.LWIP_GP_GW, netdrv.WHALE);
关于网络事件的常量:
socket.LINK
常量含义:表示socket的物理链路连接状态事件,
当设备与网络的物理连接(如4G模块的基站连接)建立或断开时触发;
数据类型:number;
取值范围:暂无;
示例代码:if event == socket.LINK then
log.info("连接成功")
socket.ON_LINE
常量含义:表示socket的网络就绪状态事件,
设备成功接入网络时触发;
数据类型:number;
取值范围:暂无;
示例代码:if event == socket.ON_LINE then
socket.tx(netc, "hello,luatos!")
socket.EVENT
常量含义:表示通用事件标识,具体含义需结合上下文或参数判断,
用于标识自定义事件或未明确分类的socket事件;
数据类型:number;
取值范围:暂无;
示例代码:if event == socket.EVENT then
socket.rx(netc, rxbuf)
socket.wait(netc)
if rxbuf:used() > 0 then
log.info("收到", rxbuf:toStr(0,rxbuf:used()):toHex())
log.info("发送", rxbuf:used(), "bytes")
socket.tx(netc, rxbuf)
end
socket.TX_OK
常量含义:表示数据发送成功事件,
当socket成功发送数据到对端时触发;
数据类型:number;
取值范围:暂无;
示例代码:if event == socket.TX_OK then
socket.wait(netc)
log.info("发送完成")
socket.CLOSED
常量含义:表示socket连接已关闭事件,
当连接因主动关闭、故障中断或服务器断开时触发;
数据类型:number;
取值范围:暂无;
示例代码:if event == socket.CLOSED then
sys.publish("socket_disconnect")
end
四、函数详解
socket.localIP(adapter)
功能
获取本地 ip
参数
adapter
参数含义:表示适配器序号;
数据类型:number;
取值范围:本文常量详解章节中的所有网络适配器常量,例如:socket.LWIP_GP;
是否必选:可选传入此参数;
注意事项:若不填入此参数,默认是平台自带的能上外网的适配器;
参数示例:socket.LWIP_GP;
返回值
local ip, netmask, gateway = socket.localIP()
有三个返回值 ip, netmask, gateway
ip
含义说明:返回IP地址;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"10.39.154.32";
netmask
含义说明:返回网络掩码;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"255.255.255.255";
gateway
含义说明:返回网关IP;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"0.0.0.0";
示例
local function get_ip()
while 1 do
sys.wait(3000)
local ip, netmask, gateway = socket.localIP()
log.info("socket", "ip", ip, "netmask", netmask, "gateway", gateway)
end
end
sys.taskInit(get_ip)
-- 日志打印示例
-- socket ip 10.39.154.32 netmask 255.255.255.255 gateway 0.0.0.0
socket.create(adapter, task_name)
功能
在指定网卡上申请一个 socket_ctrl
参数
adapter
参数含义:上网使用的网卡ID;
数据类型:number或者nil;
取值范围:number类型时,取值范围参考socket api中的常量详解;
是否必选:可选传入此参数;
注意事项:如果没有传入此参数,内核固件会自动选择当前时间点其他功能模块设置的默认网卡;
除非你socket请求时,一定要使用某一种网卡,才设置此参数;
如果没什么特别要求,不要设置此参数,使用系统中设置的默认网卡即可;
一般来说,LuatOS的网络应用demo中都会有netdrv_device功能模块设置默认网卡;
所以建议不要设置此参数,直接使用netdrv_device设置的默认网卡就行;
参数示例:socket.LWIP_GP表示使用4G网卡;
task_name
参数含义:为消息通知的taskName;
数据类型:string;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"socket_client_task";
返回值
local netc = socket.create(nil, "Mysocket")
netc
含义说明:成功返回socket_ctrl,失败返回nil;
数据类型:userdata;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
--[[
当通过回调函数回调消息时,输入给function一共3个参数:
param1为申请的socket_ctrl
param2为具体的消息,只能是socket.LINK, socket.ON_LINE, socket.TX_OK, socket.EVENT, socket.CLOSED等等
param3为消息对应的参数,目前只有0和-1,0表示成功或者可能有新数据(具体消息为socket.EVENT),-1表示失败或者有异常,需要断开重连
]]
-- 创建socket client对象
socket_client = socket.create(nil, TASK_NAME)
-- 如果创建socket client对象失败
if not socket_client then
log.error("tcp_client_main_task_func", "socket.create error")
goto EXCEPTION_PROC
end
socket.debug(ctrl, onoff)
功能
配置是否打开 debug 信息
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
onoff
参数含义:表示是否打开debug信息;
数据类型:boolean;
取值范围:true打开debug开关,false关闭debug开关;
是否必选:可选传入此参数,若不填此参数,默认为false;
注意事项:暂无;
参数示例:true;false;
返回值
nil
示例
local function socketTask()
local netc = socket.create(nil, netCB) --创建一个链接
socket.debug(netc, true)--开启socket层的debug日志,方便寻找问题
socket.config(netc, nil, is_udp, nil, 300, 5, 6) --配置TCP链接的参数,开启保活,防止长时间无数据交互服务器踢掉模块
while true do
--真正去链接服务器
local succ, result = socket.connect(netc, server_ip, server_port)
--链接成功后循环发送数据
while succ do
local Heartbeat_interval = Heartbeat_interval * 60 * 1000
sys.wait(Heartbeat_interval)
socket.tx(netc, heart_data)
end
--链接不成功5S重连一次
if not succ then
log.info("未知错误,5秒后重连")
uart.write(1, "未知错误,5秒后重连")
else
local result, msg = sys.waitUntil("socket_disconnect")
end
log.info("服务器断开了,5秒后重连")
uart.write(1, "服务器断开了,5秒后重连")
socket.close(netc)
sys.wait(5000)
end
end
sys.taskInit(socketTask)
socket.config(ctrl, local_port, is_udp, is_tls, keep_idle, keep_interval, keep_cnt, server_cert, client_cert, client_key, client_password)
功能
配置 socket ctrl 一些信息
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
local_port
参数含义:本地端口号;
数据类型:number;
取值范围:端口号需要小于60000;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:80;
is_udp
参数含义:是否是UDP;
数据类型:boolean;
取值范围:true或false;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true;
is_tls
参数含义:是否是加密传输;
数据类型:boolean;
取值范围:true或false;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:true;
keep_idle
参数含义:在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测包的间隔,
即允许的持续空闲时长,或者说每次正常发送心跳的周期,默认值为7200s(2h);
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数,如果留空则表示不启;
注意事项:如果是不支持标准posix接口的网卡(比如W5500),则为心跳间隔;
参数示例:300;
keep_interval
参数含义:在tcp保活设定时间之后,没有接收到对方确认,
继续发送保活探测包的发送间隔,默认值为75s。;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:75;
keep_cnt
参数含义:在TCP保活打开的情况下,最大允许发送保活探测包的次数,
到达此次数后直接放弃尝试,并关闭连接,默认值为9(次);
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:9;
server_cert
参数含义:TCP服务器ca证书数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当客户端需要验证服务器证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给server_ca_cert;
参数示例:例如通过Luatools烧录了server_ca.crt文件,就可以通过io.readFile("/luadb/server_ca.crt")读出文件内容赋值给赋值给server_ca_cert;
client_cert
参数含义:TCP模式下的客户端证书数据,UDP模式下的PSK-ID,
TCP模式下如果不需要验证客户端证书时,忽略,一般不需要验证客户端证书;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当服务器需要验证客户端证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给client_cert;
参数示例:例如通过Luatools烧录了clinet.crt文件,就可以通过io.readFile("/luadb/clinet.crt")读出文件内容赋值给赋值给client_cert;
client_key
参数含义:TCP模式下的客户端私钥加密数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_key;
参数示例:例如通过Luatools烧录了clinet.key文件,就可以通过io.readFile("/luadb/clinet.key")读出文件内容赋值给client.key;
client_password
参数含义:TCP模式下的客户端私钥加密数据;
数据类型:string或者nil;
取值范围:无特别限制;
是否必选:可选传入此参数;
注意事项:当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_password;
参数示例:例如通过Luatools烧录了clinet.password文件,就可以通过io.readFile("/luadb/clinet.password")读出文件内容赋值给client_password;
返回值
local netc = socket.create(nil, netCB)
netc
含义说明:成功返回true,失败返回false;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
local function socketTask()
local netc = socket.create(nil, netCB) --创建一个链接
socket.debug(netc, true)--开启socket层的debug日志,方便寻找问题
socket.config(netc, nil, is_udp, nil, 300, 5, 6) --配置TCP链接的参数,开启保活,防止长时间无数据交互服务器踢掉模块
while true do
--真正去链接服务器
local succ, result = socket.connect(netc, server_ip, server_port)
--链接成功后循环发送数据
while succ do
local Heartbeat_interval = Heartbeat_interval * 60 * 1000
sys.wait(Heartbeat_interval)
socket.tx(netc, heart_data)
end
--链接不成功5S重连一次
if not succ then
log.info("未知错误,5秒后重连")
uart.write(1, "未知错误,5秒后重连")
else
local result, msg = sys.waitUntil("socket_disconnect")
end
log.info("服务器断开了,5秒后重连")
uart.write(1, "服务器断开了,5秒后重连")
socket.close(netc)
sys.wait(5000)
end
end
sys.taskInit(socketTask)
socket.linkup(ctrl)
功能
等待网卡 linkup(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, result = socket.linkup(ctrl)
succ
含义说明:表示函数调用的同步结果,true没有异常发生,false失败了,如果false则不需要看下一个返回值了;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
result
含义说明:true已经linkup,false没有linkup,之后需要接收socket.LINK消息;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
socket.connect(ctrl, ip, remote_port, need_ipv6_dns)
功能
作为客户端连接服务器(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
ip
参数含义:ip地址 或者 int ip或者域名,如果是IPV4,可以是大端格式的number值;
数据类型:string或者number;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
remote_port
参数含义:服务器端口号,小端格式;
数据类型:number;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
need_ipv6_dns
参数含义:域名解析是否要IPV6,true要,false不要,默认false不要,只有支持IPV6的协议栈才有效果;
数据类型:boolean;
取值范围:true或false;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, result = socket.connect(ctrl, ip, remote_port)
succ
含义说明:true没有异常发生,false失败了,如果false则不需要看下一个返回值了,如果有异常,后续要close;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
result
含义说明:true已经connect,false没有connect,之后需要接收socket.ON_LINE消息;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
--[[
常见的连接失败的code值, 会在日志中显示
-1 底层内存不足
-3 超时
-8 端口已经被占用
-11 链接未建立
-13 模块主动断开连接
-14 服务器主动断开连接
]]
socket.discon(ctrl)
功能
作为客户端断开连接(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, result = socket.discon(ctrl)
succ
含义说明:true没有异常发生,false失败了,如果false则不需要看下一个返回值了;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
result
含义说明:true已经断开,false没有断开,之后需要接收socket.CLOSED消息;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
socket.close(ctrl)
功能
强制关闭 socket(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
nil
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
socket.tx(ctrl, data, ip, port, flag)
功能
发送数据给对端,UDP 单次发送不要超过 1460 字节,否则很容易失败(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
data
参数含义:待发送的数据 或者 userdata zbuff 要发送的数据;
数据类型:string/zbuff;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
ip
参数含义:对端IP,如果是TCP应用则忽略,
如果是UDP,如果留空则用connect时候的参数,
如果是IPV4,可以是大端格式的number值;
数据类型:string或者number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
port
参数含义:对端端口号,小端格式,如果是TCP应用则忽略,如果是UDP,如果留空则用connect时候的参数;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
flag
参数含义:发送参数,目前预留,不起作用;
数据类型:int;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, full, result = socket.tx(ctrl, "123456", "xxx.xxx.xxx.xxx", xxxx)
succ
含义说明:true没有异常发生,false失败了,如果false则不需要看下一个返回值了,
如果false,后续要close;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
full
含义说明:true缓冲区满了,false没有满,
如果true,则需要等待一段时间或者等到socket.TX_OK消息后再尝试发送,同时忽略下一个返回值;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
result
含义说明:true已经收到应答,false没有收到应答,
之后需要接收socket.TX_OK消息, 也可以忽略继续发送,直到full==true;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
socket.rx(ctrl, buff, flag, limit)
功能
接收对端发出的数据,注意数据已经缓存在底层,使用本函数只是提取出来,UDP 模式下一次只会取出一个数据包
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
buff
参数含义:zbuff 存放接收的数据,如果缓冲区不够大会自动扩容;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
flag
参数含义:接收参数,目前预留,不起作用;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
limit
参数含义:接收数据长度限制,如果指定了,则只取前N个字节;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, data_len, remote_ip, remote_port = socket.rx(ctrl)
succ
含义说明:true没有异常发生,false失败了,如果false则不需要看下一个返回值了,
如果false,后续要close;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
data_len
含义说明:本次接收到数据长度;
数据类型:int;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
remote_ip
含义说明:对端IP,只有UDP模式下才有意义,TCP模式返回nil,
注意返回的格式,如果是IPV4,1byte 0x00 + 4byte地址;如果是IPV6,1byte 0x01 + 16byte地址;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:如果是IPV4,以返回的hex值"00707D5908"为例,
此返回值共有5个字节,其中第一个字节固定为0x00,第二个字节0x70,第三个字节0x7D,第四个字节0X59,第五个字节0x08
转化为由4个点分十进制数组成的"ip地址"就为112.125.89.8;
remote_port
含义说明:对端port,只有UDP模式下才有意义,TCP模式返回0;
数据类型:number;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
function udp_client_receiver.proc(socket_client)
-- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
if recv_buff==nil then
recv_buff = zbuff.create(1024)
end
while true do
-- 从内核的缓冲区中读取数据到recv_buff中
-- 如果recv_buff的存储空间不足,会自动扩容
local result = socket.rx(socket_client, recv_buff)
if not result then
log.error("udp_client_receiver.proc", "socket.rx error")
return false
end
-- 如果读取到了数据, used()就必然大于0, 进行处理
if recv_buff:used() > 0 then
log.info("udp_client_receiver.proc", "recv data len", recv_buff:used())
-- 读取socket数据接收缓冲区中的数据,赋值给data
local data = recv_buff:query()
-- 将数据data通过"RECV_DATA_FROM_SERVER"消息publish出去,给其他应用模块处理
sys.publish("RECV_DATA_FROM_SERVER", "recv from udp server: ", data)
-- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
-- 清空socket数据接收缓冲区中的数据
recv_buff:del()
-- 读取成功,但是读出来的数据为空,表示已经没有数据可读,可以退出循环了
else
break
end
end
return true
end
socket.read(netc, len)
功能
读取数据(非 zbuff 版本)
netc
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
len
参数含义:限制读取数据长度,可选,不传就是读出全部;
数据类型:int;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local success, data, ip, port = socket.read(netc, 1024)
success
含义说明:true表示读取成功,false表示读取失败;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
data
含义说明:读取的数据,仅当读取成功时有效;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
ip
含义说明:对方IP地址,仅当读取成功且UDP通信时有效;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
port
含义说明:对方端口,仅当读取成功且UDP通信时有效;
数据类型:number;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
-- 本函数于2024.4.8添加, 用于简易读取不大的数据
-- 请优先使用socket.rx函数, 本函数主要用于固件不含zbuff库时的变通调用
local ok, data = socket.read(netc, 1500)
if ok and data > 0 then
log.info("读取到的数据", data)
end
socket.wait(ctrl)
功能
等待新的 socket 消息,在连接成功和发送数据成功后,使用一次将 network 状态转换到接收新数据
(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, result = socket.wait(ctrl)
succ
含义说明:true没有异常发生,false失败了,
如果false则不需要看下一个返回值了,如果false,后续要close;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
result
含义说明:true有新的数据需要接收,false没有数据,之后需要接收socket.EVENT消息;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
socket.listen(ctrl)
功能
作为服务端开始监听(此函数给 libnet 扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用)
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, result = socket.listen(ctrl)
succ
含义说明:true没有异常发生,false失败了,
如果false则不需要看下一个返回值了,如果false,后续要close;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
result
含义说明:true已经connect,false没有connect,之后需要接收socket.ON_LINE消息;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
--此函数给libnet扩展库使用,用户不用深入了解,也不建议在应用脚本中去使用,不再举例。
socket.accept(ctrl)
功能
作为服务端接收到一个新的客户端,注意,如果是类似 W5500 的硬件协议栈不支持 1 对多,则不需要第二个参数
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local succ, new_netc = socket.accept(ctrl, cb)
succ
含义说明:true没有异常发生,false失败了,
如果false则不需要看下一个返回值了,如果false,后续要close;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
new_netc
含义说明:或者 nil 如果支持1对多,则会返回新的ctrl,自动create,如果不支持则返回nil;
数据类型:userdata;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
function ipv6task(d1Name, txqueue, rxtopic)
-- 本地监听的端口
local port = 14000
local rx_buff = zbuff.create(1024)
local tx_buff = zbuff.create(4 * 1024)
local netc = socket.create(nil, d1Name)
socket.config(netc, 14000)
log.info("任务id", d1Name)
while true do
log.info("socket", "开始监控")
local result = libnet.listen(d1Name, 0, netc)
if result then
log.info("socket", "监听成功")
result = socket.accept(netc, nil) --只支持1对1
if result then
log.info("客户端连上了")
end
else
log.info("socket", "监听失败!!")
end
while result do
-- log.info("socket", "调用rx接收数据")
local succ, param = socket.rx(netc, rx_buff)
if not succ then
log.info("客户端断开了", succ, param, ip, port)
break
end
if rx_buff:used() > 0 then
log.info("socket", "收到客户端数据,长度", rx_buff:used())
local data = rx_buff:query() -- 获取数据
sys.publish(rxtopic, "downlink", data)
rx_buff:del()
end
-- log.info("libnet", "调用wait开始等待消息")
result, param, param2 = libnet.wait(d1Name, 15000, netc)
log.info("libnet", "wait", result, param, param2)
if not result then
-- 网络异常了
log.info("socket", "客户端断开了", result, param)
break
elseif #txqueue > 0 then
local force_close = false
while #txqueue > 0 do
local data = table.remove(txqueue, 1)
if not data then
break
end
log.info("socket", "上行数据长度", #data)
if data == "close" then
--sys.wait(1000)
force_close = true
break
end
tx_buff:del()
tx_buff:copy(nil, data)
result,param = libnet.tx(d1Name, 15000, netc, tx_buff)
log.info("libnet", "发送数据的结果", result, param)
if not result then
log.info("socket", "数据发送异常", result, param)
break
end
end
if force_close then
break
end
end
end
log.info("socket", "连接已断开,继续下一个循环")
libnet.close(d1Name, 5000, netc)
-- log.info(rtos.meminfo("sys"))
sys.wait(50)
end
end
sys.taskInit(ipv6test)
socket.state(ctrl)
功能
获取 socket 当前状态
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local state, str = socket.state(ctrl)
state
含义说明:如果支持1对多,则会返回新的ctrl,自动create,如果不支持则返回nil;
数据类型:number或者nil;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
_str _
含义说明:输入参数正确的情况下,返回状态的中文描述,否则返回nil;
数据类型:string/nil;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
local state, str = socket.state(ctrl)
log.info("state", state, str)
state 0 "硬件离线",
1 "离线",
2 "等待DNS",
3 "正在连接",
4 "正在TLS握手",
5 "在线",
6 "在监听",
7 "正在离线",
8 "未知"
socket.release(ctrl)
功能
主动释放掉 socket_ctrl
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
nil
示例
-- 释放后就不能再使用了
-- 如果存在socket client对象
if socket_client then
-- 关闭socket client连接
libnet.close(TASK_NAME, 5000, socket_client)
-- 释放socket client对象,释放后就不能再使用了
socket.release(socket_client)
socket_client = nil
end
socket.setDNS(adapter_index, dns_index, ip)
设置 DNS 服务器
参数
adapter_index
参数含义:适配器序号,前面章节网络适配器常量里面的适配器,
如果不填,会选择最后一个注册的适配器;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
dns_index
参数含义:dns服务器序号,从1开始;
数据类型:number;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
ip
参数含义:ip地址 或者 int ip或者域名,如果是IPV4,可以是大端格式的number值;
数据类型:string或者number;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local result = socket.setDNS(adapter_index, dns_index, ip)
result
含义说明:成功返回true,失败返回false;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
示例
function ipv6test()
-- 启用IPv6, 默认关闭状态,必须在驻网前开启
-- 注意, 启用IPv6, 联网速度会慢2~3秒
mobile.ipv6(true)
log.info("ipv6", "等待联网")
sys.waitUntil("IP_READY")
log.info("ipv6", "联网完成")
sys.wait(100)
socket.setDNS(nil, 1, "119.29.29.29")
socket.setDNS(nil, 2, "114.114.114.114")
-- 开始正在的逻辑, 发起socket链接,等待数据/上报心跳
local taskName = "ipv6client"
local topic = taskName .. "_txrx"
local txqueue = {}
sys.taskInitEx(ipv6task, taskName, netCB, taskName, txqueue, topic)
while 1 do
local result, tp, data = sys.waitUntil(topic, 30000)
if not result then
-- 等很久了,没数据上传/下发, 发个日期心跳包吧
table.insert(txqueue, string.char(0))
sys_send(taskName, socket.EVENT, 0)
elseif tp == "uplink" then
-- 上行数据, 主动上报的数据,那就发送呀
table.insert(txqueue, data)
sys_send(taskName, socket.EVENT, 0)
elseif tp == "downlink" then
-- 下行数据,接收的数据, 从ipv6task来的
-- 其他代码可以通过 sys.publish()
log.info("socket", "收到下发的数据了", #data)
end
end
end
sys.taskInit(ipv6test)
socket.sslLog(log_level)
功能
设置 SSL 的 log 等级
参数
log_level
参数含义:mbedtls log等级;
数据类型:number;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
nil
示例
--[[
SSL/TLS log级别说明
0不打印
1只打印错误和警
2大部分info
3及3以上详细的debug
过多的信息可能会造成内存碎片化
]]
-- 打印大部分info日志
socket.sslLog(2)
socket.adapter(index)
功能
查看网卡适配器的联网状态
参数
index
参数含义:需要查看的适配器序号,可以留空会查看全部网卡,直到遇到IP READY的,
如果指定网卡,支持上文中网卡适配器中的所有常量;
数据类型:int;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local isReady,index = socket.adapter()
isReady
含义说明:被查看的适配器是否IP READY,true表示已经准备好可以联网了,false暂时不可以联网;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:暂无;
index
含义说明:最后一个被查看的适配器序号;
数据类型:number;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
while not socket.adapter(socket.dft()) do
log.warn("tcp_ssl_ca_main_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
socket.remoteIP(ctrl)
功能
获取对端 ip
参数
ctrl
参数含义:socket.create得到的ctrl;
数据类型:userdata;
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local ip1,ip2,ip3,ip4 = socket.remoteIP(ctrl)
ip1
含义说明:IP1,如果为nil,则表示没有获取到IP地址;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"10.39.154.32";
ip2
含义说明:IP2,如果为nil,则表示没有IP2;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"10.39.154.32";
ip3
含义说明:IP3,如果为nil,则表示没有IP3;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"10.39.154.32";
ip4
含义说明:IP4,如果为nil,则表示没有IP4;
数据类型:string;
取值范围:暂无;
注意事项:暂无;
返回示例:"10.39.154.32";
示例
-- 注意: ,必须在接收到socket.ON_LINE消息之后才可能获取到,最多返回4个IP。
-- socket.connect里如果remote_port设置成0,则当DNS完成时就返回socket.ON_LINE消息
local ip1,ip2,ip3,ip4 = socket.remoteIP(ctrl)
socket.dft(id)
功能
设置默认网络适配器编号
参数
id
参数含义:默认适配器编号,若不传,则打包获取;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
返回值
local id, last_id = socket.dft()
id
含义说明:默认适配器编号;
数据类型:number;
取值范围:暂无;
注意事项:暂无;
返回示例:socket.LWIP_ETH;
last_id
含义说明:最后一个注册的适配器编号(2025.7.25新增);
数据类型:int;
取值范围:暂无;
注意事项:暂无;
返回示例:socket.LWIP_ETH;
示例
-- 本函数于 2025.1.6 新增
-- 获取当前默认适配器编号
local id = socket.dft()
-- 设置默认适配器编号
socket.dft(socket.LWIP_ETH)
-- 获取当前默认适配器编号, 及最后一个注册的适配器编号
local id, last_id = socket.dft()
log.info("当前默认适配器编号", id, "最后一个注册的适配器编号", last_id)
-- 1. 当前的默认网卡, 可以获取, 可以设置, 就是socket.dft(id)的第一个参数, 也是第一个返回值
-- 2. 最后注册的网卡, 可以获取, 不支持设置, 就是socket.dft()的第二个返回值
socket.sntp(sntp_server,index)
功能
sntp 时间同步
参数
sntp_server
参数含义:sntp服务器地址 选填;
数据类型:string或者table;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;
index
参数含义:上网使用的网卡ID;
数据类型:number或者nil;
取值范围:number类型时,取值范围参考socket api中的常量详解;
是否必选:可选传入此参数;
注意事项:如果没有传入此参数,内核固件会自动选择当前时间点其他功能模块设置的默认网卡;
除非你socket请求时,一定要使用某一种网卡,才设置此参数;
如果没什么特别要求,不要设置此参数,使用系统中设置的默认网卡即可 ;
一般来说,LuatOS的网络应用demo中都会有netdrv_device功能模块设置默认网卡;
所以建议不要设置此参数,直接使用netdrv_device设置的默认网卡就行;
参数示例:socket.LWIP_GP表示使用4G网卡;
返回值
nil
示例
socket.sntp()
--socket.sntp("ntp.aliyun.com") --自定义sntp服务器地址
--socket.sntp({"ntp.aliyun.com","ntp1.aliyun.com","ntp2.aliyun.com"}) --sntp自定义服务器地址
--socket.sntp(nil, socket.ETH0) --sntp自定义适配器序号
sys.subscribe("NTP_UPDATE", function()
log.info("sntp", "time", os.date())
end)
sys.subscribe("NTP_ERROR", function()
log.info("socket", "sntp error")
socket.sntp()
end)
socket.ntptm()
功能
网络对时后的时间戳(ms 级别)
参数
nil
返回值
local tm = socket.ntptm()
table类型,表示包含时间信息的数据;
此参数的内容格式说明如下
{
"sms":0, -- number类型
-- 系统启动时刻与1900.1.1 0:0:0的毫秒偏移量
"tms":365, -- number类型
-- 当前毫秒数
"tsec":0, -- number类型
-- 当前秒数,从1900.1.1 0:0:0 开始算, UTC时间
"lms":365, -- number类型
-- 本地毫秒数计数器,基于mcu.tick64()
"ndeley":0, -- number类型
-- 网络延时平均值,单位毫秒
"lsec":0, -- number类型
-- 本地秒数计数器,基于mcu.tick64()
"ssec":0, -- number类型
-- 系统启动时刻与1900.1.1 0:0:0的秒数偏移量
}
示例
-- 本API于 2023.11.15 新增
-- 注意, 本函数在执行socket.sntp()且获取到NTP时间后才有效
-- 而且是2次sntp之后才是比较准确的值
-- 网络波动越小, 该时间戳越稳定
local tm = socket.ntptm()
-- 对应的table包含多个数据, 均为整数值
-- 标准数据
-- tsec 当前秒数,从1900.1.1 0:0:0 开始算, UTC时间
-- tms 当前毫秒数
-- vaild 是否有效, true 或者 nil
-- 调试数据, 调试用,一般用户不用管
-- ndelay 网络延时平均值,单位毫秒
-- ssec 系统启动时刻与1900.1.1 0:0:0的秒数偏移量
-- sms 系统启动时刻与1900.1.1 0:0:0的毫秒偏移量
-- lsec 本地秒数计数器,基于mcu.tick64()
-- lms 本地毫秒数计数器,基于mcu.tick64()
log.info("tm数据", json.encode(tm))
log.info("时间戳", string.format("%u.%03d", tm.tsec, tm.tms))
socket.sntp_port(port)
功能
设置 SNTP 服务器的端口号
参数
Port
参数含义:port 端口号, 默认123;
数据类型:number;
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:123;
返回值
含义说明:返回当前的端口号;
数据类型:number;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;
示例
-- 本函数于2024.5.17新增
-- 大部分情况下不需要设置NTP服务器的端口号,默认123即可
local current_port = socket.sntp_port(123)
log.info("Current SNTP port:", current_port)
五、产品支持说明
支持 LuatOS 开发的所有产品都支持 socket 核心库。