9擎场、nodeMCU學(xué)習(xí)筆記--net模塊

esp8266??nodemcu??lua??wifi??net??web

閑言碎語(yǔ)

nodemcu的wifi模塊瞒御,花了三篇文章被我水完了。內(nèi)容還是比較淺顯的神郊。不過(guò)肴裙,nodemcu的開(kāi)發(fā)者確實(shí)把wifi模塊設(shè)計(jì)的很簡(jiǎn)單,也和容易使用涌乳。配置函數(shù)蜻懦、station類函數(shù)、ap類函數(shù)夕晓、監(jiān)聽(tīng)注冊(cè)函數(shù)宛乃,總體來(lái)講還是很清晰明了。要用熟這些wifi功能蒸辆,其實(shí)還要配合其他模塊一起來(lái)(比如這篇文章要說(shuō)的net)征炼,循序漸進(jìn)。

這里有個(gè)綜合文章這里

模塊函數(shù)

net模塊的函數(shù)也是比較多的躬贡。不過(guò)谆奥,整體結(jié)構(gòu)也是很清晰的。趕緊來(lái)看看這些函數(shù)

序號(hào) 函數(shù)名 參數(shù) 返回值
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

參數(shù)里面有個(gè)type的拂玻,只有兩種選擇酸些,要么net.TCP宰译,要么net.UDP。有幾個(gè)server相關(guān)的API魄懂,幾個(gè)socket相關(guān)的API沿侈。這里不打算一個(gè)一個(gè)函數(shù)的講了,直接來(lái)幾個(gè)例子反而更容易理解API的含義市栗。

實(shí)踐一下

光說(shuō)不練假把式缀拭,直接來(lái)實(shí)踐一下。從API中可以知道肃廓,net模塊可以創(chuàng)建server和client智厌。實(shí)踐前,確保nodemcu已經(jīng)連入網(wǎng)絡(luò)盲赊。

wifi的配置后會(huì)一直生效诚卸。如果你先前配置過(guò),可以不用配置绘迁。當(dāng)然合溺,重新配置一下也可以。

client

這里先來(lái)看看如何創(chuàng)建一個(gè)client缀台,以及如何進(jìn)行通信棠赛。

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創(chuàng)建一個(gè)net.TCP客戶端,函數(shù)會(huì)返回一個(gè)socket子模塊膛腐,后面要用的都是socket相關(guān)的函數(shù)睛约,第二個(gè)參數(shù),1表示加密哲身,0表示不加密辩涝。net.socket:connect用來(lái)連接到服務(wù)端。參數(shù)2既可以是ip地址勘天,也可以是域名怔揩。注意connect前面用的是冒號(hào):,不是點(diǎn)脯丝。接著商膊,找一個(gè)網(wǎng)絡(luò)調(diào)試工具來(lái)創(chuàng)建一個(gè)server。這里我找了個(gè)名字叫網(wǎng)絡(luò)調(diào)試的手機(jī)APP巾钉。net.socket:on函數(shù)用來(lái)綁定幾個(gè)事件回調(diào)翘狱,函數(shù)原型是這樣的 function(net.socket[, string]):

  • "connection" : 連接;
  • "reconnection" : 重連接砰苍;
  • "disconnection" : 斷開(kāi)連接潦匈;
  • "receive" : 接收回調(diào)阱高,string表示接收到的字符串?dāng)?shù)據(jù);
  • "sent" : 發(fā)送茬缩;

這個(gè)例子里面赤惊,nodemcu連接到app創(chuàng)建的server后,并沒(méi)有產(chǎn)生回調(diào)事件凰锡,具體是什么原因未舟,不清楚。不過(guò)掂为,嘗試連接到域名卻可以產(chǎn)生回調(diào)事件裕膀。比如下面這個(gè)域名

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

服務(wù)端

點(diǎn)擊APP左邊的客戶端列表,斷開(kāi)nodemcu勇哗,得到一個(gè)預(yù)期的斷開(kāi)回調(diào)昼扛。使用.createConnection創(chuàng)建多個(gè)客戶端。比如欲诺,這樣子:

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

使用net.socket:send可以向服務(wù)端發(fā)送數(shù)據(jù)抄谐。比方說(shuō)在ESPlorer右邊的輸入框里面輸入下面這句語(yǔ)句:

=cl:send("Hello NodeMCU")

這里需要說(shuō)明的是,send函數(shù)發(fā)送的數(shù)據(jù)長(zhǎng)度是有限度的扰法,大概是1400多個(gè)字節(jié)蛹含。當(dāng)要發(fā)送大于1400字節(jié)的內(nèi)容的時(shí)候,比如說(shuō)發(fā)送一個(gè)帶css塞颁、js的網(wǎng)頁(yè)浦箱,就需要分成多次發(fā)送。多次發(fā)送也不是簡(jiǎn)單的把上面的代碼復(fù)制幾遍就能解決的祠锣。而是要用到"sent"事件來(lái)回調(diào)憎茂。

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)

這個(gè)例子可以讓客戶端在發(fā)送完第一條消息后,再發(fā)10條消息給服務(wù)端锤岸。激活的方法還是在ESPlorer中輸入一條send語(yǔ)句。

=cl:send("Hello NodeMCU")

當(dāng)nodemcu發(fā)送完第一條語(yǔ)句后板乙,會(huì)觸發(fā)"sent"事件是偷,進(jìn)而發(fā)送10條消息給服務(wù)端。

收到消息了募逞!

server

知道了如何創(chuàng)建并使用一個(gè)client后蛋铆,我們來(lái)繼續(xù)看如何創(chuàng)建一個(gè)server。先上個(gè)開(kāi)胃菜放接。

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創(chuàng)建一個(gè)net.TCP的服務(wù)端刺啦,第二次參數(shù)用于設(shè)置不活動(dòng)連接的超時(shí)時(shí)間,返回一個(gè)net.server模塊纠脾。nodemcu只能創(chuàng)建一個(gè)server玛瘸,不像client可以創(chuàng)建多個(gè)蜕青。需要注意一下。net.server只有4個(gè)函數(shù)糊渊,其中的send和on僅對(duì)udp有用右核。tcp要使用socket的send和on函數(shù)。
??接著用net.server:listen創(chuàng)建一個(gè)監(jiān)聽(tīng)渺绒『睾龋回調(diào)傳入的是一個(gè)socket∽诩妫可以盡情的使用socket的函數(shù)了躏鱼,比如用net.socket:on設(shè)置各種事件回調(diào)。這個(gè)例子里面的"connection"依然沒(méi)效果╮(╯_╰)╭殷绍。使用APP連接到創(chuàng)建好的server染苛,試著發(fā)送信息。

這圖有點(diǎn)大啊 ╮(╯_╰)╭

??接著到主菜上場(chǎng)了篡帕。內(nèi)容有點(diǎn)長(zhǎng)殖侵。主要是實(shí)現(xiàn)上篇文章說(shuō)的enduser setup。動(dòng)筷子前記得把wifi模式設(shè)置成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數(shù)組存儲(chǔ)了一個(gè)web頁(yè)面拢军。當(dāng)然了,這個(gè)web頁(yè)面比較大怔鳖,遠(yuǎn)遠(yuǎn)超過(guò)了1400字節(jié)茉唉。需要將它分成幾塊,以便后面分批發(fā)送结执。所以度陆,把這個(gè)web頁(yè)面分塊存儲(chǔ)到一個(gè)table中。

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

函數(shù)sendWeb用來(lái)把table里面的內(nèi)容發(fā)送出去献幔,一邊發(fā)送懂傀,一邊remove表里面的內(nèi)容,所以用瀏覽器瀏覽只能打開(kāi)頁(yè)面一次 o(╯□╰)o蜡感〉乓希或許這個(gè)地方可以優(yōu)化一下。

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)

最后這一部分郑兴,和開(kāi)胃菜那個(gè)例子的效果差不多犀斋,只是這回發(fā)送的是一個(gè)頁(yè)面∏榱回調(diào)函數(shù)中叽粹,先解析瀏覽器get過(guò)來(lái)的內(nèi)容,之后把類似于這種格式的字符串("wifi_ssid=hello&wifi_password=12345678")存儲(chǔ)到一個(gè)table中。最后又把提取到的內(nèi)容send出來(lái)虫几,趕緊用瀏覽器訪問(wèn)nodemcu看看效果吧锤灿。只需要在瀏覽器的地址欄輸入ip地址即可。
??利用net的server持钉,還可以顯示web控制led之類的效果衡招,網(wǎng)上有相關(guān)的例子∶壳浚或者可以配合nodemcu上面的AD完成更多東西來(lái)始腾。不過(guò)前提是,要能寫出漂亮的web頁(yè)面o(╯□╰)o空执。

一點(diǎn)lua語(yǔ)法

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

這個(gè)地方的 _ 實(shí)際上是一個(gè)變量浪箭,叫虛變量,因?yàn)閟tring的find方法會(huì)返回子串的起始和結(jié)束地址辨绊。不需要的話奶栖,可以用虛變量來(lái)存儲(chǔ)。

簡(jiǎn)書評(píng)論不能貼圖, 如有需要可以到我的GitHub上提issues

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末门坷,一起剝皮案震驚了整個(gè)濱河市宣鄙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌默蚌,老刑警劉巖冻晤,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绸吸,居然都是意外死亡鼻弧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門锦茁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)攘轩,“玉大人,你說(shuō)我怎么就攤上這事码俩《劝铮” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵稿存,是天一觀的道長(zhǎng)够傍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)挠铲,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任寂诱,我火速辦了婚禮拂苹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己瓢棒,他們只是感情好浴韭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著脯宿,像睡著了一般念颈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上连霉,一...
    開(kāi)封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天榴芳,我揣著相機(jī)與錄音,去河邊找鬼跺撼。 笑死窟感,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歉井。 我是一名探鬼主播柿祈,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哩至!你這毒婦竟也來(lái)了躏嚎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤菩貌,失蹤者是張志新(化名)和其女友劉穎卢佣,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菜谣,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡珠漂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尾膊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片媳危。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖冈敛,靈堂內(nèi)的尸體忽然破棺而出待笑,到底是詐尸還是另有隱情,我是刑警寧澤抓谴,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布暮蹂,位于F島的核電站,受9級(jí)特大地震影響癌压,放射性物質(zhì)發(fā)生泄漏仰泻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一滩届、第九天 我趴在偏房一處隱蔽的房頂上張望集侯。 院中可真熱鬧,春花似錦、人聲如沸棠枉。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辈讶。三九已至命浴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贱除,已是汗流浹背生闲。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勘伺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓飞醉,卻偏偏與公主長(zhǎng)得像冲茸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缅帘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容