實現一個監控 IP 的 windows 服務

實現一個監控 IP 的 windows 服務

Intro

我們公司的 VPN 用自己的電腦連公司的臺式機的時候需要用 IP 地址,有一次嘗試去連的時候發現連不上,第二天到公司發現 IP 變掉了,不是之前連的 IP 了,于是就想寫一個簡單 Windows 服務來監控臺式機的 IP 變化

Overview

在 C# 里我們可以使用 Dns.GetHostAddresses() 方法來獲取 IP 地址,我們可以每隔一段時間就判斷一下當前的 IP 地址,為了方便測試,可以把這個時間定義在配置里,這樣本地開發的時候比較方便

為了避免消息太多,我們可以做一個簡單的檢查,如果 IP 地址不變,就不發消息了,只有當 IP 信息變化的時候再發消息

我們辦公使用的是 Google Chat, 所以打算使用 Google Chat 來發消息,也可以根據需要改成自己想用的通知方式

Implement

首先我們可以新建一個 worker 服務,使用 dotnet cli 新建即可

dotnet?new?worker?-n?IpMonitor

如果不習慣沒有解決方案文件,也可以新建一個解決方案文件并將項目添加到解決方案文件中

cd?IpMonitor
dotnet?new?sln
dotnet?sln?add?./IpMonitor.csproj

然后我們來改造我們的 Worker, Worker 其實就是一個后臺服務,我們的服務比較簡單就直接在上面改了

public?sealed?class?Worker?:?BackgroundService
{private?readonly?TimeSpan?_period;private?readonly?INotification?_notification;private?readonly?ILogger<Worker>?_logger;private?volatile?string?_previousIpInfo?=?string.Empty;public?Worker(IConfiguration?configuration,?INotification?notification,?ILogger<Worker>?logger){_notification?=?notification;_logger?=?logger;_period?=?configuration.GetAppSetting<TimeSpan>("MonitorPeriod");if?(_period?<=?TimeSpan.Zero){_period?=?TimeSpan.FromMinutes(10);}}protected?override?async?Task?ExecuteAsync(CancellationToken?stoppingToken){using?var?timer?=?new?PeriodicTimer(_period);while?(await?timer.WaitForNextTickAsync(stoppingToken)){try{var?host?=?Dns.GetHostName();var?ips?=?await?Dns.GetHostAddressesAsync(host,?stoppingToken);var?ipInfo?=?$"{Environment.MachineName}?-?{host}\n?{ips.Order(new?IpAddressComparer()).Select(x?=>?x.MapToIPv4().ToString()).StringJoin(",?")}";if?(_previousIpInfo?==?ipInfo){_logger.LogDebug("IpInfo?not?changed");continue;}_logger.LogInformation("Ip?info:?{IpInfo}",?ipInfo);await?_notification.SendNotification(ipInfo);_previousIpInfo?=?ipInfo;}catch?(Exception?e){_logger.LogError(e,?"GetIp?exception");}}}
}

這里我們使用了 .NET 6 引入的 PeriodicTimer 來實現定時任務,自定義了一個 IpAddressComparer 來對 IP 地址做一個排序,實現如下:

public?sealed?class?IpAddressComparer:?IComparer<IPAddress>
{public?int?Compare(IPAddress??x,?IPAddress??y){if?(ReferenceEquals(x,?y))?return?0;if?(ReferenceEquals(null,?y))?return?1;if?(ReferenceEquals(null,?x))?return?-1;var?bytes1?=?x.MapToIPv4().ToString().SplitArray<byte>(new?[]{?'.'?});var?bytes2?=?y.MapToIPv4().ToString().SplitArray<byte>(new?[]{?'.'?});for?(var?i?=?0;?i?<?bytes1.Length;?i++){if?(bytes1[i]?!=?bytes2[i]){return?bytes1[i].CompareTo(bytes2[i]);}}return?0;}
}

通知使用了 Google Chat 的 webhook API,可以自定義一個 Space,添加一個 webhook 即可,添加成功即可獲取一個 webhook URL, 發送消息 API 可以參考文檔:https://developers.google.com/chat/api/guides/message-formats/basic

5116298fad19620ae1f125d9fc024ab0.png

a9937251c9558a6e85b38387cb09a3bc.png

實現如下:

public?sealed?class?GoogleChatNotification:?INotification
{private?readonly?HttpClient?_httpClient;private?readonly?string?_webhookUrl;public?GoogleChatNotification(HttpClient?httpClient,?IConfiguration?configuration){_httpClient?=?httpClient;_webhookUrl?=?Guard.NotNullOrEmpty(configuration.GetAppSetting("GChatWebHookUrl"));}public?async?Task<bool>?SendNotification(string?text){using?var?response?=?await?_httpClient.PostAsJsonAsync(_webhookUrl,?new?{?text?});return?response.IsSuccessStatusCode;}
}

Program 文件中注冊我們新加的服務就可以了

然后我們進行一些改造來發布和部署 Windows 服務,可以按照文檔的提示將項目發布為單文件,部署我比較喜歡 powershell,寫了兩個簡單的 powershell script 來安裝和卸載 Windows 服務

首先我們可以在項目里添加 Microsoft.Extensions.Hosting.WindowsServices 的引用,并添加一些發布屬性

<PropertyGroup><PublishSingleFile?Condition="'$(Configuration)'?==?'Release'">true</PublishSingleFile><RuntimeIdentifier>win-x64</RuntimeIdentifier><PlatformTarget>x64</PlatformTarget>
</PropertyGroup>

Program 中注冊 windows 服務相關配置

using?IpMonitor;Host.CreateDefaultBuilder(args).ConfigureServices(services?=>{services.AddHostedService<Worker>();services.AddSingleton<HttpClient>();services.AddSingleton<INotification,?GoogleChatNotification>();})
#if?!DEBUG//?https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service.UseWindowsService(options?=>{options.ServiceName?=?"IpMonitor";})
#endif.Build().Run();

安裝服務 powershell 腳本:

$serviceName?=?"IpMonitor"
Write-Output?"serviceName:?$serviceName"dotnet?publish?-c?Release?-o?out
$destDir?=?Resolve-Path?".\out"
$ipMonitorPath?=?"$destDir\IpMonitor.exe"Write-Output?"Installing?service...?$ipMonitorPath?$destDir"
New-Service?$serviceName?-BinaryPathName?$ipMonitorPath
Start-Service?$serviceName
Write-Output?"Service?$serviceName?started"

卸載服務 powershell 腳本:

$serviceName?=?"IpMonitor"
Stop-Service?$serviceName
Write-Output?"Service?$serviceName?stopped"
Remove-Service?$serviceName
Write-Output?"Service?$serviceName?removed"

運行效果如下(腳本運行需要以管理員權限運行):

我們可以使用 Get-Service IpMonitor 來查看服務狀態

368dbd953e329290deddcfe4b16ba0a3.png

install

也可以在任務管理器和服務中查看

21593d2b5c504677b392cafa73eda785.png

c2ff42bd7fd545b6b0e0bee4c495bdf6.png

最后再把我們的服務卸載掉

dc0a8563ae0cda2458c250000ec55ef5.png

uninstall

More

發布為 Windows 服務時如果有問題可以通過 event log 來排查,在 event log 里可以看到我們服務的日志

de40557f8f4dd72bf6fc2f7d2435603a.png

References

  • https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service

  • https://github.com/WeihanLi/SamplesInPractice/tree/master/IpMonitor

  • https://developers.google.com/chat/api/guides/message-formats/basic

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282293.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282293.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282293.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

微信企業號開發:啟用回調模式

微信企業號開發怎樣啟用回調模式&#xff1f;就是簡單的登陸PC版微信&#xff0c;點擊應用中心&#xff0c;選擇須要應用&#xff0c;再點擊回調模式啟用&#xff1f;似乎不是這么簡單。&#xff01;能夠看到核心的僅僅有三個URL。Token&#xff0c;EncodingAESKey這三個參數能…

MVC中提交表單的4種方式

一&#xff0c;MVC HtmlHelper方法 Html.BeginForm(actionName,controllerName,method,htmlAttributes){} BeginRouteForm 方法 (HtmlHelper, String, Object, FormMethod) 二&#xff0c;傳統Form表單Aciton屬性提交 三&#xff0c;JqueryAjax 提交表單 四&#xff0c;MVC C…

photoshop制作網站圓形圖標ico

1、選擇左側工具欄中的橢圓工具2、鼠標直接在圖片上選擇區域3、在圖片上鼠標右鍵建立選區&#xff0c;在彈出的對話框直接點確定變成這樣&#xff1a;4、點擊選擇&#xff0c;然后點擊反選變成這樣5、圖層欄&#xff0c;在圖片上右鍵復制圖層&#xff0c;彈出對話框直接確定即可…

《簡明 PHP 教程》00 開篇

《簡明 PHP 教程》是一本旨在介紹如何使用 PHP 語言進行編程的自由圖書。它以教材與指南的形式為入門者介紹 PHP 編程語言。如果你對電腦知識的了解僅限于如何保存文本文件的話&#xff0c;那這本書就是為你準備的。 本博客后續將以連載的方式為讀者呈現這本書。 關于作者 一名…

WPF 窗體設置亞克力效果

WPF 窗體設置亞克力效果控件名&#xff1a;WindowAcrylicBlur作者&#xff1a; WPFDevelopersOrg - 吳鋒原文鏈接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40。Visual Studio 2022。項目使用 MIT 開源許可協議。WindowAcrylicB…

JS向后臺傳遞json數組對象

var Obj [];            //一下代碼可以循環插入            var returnObj new Object();//創建一個對象returnObj.id “123”&#xff1b;returnObj.money 456“”;Obj.push(returnObj);           JS中將Obj對象進行序列化操作   …

ArrayBlockingQueue跟LinkedBlockingQueue的區別

1.隊列中的鎖的實現不同 ArrayBlockingQueue中的鎖是沒有分離的&#xff0c;即生產和消費用的是同一個鎖&#xff1b; LinkedBlockingQueue中的鎖是分離的&#xff0c;即生產用的是putLock&#xff0c;消費是takeLock 2.在生產或消費時操作不同 ArrayBlockingQueue基于數組&…

jqGrid('setSelection',rowid)報Cannot read property 'multiple' of undefined

項目組非要上jeeweb框架&#xff0c;用jqgrid大量iframe做為前端框架&#xff0c;臃腫不堪。 今天上午&#xff0c;在進行選定操作jqGrid(setSelection,rowid)報Cannot read property multiple of undefined&#xff0c;怎么分析也找不出原因&#xff0c;最后百度搜了一下竟然有…

數據分塊加載——BigPipe 技術【類似facebook】

一、原理 分塊加載&#xff0c;加載完一塊&#xff0c;就先把頁面數據刷給用戶&#xff0c;再加載下面的&#xff0c;直到加載完畢二、基礎需知&#xff1a;三、服務端和php的相應配置 如果想實現分塊加載【bigpipe技術】&#xff0c;還需要對nginx.conf 和 php.ini 進行相應配…

Maven -- 在進行war打包時用正式環境的配置覆蓋開發環境的配置

我們的配置文件一般都放在 src/main/resource 目錄下。 假定我們的正式環境配置放在 src/main/online-resource 目錄下。 那么打成war包時&#xff0c;我們希望用online-resource下的配置文件取代resource 下的配置文件。 pom.xml 插件配置&#xff1a; <plugin><gr…

右鍵一下,哇塞!

面向 Dev 頻道的 Windows 預覽體驗成員微軟推送了 Windows 11 預覽版Insider Preview Build 25211主要變化1.微軟改進了 Windows 11 小組件面板&#xff0c;小組件面板中的添加按鈕更加醒目&#xff0c;點擊用戶頭像將打開小組件設置。Windows 11 小組件由 Microsoft Edge 瀏覽…

前端學習 -- Css -- 內聯元素的盒模型

內聯元素不能設置width和height&#xff1b;設置水平內邊距,內聯元素可以設置水平方向的內邊距&#xff1a;padding-left&#xff0c;padding-right&#xff1b;垂直方向內邊距&#xff0c;內聯元素可以設置垂直方向內邊距&#xff0c;但是不會影響頁面的布局&#xff1b;為元素…

Redis 數據持久化的方案的實現

一、需要了解的基礎 1、Redis實現數據持久化的兩種實現方式&#xff1a; RDB&#xff1a;指定的時間間隔內保存數據快照 AOF&#xff1a;先把命令追加到操作日志的尾部&#xff0c;保存所有的歷史操作二、RDB 實現 Redis數據持久化&#xff08;默認方式&#xff09;1、編輯 red…

div剩余空間填滿

div里有一個固定高度的div使其另一個div填滿空間&#xff0c;外層div設置的高度為百分比&#xff0c;給外層一個相對定位&#xff0c;設置想要充滿的div高度為100%&#xff0c;其中這次有個要求&#xff0c;使其填充div里面的內容距離固定高度div30px&#xff1b;給填充div一個…

快速生成快遞柜唯一取件碼

曾管理一萬多臺快遞柜&#xff0c;優化了系統中生成唯一取件碼的算法。項目&#xff1a;https://github.com/nnhy/PickupCode新建項目&#xff0c;添加 Nuget 應用 NewLife.Redis &#xff0c;借助其Add去重能力。代碼如下&#xff1a;private static void Main(string[] args)…

自動調試自動編譯五分鐘上手

Browsersync能讓瀏覽器實時、快速響應您的文件更改&#xff08;html、js、css、sass、less等&#xff09;并自動刷新頁面。更重要的是 Browsersync可以同時在PC、平板、手機等設備下進項調試。 無論您是前端還是后端工程師&#xff0c;使用它將提高您30%的工作效率。 MD5加密&a…

六臺機器搭建RedisCluster分布式集群

一、RedisCluster結構二、redis Cluster集群搭建1、修改redis.conf中需要更改的配置 bind 改成當前ip cluster-enabled yes #允許redis集群 cluster-config-file nodes-6379.conf #集群配置文件 cluster-node-timeout 15000 #集群中節點允許失聯的最大時間15s 注&#xff1…

C# 的 async/await 其實是stackless coroutine

注&#xff1a; 最近Java 19引入的虛擬線程火熱&#xff0c;還有很多人羨慕 go的 coroutine&#xff0c;很多同學一直有一個疑問&#xff1a; C# 有 虛擬線程或者 coroutine嗎&#xff0c;下面的這個回答可以解決問題。這里節選的是知乎上的hez2010 的高贊回答&#xff1a;http…

推薦使用typora

最近在網上接觸到一款全新的markdown寫作工具——typora。 現在它已經是我的主要寫作工具了。 甚至我也也會利用它安排自己的工作和任務。 typora介紹 下載鏈接特色&#xff1a;可以即時渲染markdown語法的書寫工具總算找到了&#xff0c;終于不用再糾結發生語法錯誤&#xff0…

中文詞頻統計

import jiebafoopen(text.txt,r,encodingutf-8)tfo.read()fo.close() wordsjieba.cut(t)dic{}for w in words: if len(w)1: continue else: dic[w]dic.get(w,0)1wc list(dic.items())wc.sort(keylambda x:x[1],reverse True)for i in range(20): print(wc[i]) 轉載于:https:/…