【玩轉開源】BananaPi R2 —— 第四篇 Openwrt Luci 初探


  什么是Luci呢?先直觀的感受一下,打開web瀏覽器,輸入R2的網關地址,然后出現了一個web登錄界面,這個就是Openwrt Luci的應用。

  那么到底什么是Luci呢?在這里我先給大家一個公式:Luci = lua + uci,然后接下來我針對這個公式去講解什么是Luci。

  首先簡單介紹一下什么是lua和uci;lua是一門編程語言,在后面你會看到它長什么樣子,uci(Unified Configuration Interface)是Openwrt的配置框架。

  那么到這里能不能大致猜到Luci是什么了?沒錯,Luci就是這兩者的結合,簡單理解就是基於lua語言去實現配置Openwrt。

  我們再回過頭來看這個web界面,是不是感覺和家里路由器的配置web界面很相近呀,細心一點看,會看到路徑除了IP地址外,還有"/cgi-bin/luci",這里留個伏筆,后面我們會講到為什么是這個路徑。

  那么接下來我們就來看luci的基本用法,以及工作原理,讓大家對Luci有一個初步的認識。

  • 初識Luci

  輸入賬號密碼(一般默認是root,root)登錄頁面,登錄后的界面類似於這樣:

  從頁面上可以看到我們設備的固件、內核版本以及內存等相關信息。

  點擊Status => Routes,我們可以看到設備上的路由信息:

  更多的Luci界面的配置細節,我在這里就不過多闡述,后續結合代碼的時候再來看部分Luci的配置,接下來我們來看一下Luci的工作原理。

  回到第一個問題,我們在瀏覽器里輸入網關地址“192.168.1.1”,但是為什么Luci的路徑是“http://192.168.1.1/cgi-bin/luci”,那么當我們在web輸入網關地址后,頁面是在哪里被調用的呢?在這里我們就要引入一個概念uhttpd,那么這個uhttpd是個什么東東呢?

   uhttpd是一個輕量級的web服務器,由於其可以和Openwrt的配置框架UCI結合到一起,因此默認被用於OpenWrt的Web管理接口LuCI。
   我們都知道,網站都是被部署在一台台服務器,PC等設備上的,我們的設備訪問網站時,先是通過網絡訪問到部署這個網站的服務器,然后服務器的web服務再返回頁面給我們;也就是說如果服務器沒有web服務,我們是訪問不了網頁的哦。
  • 接下來我們來看一下uhttpd的UCI配置
root@LEDE:/# cat /etc/config/uhttpd 
config uhttpd 'main'
        list listen_http '0.0.0.0:80'    #http協議IPV4的監聽端口80
        list listen_http '[::]:80'      #http協議IPV6的監聽端口為443
        list listen_https '0.0.0.0:443'
        list listen_https '[::]:443'
        option redirect_https '1'
        option home '/www'         #指定根路徑
        option rfc1918_filter '1'
        option max_requests '3'          #最大請求數
        option max_connections '100'     #最大TCP連接數
        option cert '/etc/uhttpd.crt'    #HTTPS連接的證書路徑
        option key '/etc/uhttpd.key'     #HTTPS連接的私鑰路徑
        option cgi_prefix '/cgi-bin'     #cgi腳本的路徑,這個路徑又是home的相對路徑,即/www/cgi-bin
        option lua_prefix '/luci'        #lua解釋器路徑,這個路徑又是home的相對路徑,即/www/luci
        option lua_handler '/usr/lib/lua/luci/sgi/uhttpd.lua'     #lua runtime初始化的路徑
        option script_timeout '60'
        option network_timeout '30'
        option http_keepalive '20'
        option tcp_keepalive '1'
        option ubus_prefix '/ubus'

config cert 'defaults'
        option days '730'
        option bits '2048'
        option country 'ZZ'
        option state 'Somewhere'
        option location 'Unknown'
        option commonname 'LEDE'

  當然我們也可以通過uci的命令去查看:

root@LEDE:/www/cgi-bin# uci show uhttpd
uhttpd.main=uhttpd
uhttpd.main.listen_http='0.0.0.0:80' '[::]:80'
uhttpd.main.listen_https='0.0.0.0:443' '[::]:443'
uhttpd.main.redirect_https='1'
uhttpd.main.home='/www'
uhttpd.main.rfc1918_filter='1'
uhttpd.main.max_requests='3'
uhttpd.main.max_connections='100'
uhttpd.main.cert='/etc/uhttpd.crt'
uhttpd.main.key='/etc/uhttpd.key'
uhttpd.main.cgi_prefix='/cgi-bin'
uhttpd.main.lua_prefix='/luci'
uhttpd.main.lua_handler='/usr/lib/lua/luci/sgi/uhttpd.lua'
uhttpd.main.script_timeout='60'
uhttpd.main.network_timeout='30'
uhttpd.main.http_keepalive='20'
uhttpd.main.tcp_keepalive='1'
uhttpd.main.ubus_prefix='/ubus'
uhttpd.defaults=cert
uhttpd.defaults.days='730'
uhttpd.defaults.bits='2048'
uhttpd.defaults.country='ZZ'
uhttpd.defaults.state='Somewhere'
uhttpd.defaults.location='Unknown'
uhttpd.defaults.commonname='LEDE'

  細看一下,是不是和"/etc/config/uhttpd"里面的uhttpd的配置是一樣的,沒錯,現在我們已經接觸到Openwrt的UCI框架了。

  實際上Openwrt里面的所有配置都是在"/etc/config"目錄下,我們看一下有哪些配置:

root@LEDE:/etc/config# ls
aria2     firewall  luci      network   sysstat   uhttpd
dhcp      hd-idle   mtkhnat   qos       system    wireless
dropbear  kdump     mwan3     rpcd      ucitrack

  這些配置就構成了整個Openwrt的配置,而管理這些配置的框架正是UCI,我們可以簡單去理解,就是UCI = /etc/config/,這樣的好處就是方便統一配置,不過你配置什么,只管去"/etc/config"目錄下找對應需要配置的服務就好了,而且都是使用uci的方式,十分方便;相比Ubuntu等Linux其它衍生系統的配置文件來講是要方便和簡單很多,后面講Ubuntu系統的時候,大家就能感受到。

  到這里大家應該對UCI有一個初步的認識了,接下來我們通過繼續看uhttpd的那個問題,去認識lua語言,然后讓大家更加理解 Luci = lua + uci 這個公式。

  由上面uhttpd的配置來看,當我們通過web的方式訪問R2時,uhttpd會導向"/www"的路徑,那么我們來看看R2上的"/www"里面有什么。

root@LEDE:/www# ls 
/cgi-bin      index.html   /luci-static
root@LEDE:/www# cat index.html 
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="refresh" content="0; URL=/cgi-bin/luci" />
</head>
<body style="background-color: white">
<a style="color: black; font-family: arial, helvetica, sans-serif;" href="/cgi-bin/luci">LuCI - Lua Configuration Interface</a>
</body>
</html>
root@LEDE:/www# 

  能看到,"/www"路徑下面有個index.html,同時打印出“index.html”的內容,可以看到這個內容“href="/cgi-bin/luci”,原來是這里把網關導向了“/cgi-bin/luci”;那么我們再來看看這個路徑里面又有什么?

root@LEDE:/www/cgi-bin# ls         #這里有個luci的腳本
luci
root@LEDE:/www/cgi-bin# cat luci   #打印luci這個腳本的內容,可以看到這個腳本里的內容就是lua語言寫的
#!/usr/bin/lua
require "luci.cacheloader"
require "luci.sgi.cgi"
luci.dispatcher.indexcache = "/tmp/luci-indexcache"
luci.sgi.cgi.run()

  這個路徑下面放着一個lua的腳本,腳本里面調用了這個接口“luci.sgi.cgi.run()”,那么這個接口執行的函數在哪里呢,在這里:

root@LEDE:/usr/lib/lua/luci/sgi# ls
cgi.lua     uhttpd.lua
root@LEDE:/usr/lib/lua/luci/sgi# cat cgi.lua 
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.

***************

function run()
        local r = luci.http.Request(
                luci.sys.getenv(),
                limitsource(io.stdin, tonumber(luci.sys.getenv("CONTENT_LENGTH"))),
                ltn12.sink.file(io.stderr)
        )

        local x = coroutine.create(luci.dispatcher.httpdispatch)
        local hcache = ""
        local active = true

        while coroutine.status(x) ~= "dead" do
                local res, id, data1, data2 = coroutine.resume(x, r)

                if not res then
                        print("Status: 500 Internal Server Error")
                        print("Content-Type: text/plain\n")
                        print(id)
                        break;
                end

                if active then
                        if id == 1 then
                                io.write("Status: " .. tostring(data1) .. " " .. data2 .. "\r\n")
                        elseif id == 2 then
                                hcache = hcache .. data1 .. ": " .. data2 .. "\r\n"
                        elseif id == 3 then
                                io.write(hcache)
                                io.write("\r\n")
                        elseif id == 4 then
                                io.write(tostring(data1 or ""))
                        elseif id == 5 then
                                io.flush()
                                io.close()
                                active = false
                        elseif id == 6 then
                                data1:copyz(nixio.stdout, data2)
                                data1:close()
                        end
                end
        end
end

  run()函數就在cgi.lua里面;現在我們可以初步了解到,lua語言就是這樣被Luci使用的。

  那么我們再整體看一下整個訪問流程:web(輸入網關地址)==> uhttpd調用"/www/index.html" ==> index.html重定向到"/cgi-bin/luci" ==> luci被啟動。講到這里可能大家對Luci有一個初步的認識了,由於Luci涉及lua語言,這門語言不像Java,C普及率那么高,我這里暫時也點到為止,更多Luci的知識后續有時間我會繼續和大家一起研究。

  Luci Github:https://github.com/openwrt/luci


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM