亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

1. 概述

  • 本文介紹了一個(gè)簡單的嵌入式項(xiàng)目的的開發(fā)過程;
  • 從需求到實(shí)踐,本文對整個(gè)過程做了全面的介紹,本文所介紹的設(shè)備容易獲得且價(jià)格低廉;
  • 本文涉及了 *linux* 下 C 語言下的網(wǎng)絡(luò)編程、網(wǎng)絡(luò)廣播、*Magic Packet*、內(nèi)網(wǎng)穿透、反向代理等概念;
  • 本文所涉及的一些技術(shù)概念讀者可以自行參考其它的文章;
  • 本文可能并不適合初學(xué)者

2. 需求

  • 家里放了一臺(tái)服務(wù)器,差不多我所有的東西都在服務(wù)器上,不管在家里還是其它地方,都需要連接這臺(tái)服務(wù)器才能做事情;
  • 這臺(tái)服務(wù)器白天開著,晚上就關(guān)了(省點(diǎn)電:));每天起床以后要想著按一下服務(wù)器的電源開關(guān),每天睡覺前要記得把服務(wù)器關(guān)了;
  • 晚上忘記關(guān)服務(wù)器,通常不會(huì)有什么問題;但有時(shí)早上沒有打開服務(wù)器,可能就要有麻煩了;
  • 尷尬的時(shí)候就是早上沒有打開服務(wù)器,然后外出,然后剛好需要登錄服務(wù)器,這才想起來服務(wù)器沒開;
  • 所以吶,我需要有個(gè)機(jī)制,可以 **遠(yuǎn)程打開我的服務(wù)器**,這樣我就不會(huì)再出現(xiàn)尷尬了;

3. 簡要解決方案

  • 我們把要完成的這個(gè)需求當(dāng)作一個(gè)項(xiàng)目來做,可以把這個(gè)項(xiàng)目叫做服務(wù)器遠(yuǎn)程開機(jī)
  • 首先要確保服務(wù)器的主板支持網(wǎng)絡(luò)喚醒,否則不太好辦,不過現(xiàn)在的絕大多數(shù)主板都是支持的(PCI 2.2 以后的主板一般都支持,而 PCI 2.2 的標(biāo)準(zhǔn)是1998年提出的),有些主板可能需要 BIOS 設(shè)置,請自行搜索解決方案;
  • 第二是在家里的局域網(wǎng)上要有一個(gè)小設(shè)備是 24 小時(shí)運(yùn)行的,通過這臺(tái)設(shè)備在局域網(wǎng)上廣播 Magic Packet 來喚醒服務(wù)器,這臺(tái)設(shè)備應(yīng)該是一臺(tái)低功耗設(shè)備,越小越簡單越好;我們姑且把這個(gè)設(shè)備叫做 wakener
  • 第三是要在這個(gè) wakener 上編寫一個(gè)簡單的程序,這個(gè)程序可以在局域網(wǎng)上廣播 Magic Packet,以喚醒服務(wù)器,這個(gè)程序我們稱為 wakeOnLan
  • 第四是要有一個(gè)機(jī)制可以從互聯(lián)網(wǎng)上訪問到這臺(tái) wakener,只有這樣才能從互聯(lián)網(wǎng)上操控 wakener 上的軟件,其實(shí)這是一個(gè)內(nèi)網(wǎng)穿透的問題,要做到這一點(diǎn)或許需要一臺(tái)連接到互聯(lián)網(wǎng)上的輕量級(jí)服務(wù)器(VPS就可以);
  • 這樣我不管在哪里,通過終端(筆記本、臺(tái)式機(jī)、手機(jī)、平板等)登錄家里24小時(shí)開機(jī)的 wakener,運(yùn)行 wakeOnLan,就可以打開我的服務(wù)器;
  • 這臺(tái)24小時(shí)運(yùn)行的設(shè)備(wakener)有可能為你完成更多的事情,比如 NAS、遠(yuǎn)程開空調(diào)等等,但是重要的是完成眼前這個(gè)第一步。

4. 技術(shù)要點(diǎn)

上面的解決方案顯然非常粗糙,但是這個(gè)項(xiàng)目本身確實(shí)也比較簡單,沒有必要做非常詳盡的設(shè)計(jì)方案,所以我們下面僅列出一些可能的要點(diǎn)及解決方法

本項(xiàng)目的基本網(wǎng)絡(luò)架構(gòu)

下面是一個(gè)簡單的示意圖,表達(dá)了這個(gè)項(xiàng)目中各個(gè)設(shè)備是如何連接和互相影響的,其中 Local Server 是我們要遠(yuǎn)程開機(jī)的服務(wù)器,Server 是一臺(tái)連接在互聯(lián)網(wǎng)上的 VPS,用于內(nèi)網(wǎng)穿透

圖1:wake on lan架構(gòu)圖

Magic Packet

遠(yuǎn)程喚醒其實(shí)是網(wǎng)卡的一個(gè)功能,在 PCI 2.2 之后,信號(hào)線上多了一個(gè) PME 信號(hào),主機(jī)關(guān)閉電源后進(jìn)入休眠狀態(tài),可以繼續(xù)為網(wǎng)卡供電,網(wǎng)卡在收到一個(gè)叫做 Magic Packet 的數(shù)據(jù)包后,檢測出該數(shù)據(jù)包是發(fā)給自己的,則會(huì)在 PCI 上發(fā)出 PME 信號(hào),從而控制電腦啟動(dòng),這個(gè)功能被稱為 網(wǎng)絡(luò)喚醒

網(wǎng)絡(luò)喚醒其實(shí)并不復(fù)雜,在局域網(wǎng)中,從一臺(tái)電腦以廣播的形式發(fā)送 Magic Packet,那么在 Magic Packet 中指定的 mac 地址對應(yīng)的電腦就會(huì)被喚醒;

Magic Packet 就是一個(gè)指定格式的數(shù)據(jù)包,其格式為:6 個(gè) 0xff,然后 16 組需要被網(wǎng)絡(luò)喚醒的電腦的 MAC 地址,比如需要被喚醒的電腦的 MAC 為:00:e0:2b:69:00:03,則 Magic Packet 為(16進(jìn)制表述):

ff ff ff ff ff ff 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03 
00 e0 2b 69 00 03 00 e0 2b 69 00 03

通常 Magic Packet 的廣播使用 UDP 發(fā)送,端口號(hào)可以任意,通常使用 7 或者 9

關(guān)于 Magic Packet 的更多的信息請參考

  • [wikipidia-網(wǎng)絡(luò)喚醒](https://zh.wikipedia.org/zh-cn/%E7%B6%B2%E8%B7%AF%E5%96%9A%E9%86%92)
  • [wikipedia-Wake-On-Lan](https://en.wikipedia.org/wiki/Wake-on-LAN)

從圖1中可以看出,Wakener 通過路由器向局域網(wǎng)內(nèi)廣播 Magic Packet,從而喚醒 Local Server

要注意的是,Magic Packet 只對有線網(wǎng)卡有效,所以,服務(wù)器要使用網(wǎng)線連接到路由器上;


內(nèi)網(wǎng)穿透

在這個(gè)項(xiàng)目里,內(nèi)網(wǎng)穿透指的是:使用一定的技術(shù)手段讓我們可以從互聯(lián)網(wǎng)上直接訪問到家里的一臺(tái)設(shè)備上,這臺(tái)設(shè)備通過普通家用寬帶連接互聯(lián)網(wǎng),家用寬帶可能沒有公網(wǎng) IP;

如果家里的寬帶有公網(wǎng) IP,穿透內(nèi)網(wǎng)并不是一個(gè)很困難的事,大致需要三個(gè)步驟:

  1. 在家里路由器上設(shè)置一個(gè) NAT 讓外網(wǎng)的訪問直接轉(zhuǎn)發(fā)到局域網(wǎng)內(nèi)某個(gè)指定設(shè)備的指定端口上;
  2. 局域網(wǎng)中的一個(gè)設(shè)備(或者路由器本身)向某個(gè)有權(quán)限的公網(wǎng)服務(wù)器發(fā)送心跳包,使這個(gè)服務(wù)器可以知道家里寬帶的公網(wǎng) IP;
  3. 互聯(lián)網(wǎng)上的終端設(shè)備通過服務(wù)器獲知家里寬帶的公網(wǎng) IP,直接訪問即可;

如果家里的寬帶沒有公網(wǎng) IP(大多數(shù)寬帶應(yīng)該是這樣的),穿透內(nèi)網(wǎng)就要麻煩一些,通常需要使用反向代理來實(shí)現(xiàn),這需要一個(gè)公網(wǎng)服務(wù)器;

  • 公網(wǎng)服務(wù)器上安裝有支持反向代理的服務(wù)器端軟件,比如 *sshd*;
  • 局域網(wǎng)的設(shè)備上裝有反向代理的客戶端軟件,比如 *ssh*,通過向公網(wǎng)服務(wù)器發(fā)送反向代理的指令可以建立一個(gè)反向代理隧道(*tunnel*),*tunnel* 建立起來以后,訪問公網(wǎng)服務(wù)器的某個(gè)指定端口將被映射到訪問局域網(wǎng)中某個(gè) IP 地址下的某個(gè)端口,從而實(shí)現(xiàn)內(nèi)網(wǎng)穿透;

目前有很多的內(nèi)網(wǎng)穿透的工具,其原理其實(shí)都是反向代理,但通常比直接用 ssh 要好用得多,至少 ssh 在意外斷開后不會(huì)自動(dòng)重連,這些工具都會(huì)解決這些問題;

本文所使用的嵌入式 Linux 系統(tǒng)將是 openwrt,理論上可以使用向日葵的內(nèi)網(wǎng)穿透插件,愿意折騰的讀者可以嘗試折騰一下向日葵插件;

本文在內(nèi)網(wǎng)穿透上將使用一個(gè)叫 frp 的開源項(xiàng)目,后面會(huì)給出這個(gè)項(xiàng)目的具體網(wǎng)址


其它要面對的麻煩

為硬件燒錄或編譯一個(gè)定制的 *Linux* 操作系統(tǒng),還好本文的例子并不需要自己編譯一個(gè) *Linux*,燒錄就好了;

交叉編譯環(huán)境,這個(gè)是做嵌入式開發(fā)必須面對的,無法回避。


5. 簡單的嵌入式開發(fā)步驟

  1. 需求分析
  2. 概要設(shè)計(jì)和詳細(xì)設(shè)計(jì)
  3. 硬件開發(fā)及驗(yàn)證
  4. 編譯與硬件相適應(yīng)的操作系統(tǒng)及所需工具
  5. 建立在相應(yīng)硬件上進(jìn)行軟件開發(fā)的交叉編譯環(huán)境;
  6. 嵌入式軟件開發(fā);
  7. 調(diào)試

下面我們會(huì)依照這個(gè)開發(fā)步驟去實(shí)現(xiàn)我們的方案


6. 具體實(shí)踐

需求分析和設(shè)計(jì)

本項(xiàng)目的開發(fā)的需求分析和設(shè)計(jì)已經(jīng)在前面完成,鑒于該項(xiàng)目比較簡單,就不做更詳細(xì)設(shè)計(jì)了

硬件開發(fā)和驗(yàn)證

  • 要找一個(gè)24小時(shí)運(yùn)行的設(shè)備

我有一個(gè)早就不用的 迅雷一代賺錢寶(以下簡稱賺錢寶),不知道為何物的自己去百度一下

賺錢寶這個(gè)玩意 CPU 用的是 Amlogic S805ARM Cortex-A5 架構(gòu),4核1.5GHz,功耗非常低,記住這個(gè) CPU 的型號(hào),記住這個(gè) CPU 是32位的;

圖2:賺錢寶外觀


圖3:賺錢寶主板

這個(gè)玩意有 *256M* 內(nèi)存,1G 的 *Flash*,*100M* 網(wǎng)口和一個(gè) *USB* 口,足夠用了;

以前有一些廠家用這個(gè) *CPU* 做網(wǎng)絡(luò)機(jī)頂盒,現(xiàn)在應(yīng)該沒人用了;

淘寶上查了一下,賺錢寶一代是買不到了,但三代(玩客云)還有二手賣,大概在45 - 55元,用的CPU和一代一樣,只是內(nèi)存大了,如果你想折騰,也可以買一個(gè)來玩;

  • 硬件驗(yàn)證

這個(gè)設(shè)備的硬件顯然不需要驗(yàn)證,迅雷已經(jīng)幫我們驗(yàn)證了;

實(shí)際上,這個(gè)設(shè)備可以有多種選擇,如果你的路由器是 OEM 的,上面通常運(yùn)行的都是 openwrt,那么你可以直接使用它;

或者你手頭有閑置的機(jī)頂盒等,都有可能用得上;但是通常不建議使用平板,一是太耗電,二是把Android/ target=_blank class=infotextkey>安卓刷成 *Linux* 有難度。

操作系統(tǒng)

賺錢寶上原有的 Linux 應(yīng)該是迅雷自己編譯的,很難知道迅雷在這個(gè)系統(tǒng)上做了什么,所以還是不用為好,需要刷個(gè)新的系統(tǒng),CPU 為 S805 的設(shè)備通常都是支持 USB 刷機(jī)的,所以其實(shí)根本不用把它拆開,直接一條 USB 線就可以刷新系統(tǒng)了;

刷個(gè) openwrt 是比較現(xiàn)實(shí)的,有現(xiàn)成的教程,而且 openwrt 資料豐富,便于今后折騰;

刷機(jī)教程:[廢物利用之閑置礦渣迅雷賺錢寶一代刷OpenWrt固件發(fā)揮余熱_智能設(shè)備_什么值得買];

刷機(jī)包及相應(yīng)軟件:(
https://pan.baidu.com/s/1E4Ls05lPHHHhv0Ou8fb7GA);提取碼:ow2l

刷機(jī)包提供了 openwrt 18 和 19 兩個(gè),建議刷 openwrt 19(因?yàn)槲宜⒌氖?nbsp;openwrt 19)

具體刷機(jī)過程自己去享受吧;

刷好的機(jī)器應(yīng)該是可以使用 ssh 登錄的

  • 首先要從你的路由器上找到這臺(tái) openwrt 的 IP 地址,比如為:192.168.2.100,然后用 ssh 登錄,新刷的 openwrt 沒有密碼
ssh [email protected]
  • 我這里登錄以后的樣子,登錄以后一定要改一下 root 的密碼

圖4:ssh登錄openwrt

  • openwrt 還會(huì)有一個(gè) web 界面,直接在瀏覽器上輸入 IP 即可進(jìn)入

圖5:登錄openwrt的web界面


圖6:openwrt的web界面

  • 這臺(tái)設(shè)備最好不要使用 DHCP,而是使用固定 IP,這樣便于以后遠(yuǎn)程登錄,有三種方法設(shè)置固定 IP

1. 直接修改配置文件

openwrt 的網(wǎng)絡(luò)配置文件放在 /etc/config.NETwork 文件中,可以直接修改這個(gè)文件,改成下面這個(gè)樣子:

圖7:openwrt 改成固定 IP

2. 使用 openwrt 的 web 界面修改

從瀏覽器登錄 openwrt 的 web 頁面,其密碼與 ssh 的密碼一致,選擇:Network --> Interfaces --> Edit

圖8:通過openwrt的web界面修改固定IP


圖9:通過openwrt的web界面修改固定IP


圖10:通過openwrt的web界面修改固定IP

3. 在路由器上用 *MAC* 地址綁定 IP

實(shí)際上就是在路由器上設(shè)置 DHCP 每次分配 IP 時(shí),給指定 MAC 地址的設(shè)備分配一個(gè)固定的 IP,這樣,你的 openwrt 設(shè)備就不必設(shè)置固定 IP了,每種路由器的設(shè)置方法不一樣,我的路由器的界面像這個(gè)樣子

圖11:通過路由器設(shè)定openwrt的固定IP

 

建立交叉編譯環(huán)境

要在賺錢寶上寫程序,需要我們在本地電腦完成編程,然后用交叉編譯的工具編譯成在賺錢寶上可以運(yùn)行的程序,傳到賺錢寶上才可以在賺錢寶上運(yùn)行;

所以我們需要有一個(gè)工具鏈,對我們編寫的程序進(jìn)行交叉編譯;

這個(gè)工具鏈不是放在 wakener 上的,因?yàn)?nbsp;wakener 通常性能比較差,而且為了節(jié)省存儲(chǔ)空間,上面通常只放一些運(yùn)行時(shí)(runtime)庫,不具備開發(fā)的能力;所以這個(gè)工具鏈要放在另外一臺(tái)運(yùn)行著 Linux 的機(jī)器上,也可以運(yùn)行在虛擬機(jī)上,我們把這臺(tái)電腦叫做 開發(fā)機(jī),建議在開發(fā)機(jī)上運(yùn)行 ubuntu

下面是建立這個(gè)編譯環(huán)境的過程

  • 首先 *ssh* 登錄你剛刷的 *openwrt*,查看你刷的 *openwrt* 的版本號(hào):

 

圖12:查看openwrt的版本號(hào)

  • 下載適當(dāng)?shù)?sdk

去 [openwrt官網(wǎng)](
https://downloads.openwrt.org) 找到你所需要的版本號(hào)下的 sdk,要選擇 at91/sama5 目錄下的,這個(gè)是 cortex-A5 架構(gòu)(CPU S805 的架構(gòu))的工具鏈

[我的工具鏈的下載地址](
https://downloads.openwrt.org/releases/19.07.7/targets/at91/sama5/openwrt-sdk-19.07.7-at91-sama5_gcc-7.5.0_musl_eabi.Linux-x86_64.tar.xz)

注意這個(gè)工具鏈只能運(yùn)行在 Linux 下,我是運(yùn)行在 Ubuntu 下,而且 openwrt-19.07.7 的 SDK 只有 64 位 X86 版本;

先將這個(gè)工具鏈下載到 ~/Downloads/ 目錄下

wget https://downloads.openwrt.org/releases/19.07.7/targets/at91/sama5/openwrt-sdk-19.07.7-at91-sama5_gcc-7.5.0_musl_eabi.Linux-x86_64.tar.xz -C ~/Downloads/

 

再將其解壓出來

cd ~/Downloads
tar -xvf openwrt-sdk-19.07.7-at91-sama5_gcc-7.5.0_musl_eabi.Linux-x86_64.tar.xz

 

在 ~/Downloads/ 目錄下會(huì)建立一個(gè)新目錄
openwrt-sdk-19.07.7-at91-sama5_gcc-7.5.0_musl_eabi.Linux-x86_64,進(jìn)入到這個(gè)目錄,可以看到一個(gè) staging_dir 目錄

 

cd openwrt-sdk-19.07.7-at91-sama5_gcc-7.5.0_musl_eabi.Linux-x86_64/ 
ls

這個(gè) staging_dir 目錄下的所有內(nèi)容就是一個(gè)完整的工具鏈,我們可以把這個(gè)工具鏈單獨(dú)拿出來使用;

我把這個(gè)目錄拷貝到了 ~/tooschain/openwrt-a5/ 下,我們之所以放到 ~/toolschain/ 下,是因?yàn)槲覀冞€可能有別的設(shè)備的工具鏈,都放到這個(gè)目錄下便于管理

mkdir -p ~/toolschain/openwrt-a5/
cp -fr ~/Downloads/openwrt-sdk-19.07.7-at91-sama5_gcc-7.5.0_musl_eabi.Linux-x86_64/staging_dir/* ~/toolschain/openwrt-a5/

現(xiàn)在我們已經(jīng)有了一個(gè)完整的工具鏈,但這個(gè)工具鏈基本上是沒辦法用的,我們需要簡單的配置一下,其實(shí)就是設(shè)置一些環(huán)境變量;

在 HOME 目錄下編輯一個(gè)文件 a5.sh,內(nèi)容如下:

#!/bin/bash
#A5 arm-linux-musl-eabi工具鏈,用于一代賺錢寶openwrt 
export PATH=/home/whowin/toolschain/openwrt-a5/toolchain-arm_cortex-a5+vfpv4_gcc-7.5.0_musl_eabi/bin:$PATH
export STAGING_DIR=/home/whowin/toolschain/openwrt-a5

其中 /home/whowin 為我的 HOME 目錄,你要更改為你的 HOME 目錄;

其實(shí)這個(gè)文件就是修改了環(huán)境變量 PATH,然后增加了一個(gè)環(huán)境變量 STAGING_DIR,這些設(shè)置都是為了能夠正常使用這個(gè)工具鏈;

將這個(gè)文件設(shè)置為可執(zhí)行,然后把這個(gè)文件拷貝到 /bin/ 下:

cd ~
vi a5.sh
(編輯內(nèi)容并存盤)
chmod 755 a5.sh
sudo cp a5.sh /bin/

放到 /bin/ 目錄下只是為了用起來方便,并沒有特別的含義;

下面我們可以試一下這個(gè)工具鏈

source /bin/a5.sh
arm-openwrt-linux-gcc -v

下面是在我的機(jī)器上的輸出:

圖13:測試工具鏈

源程序

有了工具鏈就可以編程了,編程的過程要在開發(fā)機(jī)上完成,不是在 openwrt 下,但是用這個(gè)源程序編譯出來的可執(zhí)行文件是要在 openwrt 下運(yùn)行的;

下面是這個(gè)項(xiàng)目中需要在 openwrt 下運(yùn)行的程序 wakeOnLan 的源程序

/******************************************************************************
      File Name: wakeOnLan.c
      Description:  向局域網(wǎng)中的計(jì)算機(jī)發(fā)出遠(yuǎn)程喚醒的指令
                    該程序?qū)⑦\(yùn)行在迅雷一代賺錢寶上(已刷openwrt),用于喚醒主機(jī)

      Compile:  source /bin/a5.sh
                arm-openwrt-linux-gcc -Wall wakeOnLan.c -o wakeOnLan

      Usage: wakeOnLan [boradcast IP] [MAC]
      Example: sudo ./wakeOnLan 192.168.2.255 00:e0:2b:68:00:03

      Date: 2022-07-26
 *******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define  BIND_PORT         7                   // 端口號(hào)
#define  MSG_LEN           102                 // magic packet的長度
#define  USAGE             "wakeOnLan [broadcast IP] [MAC]n" 
"Example: sudo ./wakeOnLan 192.168.1.255 00:e0:2b:69:00:03n"

/*****************************************************
 * Function: int is_IP(char *IP)
 * Description: 檢查IP是否為一個(gè)合法的IPv4
 * Return: 1    合法的IPv4
 *         0    非法的IPv4
 *****************************************************/
int is_IP(char *IP) {
  int a, b, c, d;
  char e;

  if (4 == sscanf(IP, "%d.%d.%d.%d%c", &a, &b, &c, &d, &e)) {
    if (a >= 0 && a < 256 &&
        b >= 0 && b < 256 &&
        c >= 0 && c < 256 &&
        d >= 0 && d < 256) {
      return 1;
    }
  }
  return 0;
}

/*************************************************************************
 * Function: int is_MAC(char *mac_str, char *mac)
 * Description: 檢查MAC是否為合法的MAC格式,如果合法,將其轉(zhuǎn)換成6組數(shù)字放到mac中
 * 
 * Return: 1    合法的MAC,char *mac中為轉(zhuǎn)換后的mac地址
 *         0    非法的MAC
 *************************************************************************/
int is_MAC(char *mac_str, char *mac) {
  int temp[6];
  char e;
  int i;

  if (6 == sscanf(mac_str, "%x:%x:%x:%x:%x:%x%c", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &e)) {
    for (i = 0; i < 6; ++i) {
      if (temp[i] < 0 || temp[i] > 255) break;
    }
    if (i == 6) {
      for (i = 0; i < 6; ++i) {
        mac[i] = temp[i];
      }
      return 1;
    }
  }
  return 0;
}

// ===================主程序================================================
int main(int argc, char *argv[]) {
  struct sockaddr_in sin;
  char *broadcast_ip;
  char wol_msg[MSG_LEN + 2];                           // magic packet
  char mac[6];
  int socket_fd;
  int i, j;
  int on = 1;

  // 檢查參數(shù)數(shù)量
  if (argc < 3) {
    // 參數(shù)數(shù)量不對
    printf("Incorrect input parameters.n");
    printf(USAGE);
    return -1;
  }

  // 檢查第一個(gè)參數(shù)是否為一個(gè)IP地址
  if (! is_IP(argv[1])) {
    printf("%s is an invalid IPv4.n", argv[1]);
    printf(USAGE);
    return -1;
  }

  // 檢查第二個(gè)參數(shù)是否為一個(gè)MAC地址
  if (! is_MAC(argv[2], mac)) {
    printf("%s is an invalid MAC address.n", argv[2]);
    printf(USAGE);
    return -1;
  }
  printf("MAC is %02x:%02x:%02x:%02x:%02x:%02xn", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);

  // 建立socket
  socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (socket_fd < 0) {
    printf("Can not set up socket. Program exits(%d).n", socket_fd);
    return -1;
  }

  // 為IP地址分配內(nèi)存
  broadcast_ip = calloc(strlen(argv[1]) + 1, sizeof(char));
  if (! broadcast_ip) {
    printf("Can not allocate memory. Program exitsn");
    return -1;
  }
  // 允許在 socket_fd 上發(fā)送廣播消息
  setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

  memset((void *)&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = inet_addr(broadcast_ip);       // 廣播IP
  sin.sin_port = htons(BIND_PORT);                     // 端口號(hào)

  // 6個(gè) ff
  for (i = 0; i < 6; i++) {
    wol_msg[i] = 0xFF;
  }
  // 16遍 mac 地址
  for (j = 0; j < 16; j++) {
    for (i = 0; i < 6; i++) {
      wol_msg[6 + j * 6 + i] = mac[i];
    }
  }
  // 發(fā)送 magic packet
  sendto(socket_fd, &wol_msg, MSG_LEN, 0, (struct sockaddr *)&sin, sizeof(sin));
  close(socket_fd);
  // 釋放前面分配的內(nèi)存空間
  free(broadcast_ip);

  printf("Magic Packet has been sended.n");

  return 0;
}

這個(gè)程序本身比較簡單,注釋比較完整,也沒什么好說明的。

交叉編譯

交叉編譯當(dāng)然也是在開發(fā)機(jī)上完成;

假定我們把上面這個(gè)源程序放在 ~/wake_on_lan/ 目錄下,下面是交叉編譯的過程:

cd ~/wake_on_lan 
source /bin/a5.sh 
arm-openwrt-linux-gcc -Wall wakeOnLan.c -o wakeOnLan

交叉編譯的過程難免出錯(cuò),請自行排錯(cuò);

交叉編譯完成的程序是不能在開發(fā)機(jī)上運(yùn)行的,需要拷貝到 openwrt 上才能運(yùn)行,仍然假定 openwrt 的 IP 地址為:192.168.2.100,則可以這樣將已經(jīng)編譯好的程序拷貝到 openwrt 上,操作在開發(fā)機(jī)上完成

cd ~/wake_on_lan 
scp wakeOnLan [email protected]:/root/

 

在 openwrt 上運(yùn)行程序

用 ssh 登錄到 openwrt,登錄后應(yīng)該就在 /root/ 目錄下,因?yàn)?nbsp;/root/ 是 root 用戶的 HOME 目錄,然后運(yùn)行程序

ssh [email protected]
./wakeOnLan 192.168.2.255 00:e0:2b:69:00:03

 

第一個(gè)參數(shù)是局域網(wǎng)上的廣播 IP,第二個(gè)參數(shù)是要被遠(yuǎn)程喚醒的機(jī)器的 MAC 地址,請根據(jù)你的具體情況進(jìn)行修改

在我的機(jī)器上運(yùn)行效果是這樣的

圖14:在openwrt上運(yùn)行wakeOnLan

 

軟件調(diào)試

- 這個(gè)程序的調(diào)試主要是確保程序能夠正確地發(fā)出 magic packet,需要在局域網(wǎng)上找另一臺(tái)機(jī)器進(jìn)行數(shù)據(jù)包的監(jiān)聽,這臺(tái)監(jiān)聽的機(jī)器既可以運(yùn)行 windows 也可以運(yùn)行 Linux,最好是使用準(zhǔn)備遠(yuǎn)程喚醒機(jī)器作為監(jiān)聽的機(jī)器,我們以一臺(tái)運(yùn)行 ubuntu 的機(jī)器為例來完成調(diào)試

使用 ubuntu 下的工具 tcpdump 來進(jìn)行數(shù)據(jù)包的監(jiān)聽,tcpdump 必須在 root 權(quán)限下運(yùn)行;

首先在監(jiān)聽機(jī)器上運(yùn)行 tcpdump

sudo tcpdump -vv -x udp port 7

這行命令的意思就是監(jiān)聽 udp 端口 7 的數(shù)據(jù)包,-vv 的意思是顯示詳細(xì)的信息,-x 的意思是按照 16 進(jìn)制顯示,這兩個(gè)參數(shù)也可以寫成 -vvx

在 openwrt 上運(yùn)行 wakeOnLan

./wakeOnLan 192.168.2.255 00:e0:2b:69:00:03

 

其中的廣播 IP 和 MAC 地址請按照實(shí)際情況填寫

正常情況下,在監(jiān)聽機(jī)器上可以看到程序發(fā)出的 Magic Packet,仔細(xì)看一下這個(gè)數(shù)據(jù)包的格式是否正確

在我的環(huán)境下,看到的輸出如下:

圖15:偵聽Magic Packet

其中黃線標(biāo)識(shí)的部分是 IP 頭,占 20 個(gè)字節(jié);綠線標(biāo)識(shí)的部分是 UDP 頭,占 8 個(gè)字節(jié),剩下的就是 Magic Packet

如果你正常地偵聽到了一個(gè)完整且正確的 Magic Packet,那么恭喜你,就快要成功了;

如果你使用 windows 偵聽 Magic Packet 數(shù)據(jù)包,通常使用著名的 Wireshark。

局域網(wǎng)內(nèi)的網(wǎng)絡(luò)喚醒測試

- 把需要網(wǎng)絡(luò)喚醒的機(jī)器關(guān)機(jī),如果需要設(shè)置 BIOS,要先設(shè)置好 BIOS 再關(guān)機(jī);

- 使用局域網(wǎng)內(nèi)的另一臺(tái)電腦 ssh 登錄 openwrt,或者使用手機(jī)登錄 openwrt,如果使用手機(jī)登錄,需要在手機(jī)上安裝一個(gè)終端 App,我使用安卓手機(jī),安裝的 app 叫 ConnetcBot,推薦大家試一下;

在 openwrt 運(yùn)行你編寫的程序 wakeOnLan,如果你運(yùn)氣好,你那臺(tái)剛剛關(guān)機(jī)的電腦應(yīng)該被默默的打開了電源

但是,通常都沒有那么好的運(yùn)氣,那么可能的問題如下:
1. 程序里的廣播 IP 是不是正確?
2. Magic Packet 中的 MAC 地址是否正確?
3. Magic Packet 的格式是否正確?
4. 被喚醒的機(jī)器是否與 openwrt 在同一個(gè)網(wǎng)段?
5. 路由器是否限制了 UDP 的端口 7?
6. 如果以上都沒有問題,恐怕只能懷疑你那臺(tái)要被喚醒的機(jī)器不支持網(wǎng)絡(luò)喚醒,或者 BIOS 設(shè)置的不正確

內(nèi)網(wǎng)穿透

做到現(xiàn)在這樣,我們已經(jīng)完成了大部分工作,下面唯一要做的是如何從外網(wǎng)上訪問到這臺(tái) openwrt 的設(shè)備,這就是前面說過的 內(nèi)網(wǎng)穿透

搞內(nèi)網(wǎng)穿透是需要在互聯(lián)網(wǎng)上有一臺(tái)服務(wù)器(VPS)的,可以是那種很便宜性能很弱的VPS,因?yàn)槲覀儾桓蓜e的事,就是轉(zhuǎn)發(fā)一下數(shù)據(jù)而已;

我自己使用的是一臺(tái)俄羅斯的 VPS,價(jià)格只有 US$13.04/年,512M內(nèi)存,5G的SSD,運(yùn)行 ubuntu 20.04,雖然配置低,但是用起來感覺還是不錯(cuò)的,我很樂意推薦給大家:

  • [俄羅斯VPS](https://justhost.ru/?ref=149230)

前面說過我使用的內(nèi)網(wǎng)穿透的工具是一個(gè)開源項(xiàng)目,叫做 frp,項(xiàng)目地址如下:

  • [frp內(nèi)網(wǎng)穿透項(xiàng)目](https://github.com/fatedier/frp)
  • 該項(xiàng)目有中文文檔,大家可以按照文檔下載適當(dāng)?shù)?nbsp;release,其服務(wù)器軟件 frps 運(yùn)行在服務(wù)器(VPS)上,客戶端 frpc 運(yùn)行在 openwrt 上;
  • 通常服務(wù)器端軟件都是 64 位的 X86 架構(gòu),比較容易搞定;
  • 要注意的是,要看清楚運(yùn)行 openwrt 的設(shè)備是什么架構(gòu),是 32 位的還是 64 位的,比如本文中的設(shè)備 CPU 為 S805,就是一個(gè) 32 位的 arm 架構(gòu),否則你下載的客戶端軟件可能無法運(yùn)行;
  • 這個(gè)軟件的設(shè)置還是要費(fèi)一些功夫,請認(rèn)真閱讀該項(xiàng)目的文檔,并參考其范例;這里我給出我的實(shí)例

服務(wù)器端配置文件:frps.ini,其中的 xxx.xxx.xxx.xxx 請按照實(shí)際情況設(shè)置,frp_log_path 請指向?qū)嶋H存放 frp 日志的目錄

[common]
bind_addr = xxx.xxx.xxx.xxx
bind_port = 57000
bind_udp_port = 57001
kcp_bind_port = 57000
proxy_bind_addr = xxx.xxx.xxx.xxx
vhost_http_port = 58080
vhost_https_port = 58443

log_file = /frp_log_path/frps.log
log_level = info
log_max_days = 3
disable_log_color = false

detailed_errors_to_client = true

authentication_method = token
authenticate_heartbeats = false
authenticate_new_work_conns = false
token = skyline.admin

oidc_client_id =
oidc_client_secret = 
oidc_audience = 
oidc_token_endpoint_url = 

allow_ports = 58000-59000,50000-53000
max_pool_count = 15
max_ports_per_client = 0
tls_only = false
subdomain_host = frps.com
tcp_mux = true

客戶端配置文件:frpc.ini,其中的 xxx.xxx.xxx.xxx 請按照實(shí)際情況設(shè)置;openwrt.aaa.com 是一個(gè) A 記錄指向 VPS 的域名(子域名),也要根據(jù)實(shí)際情況進(jìn)行設(shè)置

[common]
server_addr=xxx.xxx.xxx.xxx
server_port=57000
log_file=/tmp/frpc.log
log_level=info
log_max_days=3
disable_log_color=false
token=skyline.admin
pool_count=5
tcp_mux=true
user=whowin
login_fail_exit=false
protocol=tcp
tls_enable=falset
DNS_server=8.8.8.8
admin_addr=127.0.0.1
admin_port=7400
admin_user=skyline
admin_pwd=admin

[ssh]
type=tcp
local_ip=192.168.2.100
local_port=22
use_encryption=false
use_compression=false
custom_domain=openwrt.aaa.com
remote_port=52998
health_check_type=tcp
health_check_timeout_s=3
health_check_max_failed=10
health_check_interval_s=30

[openwrt_web]
type=http
local_ip=192.168.2.100
local_port=80
use_encryption=false
use_compression=true
custom_domains=openwrt.aaa.com
header_X-From-Where=frp           
health_check_type=http    
health_check_url=/        
health_check_interval_s=90 
health_check_max_failed=3
health_check_timeout_s=3

啟動(dòng) VPS 上的 frpspath_to 指向?qū)嶋H路徑

/path_to/frps -c /path_to/frps.ini &

 

 

啟動(dòng) openwrt 上的 frpcpath_to 指向?qū)嶋H路徑

/path_to/frpc -c /path_to/frpc.ini &

 

 

如遇問題,強(qiáng)烈建議認(rèn)真查看 frps.log 和 frpc.log

正常情況下,現(xiàn)在你已經(jīng)可以在互聯(lián)網(wǎng)上通過 frp 訪問你家里的 openwrt 了,像這樣:

ssh [email protected] -p 52998

 

 

其中:xxx.xxx.xxx.xxx 為 VPS 的 IP 地址,52998 是在 frpc.ini 中設(shè)置的端口號(hào),也可以設(shè)置一個(gè)域名指向 VPS 的 IP,比如設(shè)置 vps.aaa.com 的 A 記錄指向 VPS,則可以這樣登錄 openwrt

ssh [email protected] -p 52998

 

同樣,按照上面的設(shè)置,如果要訪問 openwrt 的 web 界面,在瀏覽器上輸入:openwrt.aaa.com:58080 即可,58080 是在 frps.ini 中設(shè)置的一個(gè)端口號(hào);

特別要注意的是,要在 VPS 上設(shè)置好防火墻,放開可能用到的端口,否則 frp 將無法正常工作。

遠(yuǎn)程開機(jī)測試

測試遠(yuǎn)程開機(jī)使用的電腦、平板或者手機(jī),不能連接到家里的 wifi 上,建議使用手機(jī),關(guān)掉 wifi,打開 ConnectBot

設(shè)置連接如下:

圖16:在ConnectBot上設(shè)置連接

通過 *frp* 連接到 *openwrt*

圖17:在ConnectBot上連接openwrt

 

在 openwrt 上運(yùn)行 wakeOnLan

圖18:在openwrt上運(yùn)行wakeOnLan

正常情況下,MAC 地址指定的機(jī)器應(yīng)該已經(jīng)開機(jī)了;為了運(yùn)行方便,你可以在 openwrt 上寫一個(gè) shell 腳本,免得每次都要輸入 IP 地址和 MAC 地址,像下面這樣,注意,openwrt 下的 shell 是 ash

$ cat wakeOnLan.sh 
#!/bin/ash
/home/whowin/wakeOnLan 192.168.2.255 00:e0:2b:68:00:03 
$

7. 后記

前面提過,Magic Packet 可以在任意端口發(fā)送,通常使用端口 7 或 9,我們這個(gè)例子使用端口 7 發(fā)送,讀者可以試一下從其他端口發(fā)送,比如端口 1234;

實(shí)際上,openwrt 是有現(xiàn)成的網(wǎng)絡(luò)喚醒模塊的,可以在 openwrt 的 web 界面上搜索 luci-app-wol,安裝這個(gè)軟件的同時(shí),還會(huì)安裝一個(gè) etherwake 的軟件,安裝好以后,可以使用類似 etherwake -b AA:BB:CC:DD:EE:FF 的命令發(fā)送 Magic Packet 喚醒指定的機(jī)器,也可以通過 web 界面喚醒指定的電腦

圖19:在web界面上發(fā)送Magic Packet

至此,我們的這個(gè)項(xiàng)目就算做完了,我們基本上經(jīng)歷了一個(gè)嵌入式開發(fā)的全過程,只是每一個(gè)階段都比較簡單而已,嵌入式開發(fā),貌似復(fù)雜,其實(shí)并沒有想象的那么難;

在嵌入式項(xiàng)目的設(shè)計(jì)階段,我們需要有足夠的知識(shí)儲(chǔ)備以便為我們的需求提出最合理的方案,在這個(gè)項(xiàng)目的設(shè)計(jì)中,正是由于我們儲(chǔ)備了 Magic Packet 和反向代理的知識(shí),才可以為我們的需求提出這樣一個(gè)軟硬件結(jié)合的方案;

我們這個(gè)項(xiàng)目基本沒有硬件開發(fā),但是通常情況下,嵌入式開發(fā)的軟件工程師是需要參與到硬件開發(fā)中去的,包括芯片方案的選擇等都要參與意見,以便設(shè)計(jì)開發(fā)的硬件產(chǎn)品在今后的軟件開發(fā)中可以比較順利,所以嵌入式軟件工程師同樣要具備閱讀芯片的 datasheet 的能力和看懂硬件原理圖的能力,好的嵌入式軟件工程師也可以擁有非常不錯(cuò)的焊接技能;

嵌入式開發(fā)的最關(guān)鍵的地方還是軟件開發(fā),但比普通的軟件開發(fā)所要了解的知識(shí)要多很多,比如在我們這個(gè)項(xiàng)目中,我們必須要知道我們所用的硬件的 CPU 是什么,甚至要知道這個(gè) CPU 的架構(gòu),否則,我們無法為這個(gè)硬件構(gòu)建正確的操作系統(tǒng),也無法在開發(fā)機(jī)上為這個(gè)硬件構(gòu)建正確的交叉編譯環(huán)境;

如果你喜歡做嵌入式開發(fā),希望這篇文章能給予你幫助。

最后歡迎訪問我的博客:https://whowin.gitee.io

分享到:
標(biāo)簽:嵌入式
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評(píng)定2018-06-03

通用課目體育訓(xùn)練成績評(píng)定