实现一个监控 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.mzph.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;弹出对话框直接确定即可…

WPF 窗体设置亚克力效果

WPF 窗体设置亚克力效果控件名&#xff1a;WindowAcrylicBlur作者&#xff1a; WPFDevelopersOrg - 吴锋原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40。Visual Studio 2022。项目使用 MIT 开源许可协议。WindowAcrylicB…

数据分块加载——BigPipe 技术【类似facebook】

一、原理 分块加载&#xff0c;加载完一块&#xff0c;就先把页面数据刷给用户&#xff0c;再加载下面的&#xff0c;直到加载完毕二、基础需知&#xff1a;三、服务端和php的相应配置 如果想实现分块加载【bigpipe技术】&#xff0c;还需要对nginx.conf 和 php.ini 进行相应配…

右键一下,哇塞!

面向 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…

快速生成快递柜唯一取件码

曾管理一万多台快递柜&#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…

中文词频统计

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:/…

[BZOJ1509][NOI2003]逃学的小孩

1509: [NOI2003]逃学的小孩 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 968 Solved: 489[Submit][Status][Discuss]Description Input 第一行是两个整数N&#xff08;3  N  200000&#xff09;和M&#xff0c;分别表示居住点总数和街道总数。以下M行&#xff0c;每行…

关闭 Visual Studio 2013 的 Browser Link 功能

什么是 Browser Link ? 这个 Browser Link 的功能就是通过一个脚本文件架起流程器和 Visual Studio IDE 之前的一个通信桥梁&#xff0c; 在启用 Browser Link 后&#xff0c; Visual Studio 会给网站注入一个 IHttpModule 模块对象&#xff0c; 然后在每个页面都会注册一段上…

Groove list操作-转数组,collect,each等

2019独角兽企业重金招聘Python工程师标准>>> list转换为数组 List list [a,b,c,d] def strs list as String[] println strs[0] 使用了Groovy语言&#xff0c;就能时不时的感受到Groovy语言在编码风格上与Java语言的不同。当然&#xff0c;我们首先感受到的可能就…

支持多种操作系统的新一代服务主机

一个应用需要常驻操作系统后台服务&#xff0c;可选框架有WindowsServiceLifeTime和SystemdLifeTime&#xff0c;但需要区别对待不同操作系统且需要另外写命令安装。NewLife.Agent自2008年设计以来&#xff0c;一直秉着简单易用的原则&#xff0c;不仅实现了服务框架&#xff0…

[翻译]Dapr 长程测试和混沌测试

介绍这是Dapr的特色项目&#xff0c;具体参见&#xff1a;https://github.com/dapr/test-infra/issues/11 &#xff0c;在全天候运行的应用程序中保持Dapr可靠性至关重要。在部署真正的应用程序之前&#xff0c;可以通过在受控的混沌环境中构建&#xff0c;部署和操作此类应用程…

Mysql Lost connection to MySQL server at ‘reading initial communication packet', system error: 0

一、问题描述&#xff1a; 在服务器端可以正常连接并操作mysql&#xff0c;但是在windows端使用navicat工具远程ssh连接就出现下面错误。 1、服务器端&#xff1a; 2、windows端navicat连接 3、原因 原来我今天在做主从配置的时候&#xff0c;将 /etc/my.cnf 配置文件中的b…

自定义ProgressBar(圆)

2019独角兽企业重金招聘Python工程师标准>>> <lib.view.progressbar.ColorArcProgressBarandroid:layout_width"match_parent"android:layout_height"220dip"android:id"id/barInterest"android:layout_centerInParent"true&…