9、nodeMCU学习笔记--net模块

esp8266  nodemcu  lua  wifi  net  web

闲言碎语

nodemcu的wifi模块,花了三篇文章被我水完了。内容还是比较浅显的。不过,nodemcu的开发者确实把wifi模块设计的很简单,也和容易使用。配置函数、station类函数、ap类函数、监听注册函数,总体来讲还是很清晰明了。要用熟这些wifi功能,其实还要配合其他模块一起来(比如这篇文章要说的net),循序渐进。

这里有个综合文章这里

模块函数

net模块的函数也是比较多的。不过,整体结构也是很清晰的。赶紧来看看这些函数

序号 函数名 参数 返回值
1 net.createConnection() type, secure net.socket 子模块
2 net.createServer() type, timeout net.server 子模块
3 net.multicastJoin() if_ip, multicast_ip
4 net.multicastLeave() if_ip, multicast_ip
5 net.server:close()
6 net.server:listen() port,[ip],function(net.socket)
7 net.server:on()
8 net.server:send()
9 net.socket:close() nil
10 net.socket:connect() port, ip / domain nil
11 net.socket:dns() domain, function(net.socket, ip)
12 net.socket:getpeer() ip, port
13 net.socket:hold()
14 net.socket:on() event, function() nil
15 net.socket:send() string[, function(sent)]
16 net.socket:unhold()
17 net.dns.getdnsserver() dns_index(0 / 1) ip
18 net.dns.resolve() host, function(ip) nil
19 net.dns.setdnsserver() dns_ip_addr, dns_index nil
20 net.cert.verify() enable / pemdata true

参数里面有个type的,只有两种选择,要么net.TCP,要么net.UDP。有几个server相关的API,几个socket相关的API。这里不打算一个一个函数的讲了,直接来几个例子反而更容易理解API的含义。

实践一下

光说不练假把式,直接来实践一下。从API中可以知道,net模块可以创建server和client。实践前,确保nodemcu已经连入网络。

wifi的配置后会一直生效。如果你先前配置过,可以不用配置。当然,重新配置一下也可以。

client

这里先来看看如何创建一个client,以及如何进行通信。

cl = net.createConnection(net.TCP, 0)
cl:connect(9999, "192.168.199.101")
cl:on("receive", function(sck, c) print(c) end)
cl:on("disconnection", function(sck, c) print("disconnection!") end)

使用.createConnection创建一个net.TCP客户端,函数会返回一个socket子模块,后面要用的都是socket相关的函数,第二个参数,1表示加密,0表示不加密。net.socket:connect用来连接到服务端。参数2既可以是ip地址,也可以是域名。注意connect前面用的是冒号:,不是点。接着,找一个网络调试工具来创建一个server。这里我找了个名字叫网络调试的手机APP。net.socket:on函数用来绑定几个事件回调,函数原型是这样的 function(net.socket[, string]):

  • "connection" : 连接;
  • "reconnection" : 重连接;
  • "disconnection" : 断开连接;
  • "receive" : 接收回调,string表示接收到的字符串数据;
  • "sent" : 发送;

这个例子里面,nodemcu连接到app创建的server后,并没有产生回调事件,具体是什么原因,不清楚。不过,尝试连接到域名却可以产生回调事件。比如下面这个域名

cl:connect(80, "www.nodemcu.com")
客户端

服务端

点击APP左边的客户端列表,断开nodemcu,得到一个预期的断开回调。使用.createConnection创建多个客户端。比如,这样子:

cl = net.createConnection(net.TCP, 0)
cl2 = net.createConnection(net.TCP, 0)

使用net.socket:send可以向服务端发送数据。比方说在ESPlorer右边的输入框里面输入下面这句语句:

=cl:send("Hello NodeMCU")

这里需要说明的是,send函数发送的数据长度是有限度的,大概是1400多个字节。当要发送大于1400字节的内容的时候,比如说发送一个带css、js的网页,就需要分成多次发送。多次发送也不是简单的把上面的代码复制几遍就能解决的。而是要用到"sent"事件来回调。

cnt = 0
cl = net.createConnection(net.TCP, 0)
cl:connect(9999, "192.168.199.101")
cl:on("receive", function(sck, c) print(c) end)
cl:on("disconnection", function(sck, c) print("disconnection!") end)
cl:on("sent", function(c) 
    if cnt ~= 10 then
        cl:send(cnt)
        cnt = cnt + 1
    end 
end)

这个例子可以让客户端在发送完第一条消息后,再发10条消息给服务端。激活的方法还是在ESPlorer中输入一条send语句。

=cl:send("Hello NodeMCU")

当nodemcu发送完第一条语句后,会触发"sent"事件,进而发送10条消息给服务端。

收到消息了!

server

知道了如何创建并使用一个client后,我们来继续看如何创建一个server。先上个开胃菜。

ns = net.createServer(net.TCP, 15)
ns:listen(80, function(c)
    c:on("receive", function(c, d)
        print(d)
        c:send(d)
    end)
    c:on("connection", function(c, d) print(d) end)
    c:on("disconnection", function(c, d) print("disconnection") end)
end)

使用.createServer创建一个net.TCP的服务端,第二次参数用于设置不活动连接的超时时间,返回一个net.server模块。nodemcu只能创建一个server,不像client可以创建多个。需要注意一下。net.server只有4个函数,其中的send和on仅对udp有用。tcp要使用socket的send和on函数。
  接着用net.server:listen创建一个监听。回调传入的是一个socket。可以尽情的使用socket的函数了,比如用net.socket:on设置各种事件回调。这个例子里面的"connection"依然没效果╮(╯_╰)╭。使用APP连接到创建好的server,试着发送信息。

这图有点大啊 ╮(╯_╰)╭

  接着到主菜上场了。内容有点长。主要是实现上篇文章说的enduser setup。动筷子前记得把wifi模式设置成AP模式或者混合模式。

web = '<!doctype html><html><head><meta charset=\'utf-8\'><meta name=\'viewport\'content=\'width=380\'><title>Connect gadget to you WiFi</title><style media=\'screen\'type=\'text/css\'>*{margin:0;padding:0}html{height:100%;background:linear-gradient(rgba(196,102,0,0.2),rgba(155,89,182,0.2)),url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAAA8AgMAAACm+SSwAAAADFBMVEVBR1FFS1VHTlg8Q0zU/YXIAAADVElEQVQ4yy1TTYvTUBQ9GTKiYNoodsCF4MK6U4TZChOhiguFWHyBFzqlLl4hoeNvEBeCrlrhBVKq1EUKLTP+hvi1GyguXqBdiZCBzGqg20K8L3hDQnK55+OeJNguHx6UujYl3dL5ALn4JOIUluAqeAWciyGaSdvngOWzNT+G0UyGUOxVOAdqkjXDCbBiUyjZ5QzYEbGadYAi6kHxth+kthXNVNCDofwhGv1D4QGGiM9iAjbCHgr2iUUpDJbs+VPQ4xAr2fX7KXbkOJMdok965Ksb+6lrjdkem8AshIuHm9Nyu19uTunYlOXDTQqi8VgeH0kBXH2xq/ouiMZPzuMukymutrBmulUTovC6HqNFW2ZOiqlpSXZOTvSUeUPxChjxol8BLbRy4gJuhV7OR4LRVBs3WQ9VVAU7SXgK2HeUrOj7bC8YsUgr3lEV/TXB7hK90EBnxaeg1Ov15bY80M736ekCGesGAaGvG0Ct4WRkVQVHIgIM9xJgvSFfPay8Q6GNv7VpR7xUnkvhnMQCJDYkYOtNLihV70tCU1Sk+BQrpoP+HLHUrJkuta40C6LP5GvBv+Hqo10ATxxFrTPvNdPr7XwgQud6RvQN/sXjBGzqbU27wcj9cgsyvSTrpyXV8gKpXeNJU3aFl7MOdldzV4+HfO19jBa5f2IjWwx1OLHIvFHkqbBj20ro1g7nDfY1DpScvDRUNARgjMMVO0zoMjKxJ6uWCPP+YRAWbGoaN8kXYHmLjB9FXLGOazfFVCvOgqzfnicNPrHtPKlex2ye824gMza0cTZ2sS2Xm7Qst/UfFw8O6vVtmUKxZy9xFgzMys5cJ5fxZw4y37Ufk1Dsfb8MqOjYxE3ZMWxiDcO0PYUaD2ys+8OW1pbB7/e3sfZeGVCL0Q2aMjjPdm2sxADuejZxHJAd8dO9DSUdA0V8/NggRRanDkBrANn8yHlEQOn/MmwoQfQF7xgmKDnv520bS/pgylP67vf3y2V5sCwfoCEMkZClgOfJAFX9eXefR2RpnmRs4CDVPceaRfoFzCkJVJX27vWZnoqyvmtXU3+dW1EIXIu8Qg5Qta4Zlv7drUCoWe8/8MXzaEwux7ESE9h6qnHj3mIO0/D9RvzfxPmjWiQ1vbeSk4rrHwhAre35EEVaAAAAAElFTkSuQmCC)}body{font-family:arial,verdana}div{position:absolute;margin:auto;top:0;right:0;bottom:0;left:0;width:320px;height:274px}form{width:320px;text-align:center;position:relative}form fieldset{background:white;border:0 none;border-radius:5px;box-shadow:0 0 15px 1px rgba(0,0,0,0.4);padding:20px 30px;box-sizing:border-box}form input{padding:15px;border:1px solid#ccc;border-radius:3px;margin-bottom:10px;width:100%;box-sizing:border-box;font-family:montserrat;color:#2C3E50;font-size:13px}form.action-button{width:100px;background:#27AE60;font-weight:bold;color:white;border:0 none;border-radius:3px;cursor:pointer;padding:10px 5px;margin:10px 5px}form.action-button:hover,#msform.action-button:focus{box-shadow:0 0 0 2px white,0 0 0 3px#27AE60}.fs-title{font-size:15px;text-transform:uppercase;color:#2C3E50;margin-bottom:10px}.fs-subtitle{font-weight:normal;font-size:13px;color:#666;margin-bottom:20px}</style></head><body><div><form><fieldset><h2 class=\'fs-title\'>WiFi Login</h2><h3 class=\'fs-subtitle\'>Connect gadget to your WiFi</h3><input type=\'text\'autocorrect=\'off\'autocapitalize=\'none\'name=\'wifi_ssid\'placeholder=\'WiFi Name\'/><input type=\'password\'name=\'wifi_password\'placeholder=\'Password\'/><input type=\'submit\'name=\'save\'class=\'submit action-button\'value=\'Save\'/></fieldset></form></div></body></html>'    

sendBuf = {}

for i = 1, #web, 1400 do
    local len = #web - i 
    if len > 1400 then
        sendBuf[#sendBuf + 1] = string.sub(web, i, i+1400-1)
    else
        sendBuf[#sendBuf + 1] = string.sub(web, i, i+len)
    end
end

web数组存储了一个web页面。当然了,这个web页面比较大,远远超过了1400字节。需要将它分成几块,以便后面分批发送。所以,把这个web页面分块存储到一个table中。

function sendWeb(c)
    if #sendBuf > 0 then
        s = table.remove(sendBuf, 1)
        c:send(s)
    else
        c:close()
    end
end

函数sendWeb用来把table里面的内容发送出去,一边发送,一边remove表里面的内容,所以用浏览器浏览只能打开页面一次 o(╯□╰)o。或许这个地方可以优化一下。

sv = net.createServer(net.TCP, 60)

sv:listen(80, function(c)
    c:on("receive", function(cn, req)
        local _, _, method, path, vars = string.find(req, "([A-Z]+) (.+)?(.+) HTTP")
        if method == nil then
            _, _, method, path = string.find(req, "([A-Z]+) (.+) HTTP")
        end

        local _GET = {}
        if vars ~= nil then
            for k, v in string.gmatch(vars, "(%w+_%w+)=(%w+)&*") do
                _GET[k] = v
                print(k .. ":" .. v)
            end        
            local sendbuf = "<h1>Config Succeed!</h1>"
            sendbuf = sendbuf.."<p>wifi_ssid: ".._GET["wifi_ssid"].."</P>"
            sendbuf = sendbuf.."<p>wifi_password  :".._GET["wifi_password"].."</P>"
            cn:send(sendbuf)
            cn:close()
        else
            cn:on("sent", sendWeb)
            sendWeb(cn)
        end
    end)
end)

最后这一部分,和开胃菜那个例子的效果差不多,只是这回发送的是一个页面。回调函数中,先解析浏览器get过来的内容,之后把类似于这种格式的字符串("wifi_ssid=hello&wifi_password=12345678")存储到一个table中。最后又把提取到的内容send出来,赶紧用浏览器访问nodemcu看看效果吧。只需要在浏览器的地址栏输入ip地址即可。
  利用net的server,还可以显示web控制led之类的效果,网上有相关的例子。或者可以配合nodemcu上面的AD完成更多东西来。不过前提是,要能写出漂亮的web页面o(╯□╰)o。

一点lua语法

local _, _, method, path, vars = string.find(req, "([A-Z]+) (.+)?(.+) HTTP")

这个地方的 _ 实际上是一个变量,叫虚变量,因为string的find方法会返回子串的起始和结束地址。不需要的话,可以用虚变量来存储。

简书评论不能贴图, 如有需要可以到我的GitHub上提issues

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容