如何使用C#检查网络连接

调用Windows API 在C#中可以通过Pinvoke调用windows API方式来进行网络连接的检查: [DllImport("wininet.dll", SetLastError=true)] extern static bool InternetGetConnectedState(out int lpdwFlags, int dwReserved); [Flags] enum ConnectionStates { Modem = 0x1, LAN = 0x2, Proxy = 0x4, RasInstalled = 0x10, Offline = 0x20, Configured = 0x40, } MSDN地址 https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetgetconnectedstate 对应的返回值Description如下: Value Meaning INTERNET_CONNECTION_CONFIGURED0x40 Local system has a valid connection to the Internet, but it might or might not be currently connected. INTERNET_CONNECTION_LAN0x02 Local system uses a local area network to connect to the Internet....

使用go发送邮件的注意事项

服务器设置 SPF设置 如果你使用的是企业邮箱,可能需要添加SPF记录。SPF(Sender Policy Framework) 是电子邮件系统中发送方策略框架的缩写,它的内容写在DNS的txt类型的记录里面;作用是防止别人伪造你的邮件地址进行发信,是一种非常高效的反垃圾邮件解决方案。如果你的服务器没有设置邮件的SPF,那么在发送邮件到Gmail等邮箱地址时,会发生退信。 一般给域名添加SPF记录的方式是添加一条TXT记录。以腾讯企业邮箱为例,添加的TXT记录值是v=spf1 include:spf.mail.qq.com -all 使用go可以实现查询域名的TXT信息。 func TestNetLookupTxt(t *testing.T) { txt, err := net.LookupTXT("czyt.tech") if err != nil { t.Fatal(err) } t.Log(txt) } DKIM 腾讯企业邮箱 DKIM配置说明 DMARC DMARC(Domain-based Message Authentication, Reporting & Conformance)是一种基于现有的SPF和DKIM协议的可扩展电子邮件认证协议,邮件收发双方建立了邮件反馈机制,便于邮件发送方和邮件接收方共同对域名的管理进行完善和监督。对于未通过前述检查的邮件,接收方则按照发送方指定的策略进行处理,如直接投入垃圾箱或拒收。从而有效识别并拦截欺诈邮件和钓鱼邮件,保障用户个人信息安全。这里同样以腾讯企业邮箱为例。在DNS管理的地方添加以下DMARC记录: 主机记录: _dmarc 记录类型:TXT 记录值: v=DMARC1; p=none; rua=mailto:mailauth-reports@qq.com 注意:DMARC记录里,有一个值可由你来自定义: p:用于告知收件方,当检测到某封邮件存在伪造发件人的情况,收件方要做出什么处理; p=none; 为收件方不作任何处理 p=quarantine; 为收件方将邮件标记为垃圾邮件 p=reject; 为收件方拒绝该邮件 rua:用于在收件方检测后,将一段时间的汇总报告,发送到哪个邮箱地址。 ruf:用于当检测到伪造邮件时,收件方须将该伪造信息的报告发送到哪个邮箱地址。ruf=mailto:xxx@xxxxxx.com; DMARC是基于DKIM和SPF的,所以开启DMARC必须先开启DKIM或SPF任意一种 消息体 Message-Id 对于Gmail等邮箱,如果你在发送邮箱的时候没有带上Message-Id也会触发退信。这时需要你在邮件发送的Header中添加Message-Id.例如<4867a3d78a50438bad95c0f6d072fca5@mailbox01.contoso.com>。可以参考微软的相关文档 邮件模板 对于常见的邮件模板,可以使用Hermes这个Golang库。下面是一个例子: package main import ( "github.com/matcornic/hermes/v2" ) type inviteCode struct { } func (w *inviteCode) Name() string { return "invite_code" } func (w *inviteCode) Email() hermes....

使用Hashcorp的cleanhttp

缘起 早上在某地方看到这样一张图 大意是说任何第三方库都可以拦截您的所有 HTTP 调用,然后推荐了一个库 cleanhttp 官网的介绍: Functions for accessing “clean” Go http.Client values 用于访问“干净”Go http.Client 值的函数 The Go standard library contains a default http.Client called http.DefaultClient. It is a common idiom in Go code to start with http.DefaultClient and tweak it as necessary, and in fact, this is encouraged; from the http package documentation: Go 标准库包含一个名为 http.DefaultClient 的默认 http.Client 。在 Go 代码中,以 http.DefaultClient 开头并根据需要进行调整是一种常见的习惯用法,事实上,这是值得鼓励的;来自 http 包文档: The Client’s Transport typically has internal state (cached TCP connections), so Clients should be reused instead of created as needed....

Rxgo使用备忘录

官网文档 –机器翻译内容– 介绍 ReactiveX,简称 Rx,是一个用于使用 Observable 流进行编程的 API。 RxGo 实现基于管道的概念。管道是由通道连接的一系列阶段,其中每个阶段是一组运行相同功能的 goroutine。 让我们看一个具体的例子,每个框都是一个运算符: 我们使用 Just 运算符基于固定的项目列表创建一个静态 Observable。 我们使用 Map 运算符定义一个转换函数(将圆形转换为方形)。 我们使用 Filter 运算符过滤每个黄色方块。 在此示例中,最终物品在通道中发送,可供消费者使用。使用 RxGo 消费或生成数据的方法有很多种。在频道中发布结果只是其中之一。 每个算子都是一个转换阶段。默认情况下,一切都是顺序的。然而,我们可以通过定义同一运算符的多个实例来利用现代 CPU 架构。每个运算符实例都是连接到公共通道的 goroutine。 RxGo 的理念是实现 ReactiveX 概念并利用主要的 Go 原语(通道、goroutines 等),以便两个世界之间的集成尽可能顺利。 安装 RxGo v2 go get -u github.com/reactivex/rxgo/v2 入门 你好世界 让我们创建第一个 Observable 并使用一个项目: observable := rxgo.Just("Hello, World!")() ch := observable.Observe() item := <-ch fmt.Println(item.V) Just 运算符从静态项目列表创建一个 Observable。 Of(value) 根据给定值创建一个项目。如果我们想从错误中创建一个项目,我们必须使用 Error(err) 。这与 v1 不同,v1 直接接受值或错误而无需包装它。这一改变的理由是什么?它是为了(希望)Go 2 中的泛型功能为 RxGo 做好准备。...

在GO中使用日志库slog

本文根据三篇文章机翻拼凑而来。其中两篇文章发布时,slog还未进入标准库。golang 1.21.0 于2023-08-09发布,slog也包含在正式库中,本文根据原文内容进行了部分的修订和补充。 什么是slog? slog 是 Go 团队的一个实验性日志记录包,提供结构化日志记录的功能。 本文向您概述了此包中的日志记录功能。 安装 # 创建一个新的 go 项目并引入 log/slog 使用记录器# 立即导入并开始使用记录器。 package main import ( "log/slog" ) func main() { slog.Info("Go is best language!") } 输出: $ go run main.go 2022/12/15 01:31:23 INFO Go is best language! 默认情况下,输出包括时间、日志级别和消息。 以下日志级别可用。 Debug Info Warn Error 结构化日志# slog 是一个结构化记录器,支持两种格式的日志记录:文本和 json。 让我们看一下文本记录器。 文本处理程序# 您首先创建一个文本处理程序和一个新的记录器。 package main import ( "os" "log/slog" ) func main() { textHandler := slog.NewTextHandler(os.Stdout,nil) logger := slog....

HashiCorp go-plugin包使用指南

1. 介绍 HashiCorp的go-plugin包是一个强大的Go语言插件系统,它通过RPC实现主程序和插件之间的通信。这个系统被广泛应用于HashiCorp的多个项目中,如Terraform、Nomad、Vault、Boundary和Waypoint等。本文将循序渐进地介绍go-plugin的使用方法,并提供简单易复现的例子。 2. 基本概念 go-plugin的工作原理是启动子进程并通过RPC进行通信。它支持标准的net/rpc和gRPC两种通信方式。主要特点包括: 插件是Go接口的实现 支持跨语言插件 支持复杂参数和返回值 支持双向通信 内置日志功能 协议版本控制 支持stdout/stderr同步 TTY保留 插件运行时主机升级 加密安全的插件 3. 单向通信示例 让我们从一个简单的单向通信示例开始,实现一个基本的问候插件。 3.1 定义接口 首先,我们需要定义插件将要实现的接口: // shared/interface.go package shared import "context" type Greeter interface { Greet(ctx context.Context, name string) (string, error) } 3.2 实现插件 接下来,我们实现这个接口作为一个插件: // plugin/main.go package main import ( "context" "fmt" "github.com/hashicorp/go-plugin" "path/to/your/shared" ) type GreeterPlugin struct{} func (g *GreeterPlugin) Greet(ctx context.Context, name string) (string, error) { return fmt.Sprintf("Hello, %s!", name), nil } var handshakeConfig = plugin....

如何为七牛已绑定域名的bucket获取Let's Encrypt证书

关于Let’s Encrypt证书 官网的说明是 一个为 2.25 亿个网站提供 TLS 证书的非盈利性证书颁发机构。 官网 : https://letsencrypt.org/zh-cn/ 获取证书的验证方式 目前有很多自动工具可以获取,需要有相关的域名或者服务器权限。认证的方式有三种,这里引用下官网的说明。验证方式 当您从 Let’s Encrypt 获得证书时,我们的服务器会验证您是否使用 ACME 标准定义的验证方式来验证您对证书中域名的控制权。 大多数情况下,验证由 ACME 客户端自动处理,但如果您需要做出一些更复杂的配置决策,那么了解更多有关它们的信息会很有用。 如果您不确定怎么做,请使用您的客户端的默认设置或使用 HTTP-01。 HTTP-01 验证 这是当今最常见的验证方式。 Let’s Encrypt 向您的 ACME 客户端提供一个令牌,然后您的 ACME 客户端将在您对 Web 服务器的 http://<你的域名>/.well-known/acme-challenge/(用提供的令牌替换 )路径上放置指定文件。 该文件包含令牌以及帐户密钥的指纹。 一旦您的 ACME 客户端告诉 Let’s Encrypt 文件已准备就绪,Let’s Encrypt 会尝试获取它(可能从多个地点进行多次尝试)。 如果我们的验证机制在您的 Web 服务器上找到了放置于正确地点的正确文件,则该验证被视为成功,您可以继续申请颁发证书。 如果验证检查失败,您将不得不再次使用新证书重新申请。 我们的 HTTP-01 验证最多接受 10 次重定向。 我们只接受目标为“http:”或“https:”且端口为 80 或 443 的重定向。 我们不目标为 IP 地址的重定向。 当被重定向到 HTTPS 链接时,我们不会验证证书是否有效(因为验证的目的是申请有效证书,所以它可能会遇到自签名或过期的证书)。 HTTP-01 验证只能使用 80 端口。 因为允许客户端指定任意端口会降低安全性,所以 ACME 标准已禁止此行为。...

Avalonia使用备忘

安装 模板 可以安装一些Avalonia的dotnet模板 dotnet new install Templates.Prism.Avalonia dotnet new install Avalonia.Templates IDE插件 Rider里面安装插件 AvaloniaRider VisualStudio安装插件 Avalonia for Visual Studio Avalonia 中的一些特性 Binding $parent 您可以使用$parent符号绑定到目标在逻辑上的父级: <Button DockPanel.Dock="Bottom" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" x:CompileBindings="False" Command="{Binding $parent[Window].DataContext.AddItem}">Add Item </Button> <Border Tag="Hello World!"> <TextBlock Text="{Binding $parent.Tag}"/> </Border> 也可以通过在$parent符号添加索引器绑定到父控件的父控件: <Border Tag="Hello World!"> <Border> <TextBlock Text="{Binding $parent[1].Tag}"/> </Border> </Border> 索引器从0开始,因此$parent[0]等同于$parent。 还可以按类型绑定到祖先: <Border Tag="Hello World!"> <Decorator> <TextBlock Text="{Binding $parent[Border].Tag}"/> </Decorator> </Border> 最后,您可以组合索引器和类型: <Border Tag="Hello World!"> <Border> <Decorator> <TextBlock Text="{Binding $parent[Border;1].Tag}"/> </Decorator> </Border> </Border> 如果需要在祖先类型中包含XAML命名空间,一般使用:字符:...

Buf使用备忘

Buf 工具针对于Schema驱动、基于 Protobuf 的 API 开发,为服务发布者和服务客户端提供可靠和更好的用户体验。简化了您的 Protobuf 管理策略,以便您可以专注于重要的事情。 下载安装 可以直接去buf的GitHub的release页面下载,其他的安装方式参考官方文档 使用 三个yaml文件 初次接触buf项目的时候,有个疑问就是buf项目中buf.yaml buf.gen.yaml buf.work.yaml这个三个文件的区别和用途。下面是简单的一个表,列出了三个文件的区别: 文件名 文件位置 说明 buf.yaml 每个proto模块定义的根目录 buf.yaml 配置的位置告诉 buf 在哪里搜索 .proto 文件,模块的依赖项以及如何处理导入 buf.gen.yaml 一般放在仓库的根目录 文件控制 buf generate 命令如何针对任何输入执行 protoc 插件 buf.work.yaml 一般放在仓库的根目录 定义项目需要哪些proto模块 示例目录结构: . ├── buf.gen.yaml ├── buf.work.yaml ├── proto │ ├── acme │ │ └── weather │ │ └── v1 │ │ └── weather.proto │ └── buf.yaml └── vendor └── protoc-gen-validate ├── buf.yaml └── validate └── validate....

浅析Jetbrains的产品版本和更新API设计

接口分析 单个产品信息接口 首先我们通过http抓包来看DataGrip这个产品查询接口,访问的接口地址为下面这个地址 https://data.services.jetbrains.com/products?code=DG&release.type=eap,rc,release&fields=distributions,link,name,releases&_=1690557030459 从接口上我们能看到有下面几个方面: graphql风格接口设计。 支持产品代码、软件包通道、软件平台的筛选。主要有下面几个: 平台 说明 Windows linux windowsZip windows压缩包 windowsARM64 mac macM1 该接口返回信息如下: { "DG": [ { "date": "2023-07-20", "type": "release", "downloads": { "linuxARM64": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.tar.gz", "size": 570768510, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2-aarch64.tar.gz.sha256" }, "linux": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.tar.gz", "size": 569402212, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2.tar.gz.sha256" }, "thirdPartyLibrariesJson": { "link": "https://resources.jetbrains.com/storage/third-party-libraries/datagrip/datagrip-2023.2-third-party-libraries.json", "size": 62706, "checksumLink": "https://resources.jetbrains.com/storage/third-party-libraries/datagrip/datagrip-2023.2-third-party-libraries.json.sha256" }, "windows": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.exe", "size": 447884488, "checksumLink": "https://download.jetbrains.com/datagrip/datagrip-2023.2.exe.sha256" }, "windowsZip": { "link": "https://download.jetbrains.com/datagrip/datagrip-2023.2.win.zip", "size": 566939835, "checksumLink": "https://download....