Flutter局域網(wǎng)關(guān)閉Windows

今天分享一個局域網(wǎng)喚醒Windows,F(xiàn)lutter局域網(wǎng)關(guān)閉Windows的方案窿锉。

這個方案是我根據(jù)我的需求而定制氮唯,并不一定適用所有人,僅供參考良风。? ? ? 因為我有一個局域網(wǎng)NAS谊迄,安裝的是Windows Server 2019,用作家庭的電影文件存儲烟央,跨設(shè)備傳輸统诺,掛載了2個機械盤,耗電是25-30W疑俭,平時沒有使用的時候,習(xí)慣將它關(guān)機粮呢,但是因為放在柜子內(nèi)部,而且沒有外接顯卡钞艇,之前都是手動開機啄寡,使用其他Windows連入進(jìn)行關(guān)機,非常的不方便香璃,所以自己做了一套開關(guān)機方案这难。

【開機方案】

關(guān)于開機方案,方案有很多種葡秒。

1.網(wǎng)卡喚醒

2.主板通電喚醒

3.主板開關(guān)跳線

第一種方案好像是支持外網(wǎng)的姻乓,因為我沒有外網(wǎng)開機需求嵌溢,所以這次沒做,它的原理是通過網(wǎng)絡(luò)給指定網(wǎng)卡發(fā)送數(shù)據(jù)包蹋岩,收到數(shù)據(jù)包的網(wǎng)卡調(diào)用電腦開機赖草。

第三種方案需要購買設(shè)備,如果會硬件開發(fā)那是最優(yōu)方案剪个,這次我沒選秧骑。


我選擇的第二種方案,我購買了一個 小米智能插座扣囊,大概是幾十塊錢乎折,然后在電腦主板Bios里面設(shè)置 通電開機,在米家里面進(jìn)行通電操作侵歇,這樣就完成了 遠(yuǎn)程開機的功能骂澄。

【關(guān)機方案】

關(guān)于關(guān)機方案,也有幾種

1.小米插座直接斷電(直接斷電惕虑,傷電腦)

2.開柜子按關(guān)機鍵(太麻煩了)

3.遠(yuǎn)程桌面進(jìn)入系統(tǒng)坟冲,點關(guān)機(...)

最后我選擇了使用軟件關(guān)機的方案,順便也 宣傳一波flutter溃蔫。

設(shè)計的方案是健提,在目標(biāo)客戶端上面啟動一個進(jìn)程,監(jiān)聽某個端口伟叛,然后用手機連入端口發(fā)送指令私痹,這樣就可以完成關(guān)機和其他操作。

【技術(shù)方案】

一開始準(zhǔn)備Windows上面使用WPF開發(fā)痪伦,這個我比較熟悉侄榴,手機端使用Flutter。

后面決定用flutter 完全開發(fā)Windows+Android网沾。最終也是滿足了我的需求癞蚕。

【網(wǎng)絡(luò)協(xié)議】選擇

? ? ? ? 網(wǎng)絡(luò)協(xié)議方面,首先是放棄TCP辉哥,然后我使用的是Http監(jiān)聽桦山,覺得結(jié)構(gòu)有點重了(Http協(xié)議優(yōu)勢是,flutter端也不用寫了醋旦,直接瀏覽器訪問一個網(wǎng)址就可以恒水,但是后面我發(fā)現(xiàn)因為NAS主機沒有固定IP,IP地址會變化饲齐,只有主機名钉凌,在手機上Linux核心的系統(tǒng)好像原生就不支持解析hostname,考慮到以后這個功能可能會給多個電腦使用捂人,最終放棄http協(xié)議)御雕,最后選擇了UDP通訊矢沿。

【W(wǎng)indows端】


? ? ? ? ? ? 啟動后UDP監(jiān)聽19999端口,當(dāng)收到固定消息包的消息時酸纲,將自己的信息封裝后發(fā)給對方主機捣鲸,當(dāng)收到關(guān)機指令,使用MethodChannel 調(diào)用Windows cpp里面的函數(shù)進(jìn)行關(guān)機

```

RawDatagramSocket.bind(InternetAddress.anyIPv4, 19999).then(

? ? ? (RawDatagramSocket udpSocket) {

? ? ? ? udpSocket.forEach((RawSocketEvent event) async {

? ? ? ? ? if (event == RawSocketEvent.write) {

? ? ? ? ? ? state.value = "服務(wù)已啟動";

? ? ? ? ? }

? ? ? ? ? if (event == RawSocketEvent.read) {

? ? ? ? ? ? Datagram? dg = udpSocket.receive();

? ? ? ? ? ? if (dg != null) {

? ? ? ? ? ? ? //dg.data.forEach((x) => print(x));

? ? ? ? ? ? ? if (dg.data.first == 0) {

? ? ? ? ? ? ? ? //廣播消息闽坡,回發(fā)自己的計算機信息

? ? ? ? ? ? ? ? List<int> data = const Utf8Encoder()

? ? ? ? ? ? ? ? ? ? .convert(windowsDeviceInfo?.computerName ?? "");

? ? ? ? ? ? ? ? udpSocket.send(data, dg.address, dg.port);

? ? ? ? ? ? ? } else if (dg.data.first == 1) {

? ? ? ? ? ? ? ? //關(guān)機

? ? ? ? ? ? ? ? state.value = "已收到開機指令";

? ? ? ? ? ? ? } else if (dg.data.first == 2) {

? ? ? ? ? ? ? ? //關(guān)機

? ? ? ? ? ? ? ? state.value = "已收到關(guān)機指令";

? ? ? ? ? ? ? ? platform.invokeMethod("CloseWindows");

? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? state.value = "已收到指令:${const Utf8Decoder().convert(dg.data)}";

? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? }

? ? ? ? });

? ? ? },

? ? );

```

```

#include "flutter/method_channel.h"

? #include "flutter/standard_method_codec.h"

? void configMethodChannel(flutter::FlutterEngine *engine)

{

? ? ? ? const std::string test_channel("DMSkin.Channel");

? ? ? ? const flutter::StandardMethodCodec &codec = flutter::StandardMethodCodec::GetInstance();

? ? ? ? flutter::MethodChannel method_channel_(engine->messenger(), test_channel, &codec);

? ? ? ? method_channel_.SetMethodCallHandler([](const auto &call, auto result)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? std::cout << "Inside method call" << std::endl;

? ? ? ? ? ? if (call.method_name().compare("CloseWindows") == 0) {

? ? ? ? ? ? std::cout << "Close window message recieved!" << std::endl;

? ? ? ? ? ? system("shutdown -s -t 3");

? ? ? ? ? ? std::cout << "Close window Success!" << std::endl;

? ? ? ? result->Success();

? ? }

? ? ? ? else if (call.method_name().compare("goToNativeScanPage") == 0) {

? ? ? ? ? ? std::cout << "goToNativeScanPage!" << std::endl;

? ? ? ? result->Success();

? ? } });

}

```

【手機端】


? ? ? ? ? ? 啟動后使用bind綁定本機端口栽惶,因為是any + 0,所有系統(tǒng)會分配一個隨機的端口號疾嗅,這個用來發(fā)送數(shù)據(jù)外厂,不需要知道具體的端口號,所以無所謂宪迟。數(shù)據(jù)包比較簡單酣衷,只用了一個 int 長度。

```

void init() async {

? ? port = 19999;

? ? socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);

? ? if (socket != null) {

? ? ? socket!.broadcastEnabled = true;

? ? ? socket!.listen((RawSocketEvent event) {

? ? ? ? if (event == RawSocketEvent.write) {

? ? ? ? ? sendBroadcast();

? ? ? ? }

? ? ? ? else if (event == RawSocketEvent.read) {

? ? ? ? ? Datagram? datagram = socket!.receive();

? ? ? ? ? if (datagram != null) {

? ? ? ? ? ? String name = const Utf8Decoder().convert(datagram.data);

? ? ? ? ? ? if (!data.any(

? ? ? ? ? ? ? ? (element) => element.ip!.address == datagram.address.address)) {

? ? ? ? ? ? ? Windows windows = Windows()

? ? ? ? ? ? ? ? ..name = name

? ? ? ? ? ? ? ? ..ip = datagram.address;

? ? ? ? ? ? ? data.add(windows);

? ? ? ? ? ? ? change(null, status: RxStatus.success());

? ? ? ? ? ? }

? ? ? ? ? }

? ? ? ? }

? ? ? });

? ? ? change(null, status: RxStatus.success());

? ? }

? }

? /* 發(fā)送廣播 - 在線 */

? void sendBroadcast() {

? ? if (socket != null && port != 0) {

? ? ? socket!.send([0], InternetAddress("255.255.255.255"), port);

? ? }

? }

? /* 關(guān)閉電腦 */

? void sendShutDown(InternetAddress ip) async {

? ? socket.send([2], InternetAddress(ip.address), port);

? }

```

【開機自啟】遇到的問題

? ? shell:startup 不登錄桌面次泽,程序不打開,

最終使用的是:

1.右鍵點擊此電腦圖標(biāo)席爽,在彈出菜單中選擇“管理”菜單項意荤。

2.然后在打開的計算機管理窗口中,找到“任務(wù)計劃程序”菜單項只锻。

3.右鍵玖像,點擊創(chuàng)建基本任務(wù),選擇開機啟動一個進(jìn)程齐饮。

4.修改這個計劃捐寥,在設(shè)置中修改為不登錄桌面就啟動,輸入電腦的開機密碼祖驱。

【廣域網(wǎng)擴展】

這套方案中握恳,只需要將端口映射到公網(wǎng)中,將Flutter端的廣播改為固定IP捺僻,就可以實現(xiàn)外網(wǎng)關(guān)機乡洼,當(dāng)然你的手機必須要在公網(wǎng)網(wǎng)段上,不然NAT地址無法回發(fā)到真實的手機19999端口上匕坯。

github地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末束昵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子葛峻,更是在濱河造成了極大的恐慌锹雏,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件术奖,死亡現(xiàn)場離奇詭異礁遵,居然都是意外死亡匿辩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門榛丢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铲球,“玉大人,你說我怎么就攤上這事晰赞〖诓。” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵掖鱼,是天一觀的道長然走。 經(jīng)常有香客問我,道長戏挡,這世上最難降的妖魔是什么芍瑞? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮褐墅,結(jié)果婚禮上拆檬,老公的妹妹穿的比我還像新娘。我一直安慰自己妥凳,他們只是感情好竟贯,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逝钥,像睡著了一般屑那。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上艘款,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天持际,我揣著相機與錄音,去河邊找鬼哗咆。 笑死蜘欲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岳枷。 我是一名探鬼主播芒填,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼空繁!你這毒婦竟也來了殿衰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盛泡,失蹤者是張志新(化名)和其女友劉穎闷祥,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡凯砍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年箱硕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悟衩。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡剧罩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出座泳,到底是詐尸還是另有隱情惠昔,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布挑势,位于F島的核電站镇防,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏潮饱。R本人自食惡果不足惜来氧,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望香拉。 院中可真熱鬧啦扬,春花似錦、人聲如沸缕溉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽证鸥。三九已至,卻和暖如春勤晚,著一層夾襖步出監(jiān)牢的瞬間枉层,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工赐写, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸟蜡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓挺邀,卻偏偏與公主長得像揉忘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子端铛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359