<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>X̂ Blog</title><link>https://blog.xhat.org/</link><description>Recent content on X̂ Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 19 Sep 2023 23:34:26 +0800</lastBuildDate><atom:link href="https://blog.xhat.org/index.xml" rel="self" type="application/rss+xml"/><item><title>OpenSSL 生成自签名证书</title><link>https://blog.xhat.org/posts/openssl-self-signed/</link><pubDate>Tue, 19 Sep 2023 23:34:26 +0800</pubDate><guid>https://blog.xhat.org/posts/openssl-self-signed/</guid><description>免费证书有效期一般较短，当服务器较多时，每个服务器都要安装脚本更新证书，管理起来比较麻烦。而合理使用自签名证书（比如测试或者非公开环境）也是不错的替代选择。
生成 CA 根证书 CA (Certificate Authority) 被称为证书授权中心，是数字证书发放和管理的机构。
根证书是 CA 认证中心给自己颁发的证书，是信任链的起始点。安装根证书意味着对这个 CA 认证中心的信任。
生成私钥 可以选择以下任何一种算法：
椭圆曲线（ECC）：
openssl ecparam -genkey -name secp384r1 -out ca.key 若需要加密私钥：
openssl ecparam -genkey -name secp384r1 | openssl ec -aes256 -out ca.key 其中 -name 参数指定使用的曲线，曲线名称可通过以下命令查看：
openssl ecparam -list_curves RSA：
openssl genrsa -out ca.key 4096 若需要加密私钥：
openssl genrsa -des3 -out ca.key 4096 生成根证书 使用上面的私钥生成一个证书，证书会包含一些组织信息和公钥。为了一劳永逸有效期自然越长越好，本例设置为 73000 天（20 年）。
如果是 RSA，可以使用 -sha256 签名。
openssl req -key ca.key -new -x509 -days 73000 -sha384 -subj &amp;#34;/C=CN/ST=Guangdong Province/L=Shenzhen/O=Shenzhen XXX Co.</description></item><item><title>获取 TCP 发送缓冲区信息</title><link>https://blog.xhat.org/posts/tcp-send-buffer/</link><pubDate>Thu, 04 May 2023 16:37:47 +0800</pubDate><guid>https://blog.xhat.org/posts/tcp-send-buffer/</guid><description>在大多数的网络编程情况下，是不需要特意关心 TCP 的缓冲区信息的。但在一些工业应用场景，如 RS485 转网口的数据采集，半双工的 485 不能同时进行读和写，这就要求 TCP 确认发送完一个指令后，才能发第二条。因为是总线网络，同时发送多条指令，对端回复数据将出现错乱。
当应用程序往套接字写入数据时，实际上只是写入了内核的发送缓冲区，接收方什么时候能收到报文是个未知数。
因此在某些需要同步状态的地方，发送方最好能确认对方收到报文后再做下一步动作。
Linux Linux 提供了 ioctl(fd, SIOCOUTQ, &amp;amp;count) 方法来查询一个套接字是否有未发送完成的数据。
SIOCOUTQ Returns the amount of unsent data in the socket send queue. The socket must not be in LISTEN state, otherwise an error (EINVAL) is returned. SIOCOUTQ is defined in &amp;lt;linux/sockios.h&amp;gt;. Alternatively, you can use the synonymous TIOCOUTQ, defined in &amp;lt;sys/ioctl.h&amp;gt;.
发送方可以使用这个方法来判断对端是否收到报文。以 Go 为例：
import ( &amp;#34;net&amp;#34; &amp;#34;golang.org/x/sys/unix&amp;#34; &amp;#34;unsafe&amp;#34; ) func getSendQueueLength(conn *net.</description></item><item><title>为 NGINX 签发 HTTPS 证书</title><link>https://blog.xhat.org/posts/issue-nginx-cert/</link><pubDate>Mon, 05 Dec 2022 00:19:04 +0800</pubDate><guid>https://blog.xhat.org/posts/issue-nginx-cert/</guid><description>目前有很多 CA 可以免费签发 3 个月的 HTTPS 证书，如 Let&amp;rsquo;s Encrypt，ZeroSSL 等。推荐使用 acme.sh 脚本来管理证书，可以简化签发流程，证书到期可以自动续签。
安装 curl https://get.acme.sh | sh Let&amp;rsquo;s Encrypt 域名验证方式有很多种，以阿里云的 DNS 认证为例：
export Ali_Key=&amp;#34;&amp;#34; export Ali_Secret=&amp;#34;&amp;#34; 签发指定域名证书：
/root/.acme.sh/acme.sh --server letsencrypt --issue --dns dns_ali -d a.example.com 成功后会输出证书保存目录，而且脚本在证书到期前会自动续签证书。
安装证书到指定目录：
/root/.acme.sh/acme.sh --install-cert -d a.example.com --fullchain-file /etc/a.example.com.cer --key-file /etc/a.example.com.key --reloadcmd &amp;#34;systemctl restart nginx&amp;#34; 当证书续签后，上面的安装命令也会再次执行。
Nginx 配置 server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/a.example.com.cer; ssl_certificate_key /etc/a.example.com.key; ssl_protocols TLSv1.3 TLSv1.2; server_name a.</description></item><item><title>ECC 椭圆曲线</title><link>https://blog.xhat.org/posts/elliptic-curve/</link><pubDate>Mon, 26 Sep 2022 09:18:01 +0800</pubDate><guid>https://blog.xhat.org/posts/elliptic-curve/</guid><description>椭圆曲线密码学（Elliptic Curve Cryptography, ECC）是一种基于椭圆曲线数学的非对称式密码学算法。
ECC 的主要优势是它相比 RSA 加密算法使用较小的密钥长度并提供相当等级的安全性。
如今，在现代计算机网络技术中，比如 TLS、PGP 和 SSH，都有用到椭圆曲线加密算法。更不要说去中心化系统，如比特币和其它加密电子货币了。
椭圆曲线 椭圆曲线是由这个方程描述的平面曲线：
$$ y^2 = x^3 + ax + b $$
其中 $a$, $b$ 都是实数。上述方程就是所谓的魏尔斯特拉斯一般形式。
为排除退化成奇异曲线的情况，还需要满足 $4a^3 + 27b^2 \ne 0$。
随着 $a$ 和 $b$ 取值的变化，椭圆曲线可能在平面上会呈现不同的性状。不论是直观还是证明，我们都可以发现椭圆曲线是关于 $x$ 轴对称的。
群 在数学中，群（Group）是由一个集合以及一个二元运算符所组成的代数结构，且符合以下四个性质：
封闭性：对于所有 $G$ 中的 $a$, $b$，运算 $a \cdot b$ 的结果也在 $G$ 中。
结合律：对于所有 $G$ 中的 $a$, $b$, $c$，等式 $(a \cdot b) \cdot c = a \cdot (b \cdot c)$ 成立。</description></item><item><title>理解 RNN</title><link>https://blog.xhat.org/posts/understanding-rnn/</link><pubDate>Thu, 21 Apr 2022 11:38:04 +0800</pubDate><guid>https://blog.xhat.org/posts/understanding-rnn/</guid><description>循环神经网络 (Recurrent Neural Network, RNN) 是一种用于处理时间序列数据的神经网络结构。包括文字、语音、视频等对象。这些数据有两个主要特点：
数据无固定长度 数据是有时序的，相邻数据之间存在相关性，非相互独立 考虑这样一个问题，如果要预测句子下一个单词是什么，一般需要用到当前单词以及前面的单词，因为句子中前后单词并不是独立的。比如，当前单词是“很”，前一个单词是“天空”，那么下一个单词很大概率是“蓝”。循环神经网络就像人一样拥有记忆的能力，它的输出依赖于当前的输入和记忆，刻画出一个序列当前的输出与之前信息的关系。
循环神经网络适用于许多序列问题中，例如文本处理、语音识别以及机器翻译等。
基本结构 如果把上面有 W 的那个带箭头的圈去掉，它就变成了普通的全连接神经网络。图中每个圆圈可以看作是一个单元，而且每个单元做的事情也是一样的，因此可以折叠呈左半图的样子。用一句话解释 RNN，就是一个单元结构重复使用。
简单理清一下各符号的定义：
$x_t$ 表示 t 时刻的输入 $y_t$ 表示 t 时刻的输出 $s_t$ 表示 t 时刻的记忆，即隐藏层的输出 U 是输入层到隐藏层之间的权重矩阵 W 是记忆单元到隐藏层之间的权重矩阵 V 是隐藏层到输出层之间的权重矩阵 U, W, V 都是权重矩阵，在不同时刻 t 之间是共享权重的 从右半图可以看到，RNN 每个时刻隐藏层输出都会传递给下一时刻，因此每个时刻的网络都会保留一定的来自之前时刻的历史信息，并结合当前时刻的网络状态一并再传给下一时刻。
比如在文本预测中，文本序列为 &amp;ldquo;machine&amp;rdquo;，则输入序列和标签序列分别为 &amp;ldquo;machin&amp;rdquo; 和 &amp;ldquo;achine&amp;rdquo;，网络的概览图如下： 前向计算 在一个循环神经网络中，假设隐藏层只有一层。在 t 时刻神经网络接收到一个输入 $x_t$，则隐藏层的输出 $s_t$ 为： $$ s_t = \tanh(Ux_t + Ws_{t-1} + b_s) $$
在神经网络刚开始训练时，记忆单元中没有上一时刻的网络状态，这时候 $s_{t-1}$ 就是一个初始值。
在得到隐藏层的输出后，神经网络的输出 $y_t$ 为： $$ y_t = \mathrm{softmax}(Vs_t + b_y) $$</description></item><item><title>使用 MQTT 实现 API 接口</title><link>https://blog.xhat.org/posts/mqtt-create-api/</link><pubDate>Tue, 15 Mar 2022 09:28:08 +0800</pubDate><guid>https://blog.xhat.org/posts/mqtt-create-api/</guid><description>MQTT (Message Queuing Telemetry Transport Protocol) 消息队列遥测传输协议，是一种轻量级的发布/订阅模式的消息传输协议，运行在 TCP 协议栈之上，为其提供有序、可靠、双向连接的网络连接保证。
MQTT最大优点在于，可以以极少的代码和有限的带宽，为连接远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议，使其在物联网、小型设备、移动应用等方面有较广泛的应用。
最近项目上需要用到 MQTT 采集设备数据，然后项目中的某个应用又需要向外提供接口，项目中的其他应用都需要用到 MQTT，因此想到利用 MQTT 完成多个应用之间的通讯。
API 接口一般是请求/响应模型，MQTT v5 也开始支持请求响应的模式了，具体的流程如下：
请求方在发布消息时包含 响应主题(Response Topic) 属性，比如使用客户端标识符 (Client ID)。 请求方在发布消息时包含 对比数据(Correlation Data) 属性，比如使用当前时间戳。请求可以是异步的，如果同时发送多个请求，那请求方需要一个字段来区分响应消息属于哪个请求。 响应方收到消息后，进行业务处理，处理完成后向该消息的 响应主题 属性指定的主题发布响应消息，同时该响应消息的 对比数据 属性与请求消息的一致。 请求方收到响应消息后，根据 对比数据 属性把消息转发给对应的请求。 实现 本文使用 github.com/eclipse/paho.golang 这个包举例。
服务端 服务端的工作和 Web 框架类似，监听多个 Topic，为每个 Topic 指定处理函数。当一个请求到来时，创建新的协程来单独处理业务。
type Engine struct { Subscriptions map[string]paho.SubscribeOptions router *paho.StandardRouter cm *autopaho.ConnectionManager } func New() *Engine { return &amp;amp;Engine{ router: paho.NewStandardRouter(), Subscriptions: make(map[string]paho.SubscribeOptions), } } func (engine *Engine) Route(topic string, handler func(string, []byte) []byte) { engine.</description></item><item><title>给 exe 添加文件信息</title><link>https://blog.xhat.org/posts/file-info-exe/</link><pubDate>Tue, 08 Feb 2022 15:36:31 +0800</pubDate><guid>https://blog.xhat.org/posts/file-info-exe/</guid><description>创建清单文件 文件名为manifest.xml。如果不需要管理器权限，就把trustInfo删掉。
&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34; standalone=&amp;#34;yes&amp;#34;?&amp;gt; &amp;lt;assembly xmlns=&amp;#34;urn:schemas-microsoft-com:asm.v1&amp;#34; manifestVersion=&amp;#34;1.0&amp;#34;&amp;gt; &amp;lt;assemblyIdentity version=&amp;#34;1.0.0.0&amp;#34; processorArchitecture=&amp;#34;*&amp;#34; name=&amp;#34;app&amp;#34; type=&amp;#34;win32&amp;#34;/&amp;gt; &amp;lt;trustInfo xmlns=&amp;#34;urn:schemas-microsoft-com:asm.v2&amp;#34;&amp;gt; &amp;lt;security&amp;gt; &amp;lt;requestedPrivileges xmlns=&amp;#34;urn:schemas-microsoft-com:asm.v3&amp;#34;&amp;gt; &amp;lt;requestedExecutionLevel level=&amp;#34;requireAdministrator&amp;#34; uiAccess=&amp;#34;false&amp;#34; /&amp;gt; &amp;lt;/requestedPrivileges&amp;gt; &amp;lt;/security&amp;gt; &amp;lt;/trustInfo&amp;gt; &amp;lt;dependency&amp;gt; &amp;lt;dependentAssembly&amp;gt; &amp;lt;assemblyIdentity type=&amp;#34;win32&amp;#34; name=&amp;#34;Microsoft.Windows.Common-Controls&amp;#34; version=&amp;#34;6.0.0.0&amp;#34; processorArchitecture=&amp;#34;*&amp;#34; publicKeyToken=&amp;#34;6595b64144ccf1df&amp;#34; language=&amp;#34;*&amp;#34;/&amp;gt; &amp;lt;/dependentAssembly&amp;gt; &amp;lt;/dependency&amp;gt; &amp;lt;application xmlns=&amp;#34;urn:schemas-microsoft-com:asm.v3&amp;#34;&amp;gt; &amp;lt;windowsSettings&amp;gt; &amp;lt;dpiAwareness xmlns=&amp;#34;http://schemas.microsoft.com/SMI/2016/WindowsSettings&amp;#34;&amp;gt;PerMonitorV2, PerMonitor&amp;lt;/dpiAwareness&amp;gt; &amp;lt;dpiAware xmlns=&amp;#34;http://schemas.microsoft.com/SMI/2005/WindowsSettings&amp;#34;&amp;gt;True&amp;lt;/dpiAware&amp;gt; &amp;lt;/windowsSettings&amp;gt; &amp;lt;/application&amp;gt; &amp;lt;/assembly&amp;gt; 创建资源文件 文件名为resources.rc，如果没有清单文件，可将对应的行删掉，图标文件类似。
#include &amp;lt;windows.h&amp;gt; #pragma code_page(65001) // UTF-8 #define STRINGIZE(x) #x #define EXPAND(x) STRINGIZE(x) LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST manifest.xml 10 ICON EXPAND(APP_ICO) VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_ARRAY PRODUCTVERSION VERSION_ARRAY FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0x0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK &amp;#34;StringFileInfo&amp;#34; BEGIN BLOCK &amp;#34;080404B0&amp;#34; BEGIN VALUE &amp;#34;CompanyName&amp;#34;, &amp;#34;Your Company&amp;#34; VALUE &amp;#34;FileDescription&amp;#34;, &amp;#34;Example&amp;#34; VALUE &amp;#34;FileVersion&amp;#34;, EXPAND(VERSION_STR) VALUE &amp;#34;InternalName&amp;#34;, &amp;#34;Example&amp;#34; VALUE &amp;#34;LegalCopyright&amp;#34;, &amp;#34;© example&amp;#34; VALUE &amp;#34;OriginalFilename&amp;#34;, &amp;#34;example.</description></item><item><title>Git 备忘</title><link>https://blog.xhat.org/posts/git-remind/</link><pubDate>Sun, 16 Jan 2022 15:22:17 +0800</pubDate><guid>https://blog.xhat.org/posts/git-remind/</guid><description>设置用户信息 git config --global --list # 用户 git config --global user.name &amp;#34;your-name&amp;#34; git config --global user.email user@example.com # GPG 签名 git config --global user.signingkey XXXXXX 克隆仓库 git clone https://github.com/xxx/x.git 有子模块的：
git clone --recursive https://github.com/xxx/x.git 标签 删除本地标签 git tag --delete tagname 删除远程标签 git push --delete origin tagname</description></item><item><title>Linux 部署 Nginx</title><link>https://blog.xhat.org/posts/linux-nginx-deploy/</link><pubDate>Tue, 14 Dec 2021 00:09:32 +0800</pubDate><guid>https://blog.xhat.org/posts/linux-nginx-deploy/</guid><description>安装 参考官网的安装文档。
静态网站 # 强制跳转HTTPS server { listen 80; server_name example.com; return 301 https://$http_host$request_uri; } server { listen 443 ssl http2; ssl_certificate /etc/example.com.crt; ssl_certificate_key /etc/example.com.key; ssl_protocols TLSv1.3 TLSv1.2; server_name example.com; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/app/html; index index.html index.htm; } #error_page 404 /404.html; error_page 497 https://$http_host$request_uri; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } 代理网站 server{ listen 8888 ssl http2; listen [::]:8888 ssl http2; ssl_certificate /etc/example.</description></item><item><title>Golang 程序以 Windows 服务运行</title><link>https://blog.xhat.org/posts/golang-windows-service/</link><pubDate>Fri, 12 Nov 2021 13:15:06 +0800</pubDate><guid>https://blog.xhat.org/posts/golang-windows-service/</guid><description>Windows 服务是运行后台程序的一个很好的选择，可以支持开机自动启动，程序异常退出后自动重启这些实用功能。
Windows 服务程序有一套自己的机制。如果你不想在你的程序添加任何代码的话，有一些工具可以直接把可执行程序作为 Windows 服务运行，比如 winsw。
本文介绍的是在 Go 中制作自己的服务程序，主要使用的是 golang.org/x/sys/windows/svc 这个包。正如文档所说，实现Handler接口即可，当服务启动时，会调用Execute方法。
type demoService struct { } func (service *demoService) Execute(args []string, r &amp;lt;-chan svc.ChangeRequest, changes chan&amp;lt;- svc.Status) (svcSpecificEC bool, exitCode uint32) { changes &amp;lt;- svc.Status{State: svc.StartPending} defer func() { changes &amp;lt;- svc.Status{State: svc.StopPending} log.Println(&amp;#34;Shutting down&amp;#34;) }() // 要执行的主程序代码 go yourMainFunc() changes &amp;lt;- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown} log.Println(&amp;#34;Startup complete&amp;#34;) for { select { case c := &amp;lt;-r: switch c.</description></item><item><title>Golang 在 Windows 下防止程序多开</title><link>https://blog.xhat.org/posts/golang-gui-singleton/</link><pubDate>Mon, 11 Oct 2021 11:02:41 +0800</pubDate><guid>https://blog.xhat.org/posts/golang-gui-singleton/</guid><description>当用户运行多个程序实例，如果操作的是同一资源，可能会造成数据不一致。所以有一个防止多开的需求，原理上是利用 CreateMutex 这个函数创建互斥对象。
func checkSingleton() (windows.Handle, error) { path, err := os.Executable() if err != nil { return 0, err } hashName := md5.Sum([]byte(path)) name, err := syscall.UTF16PtrFromString(&amp;#34;Local\\&amp;#34; + hex.EncodeToString(hashName[:])) if err != nil { return 0, err } return windows.CreateMutex(nil, false, name) } 检查error，如果是syscall.ERROR_ALREADY_EXISTS，则说明有一个程序已经在运行。
上面创建的互斥对象是局部的(有Local前缀)，多个用户登录还是可以同时多开程序的。如果需要全局限制，则替换为Global前缀。如果你的程序以服务的形式运行，则可能需要设置互斥对象的权限。
func checkSingleton() (windows.Handle, error) { path, err := os.Executable() if err != nil { panic(err) } hashName := md5.Sum([]byte(path)) name, err := syscall.UTF16PtrFromString(&amp;#34;Global\\&amp;#34; + hex.</description></item><item><title>Linux 部署 WireGuard</title><link>https://blog.xhat.org/posts/linux-wireguard/</link><pubDate>Fri, 03 Sep 2021 14:33:27 +0800</pubDate><guid>https://blog.xhat.org/posts/linux-wireguard/</guid><description>安装 CentOS sudo yum install epel-release elrepo-release sudo yum install yum-plugin-elrepo sudo yum install kmod-wireguard wireguard-tools Ubuntu sudo apt install wireguard 若内核太老不想升级，可以使用 wireguard-go 代替。
配置 创建 Wireguard 目录： mkdir /etc/wireguard/ cd /etc/wireguard/ 生成密钥对 wg genkey | tee privatekey | wg pubkey &amp;gt; publickey 编辑配置文件 vi wg0.conf 内容模板：
[Interface] Address = 10.100.100.3/32 PrivateKey = KEY ListenPort = 21841 PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] PublicKey = PUB Endpoint = IP AllowedIPs = 10.</description></item><item><title>Golang 打开 Windows 服务属性窗口</title><link>https://blog.xhat.org/posts/golang-service-property/</link><pubDate>Sun, 01 Aug 2021 11:35:17 +0800</pubDate><guid>https://blog.xhat.org/posts/golang-service-property/</guid><description>本文介绍如何在 Golang 程序里面打开某个 Windows 服务的属性窗口，这里需要用到 COM 接口，详细文档请参考 MMC 2.0 的官方文档。
既然是 COM 的话，程序里也可以使用cmd或者powershell来调用 COM 打开服务窗口。下面介绍直接调用 COM 组件的方法：
使用 github.com/go-ole/go-ole 这个库调用 COM：
import ( &amp;#34;github.com/go-ole/go-ole&amp;#34; &amp;#34;github.com/go-ole/go-ole/oleutil&amp;#34; &amp;#34;time&amp;#34; ) // 服务的显示名称 displayName := &amp;#34;Windows Update&amp;#34; ole.CoInitialize(0) unknown, _ := oleutil.CreateObject(&amp;#34;MMC20.Application&amp;#34;) mmc, _ = unknown.QueryInterface(ole.IID_IDispatch) // 读取服务 oleutil.MustCallMethod(mmc, &amp;#34;Load&amp;#34;, &amp;#34;services.msc&amp;#34;) document := oleutil.MustGetProperty(mmc, &amp;#34;Document&amp;#34;).ToIDispatch() view := oleutil.MustGetProperty(document, &amp;#34;ActiveView&amp;#34;).ToIDispatch() list := oleutil.MustGetProperty(view, &amp;#34;ListItems&amp;#34;).ToIDispatch() count := int(oleutil.MustGetProperty(list, &amp;#34;Count&amp;#34;).Val) // 注意索引从1开始 for i := 1; i &amp;lt;= count; i++ { item := oleutil.</description></item><item><title>Windows 创建临时文件</title><link>https://blog.xhat.org/posts/windows-createfile-tempfile/</link><pubDate>Mon, 19 Jul 2021 09:36:38 +0800</pubDate><guid>https://blog.xhat.org/posts/windows-createfile-tempfile/</guid><description>在 Windows 上希望创建一个临时文件，该文件在程序退出时自动删除，即使是被强制停止的。这时需要使用 CreateFile 这个函数：
HANDLE CreateFileA( [in] LPCSTR lpFileName, // 指向文件名的指针 [in] DWORD dwDesiredAccess, // 访问模式，写/读 [in] DWORD dwShareMode, // 共享模式 [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性的指针 [in] DWORD dwCreationDisposition, // 如何创建 [in] DWORD dwFlagsAndAttributes, // 文件属性 [in, optional] HANDLE hTemplateFile // 用于复制文件句柄 ); 重点关注dwShareMode和dwFlagsAndAttributes这两个参数。
共享模式dwShareMode有四种选项，分别为
0：禁止其他进程进行删除、读取和写入 FILE_SHARE_DELETE：允许删除 FILE_SHARE_READ：允许读取 FILE_SHARE_WRITE：允许写入 文件属性dwFlagsAndAttributes需要设定两项：
FILE_ATTRIBUTE_TEMPORARY：该文件为临时文件，尽可能使用内存缓存，避免写入磁盘。 FILE_FLAG_DELETE_ON_CLOSE：当所有句柄被关闭时，立刻删除文件。 实验：
h, _ := windows.CreateFile( windows.StringToUTF16Ptr(&amp;#34;tmp&amp;#34;), windows.GENERIC_WRITE, windows.FILE_SHARE_READ, nil, windows.OPEN_ALWAYS, windows.FILE_ATTRIBUTE_TEMPORARY|windows.FILE_FLAG_DELETE_ON_CLOSE, 0, ) var done uint32 windows.</description></item><item><title>Python 进行 ARP 欺骗</title><link>https://blog.xhat.org/posts/python-arpspoof/</link><pubDate>Wed, 09 Jun 2021 18:27:39 +0800</pubDate><guid>https://blog.xhat.org/posts/python-arpspoof/</guid><description>声明：本文所用的脚本仅限于学习测试目的，在使用中造成的一切后果与作者无关，后果自负。
ARP (Address Resolution Protocol) 即地址解析协议，是一种将 IP 地址转化成物理地址的协议。我们常用的以太网是通过 MAC 地址进行通信的，所以在网络链路上传送数据帧时，最终是使用硬件地址的。
一个典型的 ARP 流程如下表所示，这里为了叙述方便，硬件地址做了简化处理。
源地址 目的地址 内容 12:34:56 ff:ff:ff Who has 192.168.1.2? Tell 192.168.1.3 78:ab:cd 12:34:56 192.168.1.2 is at 78:ab:cd 大致流程就是12:34:56发送一个广播，问谁有某个 IP 地址，当对方收到这个广播时，如果自己的 IP 和广播里问的 IP 是一致的，就发送一个回复给提问者。这样提问者就建立了 IP 地址和物理地址的对应关系。
那如果对方不守信呢，明明自己没有这个 IP，还是坚持回复这个 IP 是自己，欺骗了提问者。这时提问者就会把数据包发给其他人，相当于数据包被人偷了！
没错，ARP 欺骗就是这个原理，可以用来做中间人攻击和拒绝服务攻击。下面分别实验一下两种情况。
网关 IP：10.1.45.254
受害者 IP：10.1.45.2
中间人攻击 欺骗受害者网关在我们这里，受害者就会把数据包发给我们，我们再代为转发给真正的网关，相当于做了一个中间人，这时我们可以捕获到受害者的通信数据包。
# arpspoof.py import sys from scapy.layers.l2 import Ether, ARP, sendp from scapy.layers.l2 import getmacbyip if __name__ == &amp;#39;__main__&amp;#39;: if len(sys.</description></item><item><title>Golang 中使用 JWT 进行认证</title><link>https://blog.xhat.org/posts/golang-jwt/</link><pubDate>Mon, 10 May 2021 13:19:47 +0800</pubDate><guid>https://blog.xhat.org/posts/golang-jwt/</guid><description>JSON Web Token (JWT) 是一种目前流行的跨域认证方案，JWT 是基于 JSON 的经过签名的 Token，可以在进行验证的同时附带身份信息，保证传输的信息没有被修改，对于前后端分离项目很有帮助。
JSON Web Token (JWT) 是一个开放标准 (RFC 7519)，它定义了一种紧凑的、自包含的方式，用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信任，因为它是数字签名的。
原理 JWT 的认证流程是，用户登录成功后，服务端生成一个 JWT 格式的 Token，发回给用户，这个 Token 包含了用于标记用户的信息，此后用户与服务端通信时，都携带这个 Token，服务端就能靠这个 Token 确定用户的身份。
如上面提到，这个 Token 是有签名的，所以可以保证数据不被篡改，是值得信任的。
JWT 由三部分组成，它们之间用圆点(.)相连。分别为：
Header（头部） Payload（负载） Signature（签名） 最后生成的字符串大概就是这样子的：
xxx.yyy.zzz 下面简单说一下这三个部分。
Header 头部主要用来描述一些元数据。
{ &amp;#34;alg&amp;#34;: &amp;#34;HS256&amp;#34;, &amp;#34;typ&amp;#34;: &amp;#34;JWT&amp;#34; } 主要就包含这两个字段，alg是所使用的签名算法，服务端会使用该算法签名或验证 Token，typ就是类型了，固定为JWT。
最后使用 Base64URL 算法把这个 JSON 对象转换为字符串。
可以看到这部分是没有加密的，所以不要放置敏感信息。
Payload 负载部分用来存放实际传递的数据，也就是关于用户的数据，JWT 官方提供了七个预定义的字段：
{ &amp;#34;iss&amp;#34;: &amp;#34;签发人&amp;#34;, &amp;#34;exp&amp;#34;: &amp;#34;过期时间&amp;#34;, &amp;#34;sub&amp;#34;: &amp;#34;主题&amp;#34;, &amp;#34;aud&amp;#34;: &amp;#34;受众&amp;#34;, &amp;#34;nbf&amp;#34;: &amp;#34;生效时间&amp;#34;, &amp;#34;iat&amp;#34;: &amp;#34;签发时间&amp;#34;, &amp;#34;jti&amp;#34;: &amp;#34;编号&amp;#34; } 除此之外，我们可以自己定义需要的字段：</description></item><item><title>Python 发送 Email 通知</title><link>https://blog.xhat.org/posts/python-send-email/</link><pubDate>Tue, 20 Apr 2021 01:36:21 +0800</pubDate><guid>https://blog.xhat.org/posts/python-send-email/</guid><description>感觉没什么好说的，代码看一眼就明了，当备忘吧。
import smtplib from email.header import Header from email.mime.text import MIMEText from email.utils import formataddr def send_email(subject, text, receiver): message = MIMEText(text, &amp;#39;plain&amp;#39;, &amp;#39;utf-8&amp;#39;) message[&amp;#39;From&amp;#39;] = formataddr((&amp;#34;发送人名字&amp;#34;, &amp;#39;发送人账号&amp;#39;)) message[&amp;#39;To&amp;#39;] = formataddr((&amp;#34;&amp;#34;, receiver)) message[&amp;#39;Subject&amp;#39;] = Header(subject, &amp;#39;utf-8&amp;#39;) smtp = smtplib.SMTP_SSL(&amp;#34;SMTP 服务器&amp;#34;, 465) smtp.login(&amp;#34;发送人账号&amp;#34;, &amp;#34;客户端密码&amp;#34;) smtp.sendmail(&amp;#39;发送人账号&amp;#39;, receiver, message.as_string()) smtp.quit()</description></item><item><title>Golang 使用 Casbin 进行权限管理</title><link>https://blog.xhat.org/posts/golang-casbin/</link><pubDate>Thu, 04 Mar 2021 01:18:53 +0800</pubDate><guid>https://blog.xhat.org/posts/golang-casbin/</guid><description>先说需求，设计一个基于角色的权限控制系统，满足以下几个规则：
单独配置某个角色对某个资源的访问权限 一个用户可拥有多个角色 可对角色进行禁用或启用 各个角色之间的权限为并集，且只要有一个角色有权限，该用户就有权限操作 可对一个菜单下的某些重要功能做单独控制，当用户有该菜单的访问权限，没有功能访问权限时，依然能访问该菜单下的非功能接口 Casbin 是一个强大的、高效的开源访问控制框架，其权限管理机制支持多种访问控制模型。
具体支持的模型官网有详细描述，回到本例应该使用的模型是RBAC (基于角色的访问控制)。
Casbin使用配置文件来设置访问控制模式。它有两个配置文件，model.conf和policy.csv。 其中，model.conf存储了访问模型，policy.csv存储了特定的用户权限配置。
模型 Casbin 将访问控制模型抽象为基于PERM(Policy, Effect, Request, Matcher)的一个文件，分别为：
策略 效果 请求 匹配器 基于角色的访问控制需要在此基础上加多一个role_definition进行角色的定义。
请求(request_definition) 该部分用于请求的定义，经典的三元组：访问实体 (Subject)，访问资源 (Object) 和访问方法 (Action)，也可以根据自己的需求进行增加或删除字段。后端常用的控制请求就是uid, /api/res1, GET。
[request_definition] r = sub, obj, act 策略(policy_definition) 该部分定义控制策略的模板，哪个实体对哪个资源有怎样的权限。注意：这里的sub, obj不一定需要与请求里面的值一致，具体怎样匹配是匹配器定义的。例如这里的一条策略可以是alice, res1, allow。
[policy_definition] p = sub, obj, eft 角色定义(role_definition) 该部分定义了角色系统，用户可以具有角色及其继承关系, 资源也可以具有角色及其继承关系。 这两个 RBAC 系统不会互相干扰。这里我使用了三个角色系统：g是用户和角色的从属关系；g2是资源的从属关系；g3是角色的开关。
[role_definition] g = _, _ g2 = _, _, _ g3 = _, _ 举个例子，g可以是user_1, 1，表示uid是 1 的用户拥有角色 1。g2可以理解为将多个接口组成一个资源组，角色拥有该资源组的权限则有这些接口的访问权限。</description></item><item><title>OpenWrt + Pon Stick 配置教程</title><link>https://blog.xhat.org/posts/openwrt-pon-stick/</link><pubDate>Sat, 06 Feb 2021 14:00:28 +0800</pubDate><guid>https://blog.xhat.org/posts/openwrt-pon-stick/</guid><description>0x1 配置访问模块 首先确定模块插在哪个接口，本例中模块接在eth1上。确定模块IP，本例为192.168.1.1。下面配置一个接口，使内网的机器能直接访问模块。
若OpenWrt的地址也是192.168.1.1，需要修改地址： 在网络-&amp;gt;接口页面，编辑LAN接口，把IP地址改为172.20.0.1(其他网段亦可)。
新建一个接口，名字为PON，协议为静态IP，接口为eth1。 配置IP地址为192.168.1.2，子网掩码为255.255.255.252.
在防火墙设置选项卡里选择分配给wan，
后续就可以访问模块地址进行配置，请参考模块配置教程。
0x2 拨号 这部分已经假定模块已经配置完成，并完成光路认证。还需要确定VLAN ID，一般在光猫的后台可以看到：
在上网的连接名称可以看到后面的VID_41，41就是上网的VLAN ID。
回到OpenWrt页面，编辑WAN接口(没有的新建一个)，协议选择PPPoE，用户名密码照常输入，防火墙分配给wan. 要注意的是在物理设置选择接口那里，下拉到最后，在自定义输入框里输入eth1.41, eth1是模块所在的接口，41是上面的上网VLAN ID。
后续应该就可以正常拨号上网了。</description></item><item><title>OpenWrt 网关抓包</title><link>https://blog.xhat.org/posts/openwrt-trafficdump/</link><pubDate>Fri, 08 Jan 2021 11:26:10 +0800</pubDate><guid>https://blog.xhat.org/posts/openwrt-trafficdump/</guid><description>把 WireShark 添加到环境变量 OpenWrt 安装 tcpdump 执行命令:
ssh root@openwrt tcpdump -s 0 -U -n -w - -i eth1 not port 22 | wireshark -k -i - 注意将eth1替换为你实际需要捕获的接口。</description></item><item><title>加权最小二乘</title><link>https://blog.xhat.org/posts/introduce-to-weighted-least-squares/</link><pubDate>Mon, 30 Nov 2020 13:17:00 +0800</pubDate><guid>https://blog.xhat.org/posts/introduce-to-weighted-least-squares/</guid><description>介绍 多元线性回归模型的关系式为：
$$ y_i= \beta_0+\beta_1 x_{i1}+\beta_2 x_{i2} + \dots + \beta_p x_{ip} + \epsilon_i $$ 假设随机误差项 $\epsilon_i(i=1,\dots,n)$满足
$$ E(\epsilon_i) = 0,\quad \text{Cov}(\epsilon_i,\epsilon_j)=\begin{cases} \sigma^2, &amp; i=j, \\ 0, &amp; i \ne j. \end{cases} $$ 上式通常称为高斯-马尔可夫条件。随机误差$\epsilon_i$的协方差为零表明随机误差项在不同的样本点之间是不相关的(在正态条件下即为独立)。随机误差项$\epsilon_i$在不同的样本点有相同的方差表明各次观测之间有相同的精度。
多元线性回归模型改写成矩阵形式如下：
$$ Y=X\mathbf{\beta}+\epsilon,\quad \epsilon\sim\mathbf{N}(0,\sigma^2I_n) $$ 最小二乘估计 最小二乘估计(LSE)就是找$\beta_0,\beta_1,\dots,\beta_p$ ，使离差平方和
$$ Q(\beta_0,\beta_1,\dots,\beta_p)=\sum_{i=1}^n(y_i-\beta_0-\beta_1x_{i1}-\dots-\beta_px_{ip})^2 $$ 达到最小，写成矩阵形式如下：
$$ Q(\beta)= (Y-X\beta)^T(Y-X\beta) $$ 上式中每个平方项的权数相同，是普通最小二乘回归参数估计方法。在误差项$\epsilon_i$等方差不相关的条件下，普通最小二乘估计是回归参数的最小方差线性无偏估计。
加权最小二乘 然而在异方差的条件下，平和和中的每一项的地位是不相同的。误差项$\epsilon_i$的方差$\sigma_i^2$大的项，在上式平方和中的取值就偏大，在平方和中的作用就大，因而普通最小二乘估计的回归线就被拉向方差大的项，方差大的项的拟合程度就好，而方差小的项拟合程度就差。由此求出的$\hat{\beta_0},\hat{\beta_1},\dots,\hat{\beta_p}$ 仍然是$\beta_0,\beta_1,\dots,\beta_p$ 的无偏估计，但不再是最小方差线性无偏估计。
加权最小二乘估计的方法是在平方和中加入一个适当的权数$w_i$，以调整各项在平方和中的作用，加权最小二乘的离差平方和为：
$$ Q_w(\beta_0,\beta_1,\dots,\beta_p)=\sum_{i=1}^nw_i(y_i-\beta_0-\beta_1x_{i1}-\dots-\beta_px_{ip})^2 $$ 类似地，目标也是寻找$\hat{\beta}$使上式的离差平方和$Q_w$达到最小。上式可以改写为：
$$ Q_w(\beta_0,\beta_1,\dots,\beta_p)=\sum_{i=1}^n(\sqrt{w_i}y_i-\sqrt{w_i}\beta_0-\sqrt{w_i}\beta_1x_{i1}-\dots-\sqrt{w_i}\beta_px_{ip})^2 $$ 展开为原始的模型式为：
$$ \sqrt{w_i}y_i= \sqrt{w_i}\beta_0+\sqrt{w_i}\beta_1 x_{i1}+\sqrt{w_i}\beta_2 x_{i2} + \dots + \sqrt{w_i}\beta_p x_{ip} + \sqrt{w_i}\epsilon_i $$ 令$\epsilon_i^*=\sqrt{w_i}\epsilon_i$ , 此时模型中随机误差项的方差为</description></item></channel></rss>