通过管理里的系统工具修改
选中桌面中的计算机图标,右键,点击管理
系统工具
本地用户和组
用户
选中Administrator,然后重命名
重启电脑
通过策略租修改
win+r 打开运行
输入 gpedit.msc 打开策略组
计算机配置
windows设置
安全设置
本地策略
安全选项
拉到最下面
双击这个选选项 重命名系统管理员帐户
重启电脑
通过 netplwiz (Network Places Wizard) 网上邻居向导 修改
win+r 打开运行
输入 netplwiz
选中Administrator,然后双击,然后修改
重启电脑
win+r 打开运行
输入 gpedit.msc 打开策略组
计算机配置
windows 设置
安全设置
本地策略
安全选项
拉到最下面
禁用 使用空密码的本地账户只允许控制台登录
电脑提示“账户名与安全标识间无任何映射完成” 一般是修改玩用户名后没有重启导致的。
因为公司的电脑不能设密码,同时我又想远程桌面公司的电脑,考虑到安全问题,不能用默认用户名裸奔,所以修改用户名和设置无密码的远程桌面
需要一个在 wall 以外的服务器
ss 的各个版本 https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions
python -m pip install shadowsocks
# 如果上面那句下载失败,可以尝试用这句安装
python -m pip install https://github.com/shadowsocks/shadowsocks/archive/master.zip -U
# 如果上面那句还是下载失败,可以尝试先把 master.zip 文件下载到本地,再安装
ssserver -p 61813 -k windows@163.qq -m aes-256-cfb
-p 是端口号
-k 是密码
-m 是加密方式
上面那条命令需要在 服务器的策略组 和 防火墙 放行 61813 端口
https://download.libsodium.org/libsodium/releases/
python -m pip install --upgrade shadowsocks
# 如果上面那句更新失败,可以尝试这样更新,先卸载再重新安装,卸载前记得先备份当前的版本
python -m pip show shadowsocks
python -m pip uninstall shadowsocks
python -m pip install https://github.com/shadowsocks/shadowsocks/archive/master.zip -U
https://github.com/shadowsocks/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
apt update
apt install shadowsocks-libev
ss-server -s 0.0.0.0 -p 61813 -k windows@163.qq -m aes-256-cfb
或者
ss-server -c config.json
{
"server": "0.0.0.0",
"server_port": 61813,
"password": "windows@163.qq",
"method": "aes-256-gcm"
}
对应的文档 https://github.com/shadowsocks/shadowsocks-libev/blob/master/doc/ss-server.asciidoc ss-local -s host -p 61813 -k windows@163.qq -m aes-256-cfb -l 1080
或者
ss-local -c config.json
{
"server": "host",
"server_port": 61813,
"local_address": "0.0.0.0",
"local_port": 1080,
"password": "windows@163.qq",
"timeout": 600,
"method": "aes-256-gcm"
}
对应的文档 https://github.com/shadowsocks/shadowsocks-libev/blob/master/doc/ss-local.asciidocVisual Studio 6.0 | VC6 |
Visual Studio .NET 2002 | VC7.0 |
Visual Studio .NET 2003 | VC7.1 |
Visual Studio 2005 | VC8 |
Visual Studio 2008 | VC9 |
Visual Studio 2010 | VC10 |
Visual Studio 2012 | VC11 |
Visual Studio 2013 | VC12 |
Visual Studio 2015 | VC14 |
Visual Studio 2017 | VC15 |
Visual Studio 2019 | VS16 |
Visual Studio 2022 | VS17 |
5.2 | vc6 |
5.3 | vc9 |
5.4 | vc9 |
5.5 | vc11 |
5.6 | vc11 |
7.0 | vc14 |
7.1 | vc14 |
7.2 | vc15 |
7.3 | vc15 |
7.4 | vc15 |
8.0 | vs16 |
8.1 | vs16 |
U盘 弹出失败的原因是进程占用了 U盘 ,只要占用 U盘 的进程都不在占用 U盘 或 都结束了, U盘 就可以安全地弹出了。
所以,让 U盘 安全地弹出的关键是找到占用 U盘 的进程。
当占用 U盘 的进程结束后,有时立即弹出 U盘 还是会失败的,这时再等待五六秒,再试一次弹出 U盘 就可以了。
可以安全退出 U盘 时也不要马上拔 U盘 ,最好等个五六秒再拔 U盘 。
这是各种方法的总结
笔者通常在直接弹出 U盘 失败后,会多试几次,然后通过 日志 找到对应的进程,然后通过 任务管理器 结束对应的进程,如果结束进程失败,还是会再次在网上搜索解决方法。 脱机 和 关闭写缓存都有一点副作用; 关闭文件夹,重启 explorer.exe ,注销,关机,这类都有点麻烦。
其实就三种套路
wsl1 和 wsl1 之前的 sfu/sua 是子系统, wsl2 其实算是虚拟机,其它的都是运行在 win32 上的兼容层。 nt 内核其实是有三个子系统 win32 ,os/2 和 posix ,只是除了 win32 其它两个都没有什么存在感。
所谓的 linux 环境,除了需要 bash 之外,还需要各种 linux 的工具,还需要处理管道,还需要处理文件名和路径的问题。 还有各种 linux api 的问题(但不写需要编译的代码,只使用环境中的工具,其实这个问题可以忽略的)。
http://www.ffmpeg.org/download.html
ffmpeg -i "缓存视频文件的文件名" "转换格式后的文件名"
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
选择,Windows 64 位
打开下载的 exe 文件,一路点 next 直到安装完毕
新建一个环境变量 JAVA_HOME ,值为 JDK 的安装目录,例子
C:\Program Files\Java\jdk1.8.0_161
把以下值加入到环境变量 Path
%JAVA_HOME%\bin
%JAVA_HOME%\jre\bin
%JAVA_HOME%\lib
https://tomcat.apache.org/download-90.cgi
选择,core,Windows 64 位
如果出现这种错误
无法启动此程序,因为计算机中丢失 libui.dll,尝试重新安装该程序以解决此问题。
这个提示出现说明你没有放入 libui 和 pthreadVC2 文件到 php 的根目录下
remote terminal <----> ssh server <----> shell <----> tmux client <----> tmux server <----> shell
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 另一种关闭文件描述符的方法,但 getdtablesize() 来自 unistd.h
// for(i = 0; i < getdtablesize(); i++)
// {
// close(i);
// }
vi deamon.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if (pid > 0) {
exit(0); // 1.父进程退出
} else if (pid == 0) {
// 2.变为会话组长,脱离了控制终端 setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离
setsid();
// 3.改变进程的工作目录
chdir("/var");
// 4. 重置文件掩码
umask(0);
// 5. 关闭文件描述符
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 6. 执行核心操作
// 每三秒一条记录到日志文件里,执行100次
int fd = open("/var/temp-deamon-log.txt", O_CREAT | O_WRONLY | O_APPEND, 0664);
int i;
for (i = 0; i < 100; i++) {
sleep(3);
time_t curtime;
time(&curtime);
char* pt = ctime(&curtime);
write(fd, pt, strlen(pt) + 1);
}
close(fd);
}
return EXIT_SUCCESS;
}
gcc deamon.c && \
./a.out && \
sleep 30 && \
cat -n /var/temp-deamon-log.txt && \
kill `ps -elf | grep a.out | awk '{print $4}'` && \
rm /var/temp-deamon-log.txt
>> out.log
把输出追加到 out.log
文件里2>&1
把 stderr 重定向到 stdoutnohup php queue.php >> out.log 2>&1 &
/etc/systemd/system
目录新建一个文件 myDaemon.service [Unit]
Description=myDaemon service
[Service]
# service 的类型
Type=simple
# 退出后马上重启
Restart=always
# 这里的 bash 路径和脚本路径都必须是绝对路径
ExecStart=/bin/bash /root/myDaemon.sh
[Install]
# 开机启动时的依赖项,大多数情况下都是填这个
WantedBy=multi-user.target
# 重新加载 systemctl 配置
systemctl daemon-reload
# 启动 myDaemon.service
systemctl start myDaemon.service
# myDaemon.service 加入到开机启动中
systemctl enable myDaemon.service
* * * * * php queue.php >> out.log 2>&1
编译的四个步骤
编译的四个步骤对应的 gcc 命令
gcc -E test.c -o test.i
gcc -S test.i -o test.s
gcc -c test.s -o test.o
gcc test.o -o test
实际上 gcc 这个命令只是这些后台程序的包装,它会根据不同的参数要求去调用预处理器cpp、预编译程序cc1、汇编器as、链接器ld
cpp test.c -o test.i
cc1 test.i -o test.s
as test.s -o test.o
ld test.o -o test
GNU 工具链
其它
# 没使用 pkg-config
gcc test.c -o test -I/usr/local/Cellar/opencv3/3.1.0_4/include/opencv -I/usr/local/Cellar/opencv3/3.1.0_4/include
# 使用了 pkg-config
gcc test.c -o test $(pkg-config opencv --cflags)
参考
感觉 GNU 真的除了内核之外,什么都有了。
用来测试网站对 ipv6 的支持,也可以用来查看 DNSSEC 的支持 https://ipv6.ustc.edu.cn/onlinechecklog.php
python 的 json.tool ,好像 python2 和 3 都可以这样用
echo '{ "name": "xiaohong", "age": 18 }' | python -m json.tool
json_pp , windwos 的 git bash 和 大多数 linux 发行版都有这个工具
echo '{ "name": "xiaohong", "age": 18 }' | json_pp
jq , 虽然大多数 linux 发行版都没有这个工具,但中文互联网环境下有好多文章都推荐这个
php 的命令行,标准输入中一定要有数据,不然会一直等待;同样地 python 或 node 也可以实现类似的
echo '{ "name": "xiaohong", "age": 18, "chinese character":"汉字" }' | \
php -r 'print(json_encode(json_decode(file_get_contents("php://stdin")),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));';
PowerShell 的 ConvertFrom-Json 和 ConvertTo-Json ,这两个要组合来使用
echo '{"type":"image","offset":0,"count":20}' | ConvertFrom-Json | ConvertTo-Json
配合 curl 使用
curl -s -k https://localhost/dev.json | json_pp
curl -s -k https://localhost/dev.json | python -m json.tool
配合 PowerShell 的 Invoke-WebRequest 使用
Invoke-WebRequest https://localhost/dev.json -UseBasicParsing -SkipCertificateCheck | Select -ExpandProperty Content | ConvertFrom-Json | ConvertTo-Json
Invoke-WebRequest https://localhost/dev.json -UseBasicParsing -SkipCertificateCheck | Select -ExpandProperty Content | python -m json.tool
如果 Invoke-WebRequest 出现了这种错误。
因为 Internet Explorer 引擎不可用,或者 Internet Explorer 的首次启动配置不完整
可以尝试以下步骤来解决
windows10 之前的系统在修改 path 时要注意分号 ;
在 JDK1.5 以后,classpath 并不是必须配置了,在 JDK1.5 之前,是没有办法在当前目录下加载类的(找不到 JDK 目录下 lib 文件夹中的 .jar 文件),所以我们需要通过配置 classpath ,但 JDK1.5 之后, JRE 能自动搜索目录下类文件,并且加载 dt.jar 和 tool.jar 的类。 dt.jar 是关于运行环境的类库,主要是用于 swing 的包,如果不使用可以不配置。 tools.jar 是工具类库。
编译和运行时可以通过参数 -classpath 指定 classpath 的路径,例如这样
javac -encoding UTF-8 -classpath .;./junit4.jar;./org.hamcrest.core_1.3.0.jar AaaTest.java JunitRunner.java
java -Dfile.encoding=UTF-8 -classpath .;./junit4.jar;./org.hamcrest.core_1.3.0.jar JunitRunner
通常是执行策略的原因导致的。
设置脚本执行策略,通常把 策略 设为 RemoteSigned 就可以了
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
查看 powershell 脚本执行策略
Get-ExecutionPolicy
Get-ExecutionPolicy -List
python 的 cgi 模块在 3.13 被移除了 https://docs.python.org/zh-tw/3.12/library/cgi.html https://peps.python.org/pep-0594/#cgi
python 一行命令启动 http 服务
# 最简单的 http 服务
python -m http.server
# 指定端口号的 http 服务
python -m http.server 8081
# 有 cgi 的 http 服务
python -m http.server --cgi
# 有 cgi 的和指定端口号的 http 服务
python -m http.server --cgi 8081
# 有 cgi 的,指定端口号的和指定ip地址的 http 服务
python -m http.server --cgi 8081 --bind 127.0.0.1
# 有 cgi 的,指定端口号的,指定ip地址的和指定站点根目录的 http 服务
python -m http.server --cgi 8081 --bind 127.0.0.1 --directory _book
请求 cgi 脚本的例子
curl 127.0.0.1:8000/cgi-bin/test.py
cgi 脚本的例子
#!/usr/bin/python3
print ("Content-type:text/html")
print () # 空行,告诉服务器结束头部
print ('<html>')
print ('<head>')
print ('<meta charset="utf-8">')
print ('<title>Hello Word</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word!</h2>')
print ('</body>')
print ('</html>')
#!/usr/bin/python3
print ("Content-type: application/json")
print () # 空行,告诉服务器结束头部
print ('{"result": "this is a test"}')
这个例子大致相当于这个命令 python -m http.server 8888
from http.server import HTTPServer, SimpleHTTPRequestHandler
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = HTTPServer(host, SimpleHTTPRequestHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
这个例子大致相当于这个命令 python -m http.server --cgi 8888
from http.server import HTTPServer, CGIHTTPRequestHandler
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = HTTPServer(host, CGIHTTPRequestHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
不使用命令行的 http 服务例子,这是单线程的
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'result': 'this is a test'}).encode())
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = HTTPServer(host, myHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
不使用命令行的 http 服务例子,这是多线程的
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import json
class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
pass
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({'result': 'this is a test'}).encode())
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = ThreadingHttpServer(host, myHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
不使用命令行的 http 服务例子,这是多线程的,再加上 cgi 的支持
from http.server import HTTPServer, CGIHTTPRequestHandler
from socketserver import ThreadingMixIn
class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
pass
if __name__ == '__main__':
host = ('0.0.0.0', 8888)
server = ThreadingHttpServer(host, CGIHTTPRequestHandler)
print('Serving HTTP on {host} port {port} (http://{host}:{port}/) ...'.format(host=host[0], port=host[1]))
server.serve_forever()
HTTPServer 和 BaseHTTPRequestHandler 是两个关键的类,一个用于接收 http 请求,一个用于处理请求,其它类基本是派生自这两个类
BaseHTTPRequestHandler -> SimpleHTTPRequestHandler -> CGIHTTPRequestHandler
HTTPServer -> ThreadingHttpServer
参考文档
./Lib/site-packages
参考这个文档 https://pip.pypa.io/en/stable/installation/
python 的环境变量,除了安装目录之外,还有一个 Script 目录 但其实一般影响都不大,根目录重要一点
如果没法把 python 加入环境变量,那么每次调用最好都用绝对路径
列出 pip 的所有模块
python -m pip list
列出 python 所有可用的模块
python -c 'import pydoc;pydoc.help("modules")'
这句也有类似的效果,但好像只有 sys 下的模块
python -c 'import sys;print(sys.modules.keys())'
因为要经常部署和重装系统,所以就整理了这样一句命令,可能会因为 docker 的更新而失效,要注意修命令里的版本号
具体环境
这是文档 https://docs.docker.com/engine/install/debian/
sudo apt-get remove -y docker docker-engine docker.io containerd runc ; \
sudo apt-get update && \
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release && \
if [ -e /usr/share/keyrings/docker-archive-keyring.gpg ] ; \
then rm /usr/share/keyrings/docker-archive-keyring.gpg; \
else curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg ;fi && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
sudo apt-get update && \
sudo apt-get install -y docker-ce docker-ce-cli containerd.io && \
sudo docker run --rm hello-world && \
sudo curl -L --retry 100 --retry-delay 2 "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose && \
docker-compose --version
如果 docker-compose 总是下载失败,可以尝试使用这样的脚本下载
COMMAND="curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose"
for ((i=0;i<100;i++))
do
$COMMAND
if [ $? -eq 0 ]; then
exit 0;
fi
done
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
具体环境
docker pull debian:11
docker run \
-it \
--rm \
-p 443:443 \
debian:11 /bin/bash
cp /etc/apt/sources.list /etc/apt/sources.list_bak && \
sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
apt update && \
apt install -y vim && \
apt install -y curl && \
apt install -y net-tools && \
apt install -y netcat && \
apt install -y procps
apt install -y bsdmainutils
apt install -y python3
apt install -y python3-pip
例子
curl -C - -o php-7.3.11.tar.gz https://www.php.net/distributions/php-7.3.11.tar.gz
解释
-L 允许重定向
-C 开启断点续传
- 这个表示开始和结束位置,一般就这样就可以了
--retry 100 超时重试 100 次,也可以是断点续传时的重试
--retry-delay 5 每次超时后等待 5 秒再重试
--connect-timeout 5 连接超过 5 秒算超时
一次连接超时时间。如果出错, 提示形如:curl: (28) connect() timed out!
--max-time 10 单次请求的最大时间
一次连接过程最大的允许时间。出错提示如:curl: (28) Operation timed out after 2000 milliseconds with 0 bytes received
--max-time 要大于 --connect-timeouts
--retry-max-time 30 整体请求的最大时间
-o 参数将服务器的回应保存成文件
-O 参数将服务器回应保存成文件,并将 URL 的最后部分当作文件名。
如果服务器主动返回 失败 例如 reset 这类的,就会直接退出的了,不论有没有设置 --retry
curl 提供了一个脚本用于方便下载文件 https://github.com/curl/wcurl
github 好像不支持断点下载
alias ll="ls -l "
alias ll="ls -l "
alias
alias -p
删除一个别名
unalias ll
删除两个别名
unalias ll ll2
删除全部别名
unalias -a
判断 PS1 是不是环境变量
printenv|awk -F '=' ' {print $1}'|grep "^PS1$"
printenv|awk -F '=' ' {print $1}'|grep "^PS1$";if [ "$?" -eq 1 ]; then echo "1"; else echo "0"; fi;
printenv|awk -F '=' ' {print $1}'|grep "^PS1$";if [ "$?" -eq 1 ]; then echo "This variable is not an environment variable"; else echo "This variable is an environment variable"; fi;
printenv|awk -F '=' ' {print $1}'|grep "^PS1$" 1>/dev/null ;if [ "$?" -eq 1 ]; then echo "This variable is not an environment variable"; else echo "This variable is an environment variable"; fi;
<!--
## 在 bash 里判断一个文件的类型
判断 ./index.html 是不是文本文件
file -b -i ./index.html | grep "^text" 1>/dev/null ;if [ "$?" -eq 1 ]; then echo "This file is not a text file"; else echo "This file is a text file"; fi;
应该可以通过 file 命令来区分 文本文件 和 二进制文件
file -b -i 文件路径
-b 不输出文件名
-i 输出文件对应的 MIME type 和 MIME encoding
-L 根据软连接重定向
--mime-type 只输出 MIME type
只有输出的是 text 开头的是文本文件,其它都当作是二进制文件(并不是很严谨)
一次列出当前目录下全部的 .html 文件
file -i ./*.html
file -b -L --mime-type /bin/mail
-->
<!--
/bin
/sbin
/usr/bin
/usr/sbin
/usr/local/bin
/usr/local/sbin
alias 和 $PATH
echo $PATH|awk 'BEGIN{RS=":"}{print $0}'
printenv PATH|awk 'BEGIN{RS=":"}{print $0}'
printenv PATH|awk 'BEGIN{RS=":"}{print $0}'
realpath
file -L -i /bin/mail
file -L --mime-type /bin/mail
file -b -L --mime-type /bin/mail
alias -p
-->
因为 github 的 pull 和 push 总是超时,所以写了两段脚本用于失败后的自动重试
#!/bin/bash
# ./git_help.sh pull
# ./git_help.sh push
GIT_COMMAND="git "
case $1 in
"push"|"pull")
GIT_COMMAND=$GIT_COMMAND$1
;;
*)
echo "only input push or pull";
exit 1;
;;
esac
for ((i=0;i<100;i++))
do
$GIT_COMMAND
if [ $? -eq 0 ]; then
exit 0;
fi
done
# ./git_help.ps1 pull
# ./git_help.ps1 push
param($a)
$GIT_COMMAND = "git "
if ($a -eq "push") {
$GIT_COMMAND = $GIT_COMMAND + $a
} elseif ($a -eq "pull") {
$GIT_COMMAND = $GIT_COMMAND + $a
} else {
echo "only input push or pull"
exit 1
}
for ($i = 1; $i -lt 100; $i++) {
echo $i" "$GIT_COMMAND
PowerShell -command $GIT_COMMAND
# Invoke-Expression $GIT_COMMAND
# Invoke-Command -ScriptBlock {Write-Host $GIT_COMMAND}
# Invoke-Command -ScriptBlock {$GIT_COMMAND}
if ($? -eq $true) {
break
}
}
href 是 Hypertext Reference (超文本引用) 的缩写。 href 目的是为了建立联系,让当前标签能够链接到目标地址。
src 是 source (来源) 的缩写。 指向的内容将会应用到文档中当前标签所在位置。 例如 img 和 script 的 src 属性。
href 和 src 的值通常是 url 但也可以不是 url 。 其中一个例子就是 img 标签的 src 可以直接放 base64 的值。
可以简单但不严谨地理解为 href 不会加载, src 会加载。 这样解释好象很有道理。 但 link 标签是用 href 的。 link 标签能加载 css 和 页面图标 还有 manifest 还有 预加载的 js 。
它们的全称
URL,URN,URC 都属于 URI 。 语法都是
URI = scheme ":" scheme-specific-part
URI = scheme ":" ["//" authority] path ["?" query] ["#" fragment]
authority = [userinfo "@"] host [":" port]
一些例子
userinfo host port
┌──┴───┐ ┌──────┴──────┐ ┌┴┐
https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top
└─┬─┘ └───────────┬──────────────┘└───────┬───────┘ └───────────┬─────────────┘ └┬┘
scheme authority path query fragment
ldap://[2001:db8::7]/c=GB?objectClass?one
└┬─┘ └─────┬─────┘└─┬─┘ └──────┬──────┘
scheme authority path query
mailto:John.Doe@example.com
└─┬──┘ └────┬─────────────┘
scheme path
news:comp.infosystems.www.servers.unix
└┬─┘ └─────────────┬─────────────────┘
scheme path
tel:+1-816-555-1212
└┬┘ └──────┬──────┘
scheme path
telnet://192.0.2.16:80/
└─┬──┘ └─────┬─────┘│
scheme authority path
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
└┬┘ └──────────────────────┬──────────────────────┘
scheme path
URN 的作用是描述资源的身份,例如 一个人的名字。 URN 的其中一个应用例子是 图书的 ISBN 号码 。
URN 的语法
urn:NID:NSS
NID 是 namespace identifier (命名空间标识符) 的缩写。
NSS 是 namespace specific string (命名空间特定字符串) 的缩写。
URN 的 NID 和 NSS 部分相当于 URI 里的 path 部分。
URL 的作用是描述资源的访问路径,例如 一个人的住址。
URL 的语法
hierarchical part
┌───────────────────┴─────────────────────┐
authority path
┌───────────────┴───────────────┐┌───┴────┐
abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
└┬┘ └───────┬───────┘ └────┬────┘ └┬┘ └─────────┬─────────┘ └──┬──┘
scheme user information host port query fragment
URC (统一资源特征),在九十年代的时候, URL URI URC 被期望能组成一个互联网信息架构。 但 URC 一直停留在理论阶段,随之更晚出现的其他技术(例如 资源描述框架)取代了它们。
URI 的 scheme 和 URN 的 NID 都需要在 IANA 注册。
完整的 url 或 urn 会被称为绝对 uri , 只有一部分的 url 或 urn 会被称为相对 uri 。
还有一个 Data URI 或者叫做 Data URL 。 这是具体的语法,也属于 URI 。
dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype := [ type "/" subtype ] *( ";" parameter )
data := *urlchar
parameter := attribute "=" value
比较好区分的一个特征是,以 urn 开头的 uri 就一定是 urn , 以 data 开头的 uri 就一定是 data url 。 除此之外的都是 url 。
url 两个斜杆 // 其实是没什么作用的
为什么文件 URL 以3斜杠开头?
curl -i -v file:///C:/Users/example.txt
curl -i -v file://localhost/C:/Users/example.txt
现在主流的启动过程是
MBR -> GRUB -> initramfs -> systemd
简单但又不严谨地理解, init 是第一个运行在用户态的进程。 这里描述的 init 可能是 SystemV init 也可能是 UpStart 也可能是 systemd 。
笔者认为作为一个写上层应用的程序员,了解到 加载和启动 linux 内核镜像 这一层就已经足够深入的了。
# 获取本机公网 IP
curl ifconfig.me
curl icanhazip.com
curl ipinfo.io/ip
curl ipecho.net/plain
curl www.trackip.net/i
curl ip.sb
curl whatismyip.akamai.com
curl ifconfig.co
curl ident.me
curl inet-ip.info
curl 'https://api.ipify.org?format=json' #ipv4
curl 'https://api64.ipify.org?format=json' #ipv6
# 获取本机公网 IP ,这几个有返回位置信息
curl myip.ipip.net
curl ip.cn
curl cip.cc
curl ip-api.com
curl ip-api.com/json
# 查询某个ip的信息
curl http://ip-api.com/json/58.62.220.66
大概就两种套路,从标准输入读取代码,从命令行参数读取代码,从命令行参数读取代码时要留意转义字符
代码开头都不需要 <? 或 <?php
phpcode=$(cat <<- 'EOF'
echo '123';
echo "asd";
$a="qwe";
echo $a;
echo "\"\$a\"\\";
var_dump($argv);
EOF
);
echo $phpcode | php -a -- a=1;
php -r "$phpcode" -- a=1;
php -a <<- 'EOF' -- a=1;
echo '123';
echo "asd";
$a="qwe";
echo $a;
echo "\"\$a\"\\";
var_dump($argv);
EOF
nodecode=$(cat <<- 'EOF'
console.log('hello');
EOF
);
echo $nodecode | node
node -e "$nodecode"
node <<- 'EOF'
console.log('hello');
EOF
执行标准输入里的代码,和普通文件里的代码一样,必须要有换行符
pythoncode=$(cat <<- 'EOF'
print('hi1')
print('hi2')
EOF
);
echo $pythoncode | python
python << 'EOF'
print('hi1')
print('hi2')
EOF
在一行里,换行用分号;替代
python -c "import os;print(os.environ['PATH'])"
伪代码
totalPage = ceil((totalRecord + pageSize - 1) / pageSize);
php
$totalPage = ceil(($totalRecord + $pageSize - 1) / $pageSize);
sql
SELECT @totalRecord := 123, @pageSize := 6;
SELECT ceil((@totalRecord + @pageSize + 1) / @pageSize);
ceil 是 向上取整 的函数
关于分页的语法
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
三种写法
SELECT * FROM table LIMIT rows
SELECT * FROM table LIMIT offset, rows
SELECT * FROM table LIMIT rows OFFSET offset
具体的例子
-- 每页 10 行,第 1 页
SELECT * FROM table LIMIT 10
SELECT * FROM table LIMIT 0, 10
SELECT * FROM table LIMIT 10 OFFSET 0
-- 每页 10 行,第 2 页
SELECT * FROM table LIMIT 10, 10
SELECT * FROM table LIMIT 10 OFFSET 10
-- 每页 10 行,第 3 页
SELECT * FROM table LIMIT 20, 10
SELECT * FROM table LIMIT 10 OFFSET 20
-- 每页 10 行,第 4 页
SELECT * FROM table LIMIT 30, 10
SELECT * FROM table LIMIT 10 OFFSET 30
这是获取总行数的 sql
SELECT count(*) FROM table LIMIT 1;
这是获取总页数的 sql
SELECT @pageSize := 6;
SELECT ceil((count(*) + @pageSize + 1) / @pageSize) FROM table LIMIT 1;
SELECT ceil((count(*) + 7) / 6) from table LIMIT 1;
这是获取某一页的 sql
-- 每页 6 行,第 2 页
SELECT @pageSize := 6;
SELECT @pageNo := 2;
SELECT @rows := @pageSize;
SELECT @offset := (@pageNo-1)*@pageSize;
SELECT * FROM table LIMIT @offset, @rows;
SELECT * FROM table LIMIT @rows offset @offset;
计算当前页的行数,这是伪代码
function getCurrentPageSize(pageSize, pageNo, totalRecord, totalPage)
{
if (pageNo < totalPage) {
return pageSize;
} else if (pageNo == totalPage) {
return pageSize + (totalRecord - totalPage*pageSize);
} else {
// Throw an exception
}
}
通过包管理
apt install -y busybox
通过 docker
docker run -it --rm --name my-busybox busybox:1.36-glibc sh
通过 type 命令判断当前系统有没有安装 busybox
type busybox
查看 busybox 的帮助和版本
busybox --help
可以在浏览器体验 busybox ,但版本好像有一点旧
https://busybox.net/live_bbox/live_bbox.html
windows 版的 busybox
https://frippery.org/busybox/
https://github.com/rmyorston/busybox-w32
建议下载 busybox64u.exe 这个版本,64位且支持 unicode ,虽然这个版本只支持 win10和win11
直接用 apt 安装的 busybox 版本太旧了, busybox 常常要用到宿主机的文件,容器里的 busybox 用起来不怎么方便。
安装前置的依赖
apt install -y bzip2 && \
apt install -y make && \
apt install -y gcc
下载源码
curl -O "https://busybox.net/downloads/busybox-1.37.0.tar.bz2"
解压源码
tar -xjf ./busybox-1.37.0.tar.bz2
切换进源码目录并开始安装
cd busybox-1.37.0
make defconfig
make install
编译后的 可执行二进制文件 可能在当前编译的目录,可能在源码的目录,反正要找一下
find / -name busybox
找到后就复制或剪切到 /bin 目录
cp /root/busybox-1.37.0/busybox /bin/busybox
一句命令完成下载和安装,但需要是 root 用户,其它用户需要修改对应的目录
apt install -y bzip2 && \
apt install -y make && \
apt install -y gcc && \
cd && \
curl -L -O "https://busybox.net/downloads/busybox-1.37.0.tar.bz2" && \
tar -xjf ./busybox-1.37.0.tar.bz2 && \
cd busybox-1.37.0 && \
make defconfig && \
make install && \
cp /root/busybox-1.37.0/busybox /bin/busybox && \
cd
使用这个仓库的代码来搭建 DNS , 使用这个仓库是因为笔者平时主要使用php做开发, https://github.com/yswery/PHP-DNS-SERVER
使用的是 v1.4.1 版本
git checkout v1.4.1
下载源码
https://github.com/yswery/PHP-DNS-SERVER
安装依赖,加上 --ignore-platform-reqs 参数,是因为这个仓库声明依赖的php版本比较旧,没这个参数可能无法下载composer里的依赖
composer install --no-suggest --no-dev --ignore-platform-reqs
参考 example/example.php 文件自己新建一个启动用的php文件 startup.php ```php require_once DIR.'/vendor/autoload.php';
$json = <<< EOF { "test.localhost.com": { "A": "127.0.0.1" } } EOF;
class JsonTextResolver extends \yswery\DNS\Resolver\JsonResolver { public function addZoneText(string $zone) { $zone = json_decode($zone, true); $this->addZoneArr($zone); }
public function addZoneArr(array $zone)
{
$resourceRecords = $this->isLegacyFormat($zone) ? $this->processLegacyZone($zone) : $this->processZone($zone);
$this->addZone($resourceRecords);
}
}
// JsonResolver created and provided with json dns records $jsonResolver = new JsonTextResolver([]); $jsonResolver->addZoneText($json);
// ipconfig /flushdns // php localhost2.php
// System resolver acting as a fallback to the JsonResolver $systemResolver = new yswery\DNS\Resolver\SystemResolver();
// StackableResolver will try each resolver in order and return the first match $stackableResolver = new yswery\DNS\Resolver\StackableResolver([$jsonResolver, $systemResolver]);
// Create the eventDispatcher and add the event subscribers $eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher(); $eventDispatcher->addSubscriber(new \yswery\DNS\Event\Subscriber\EchoLogger()); $eventDispatcher->addSubscriber(new \yswery\DNS\Event\Subscriber\ServerTerminator());
// Create a new instance of Server class $config = null; $storageDirectory = null; $useFilesystem = false; $ip = '127.0.0.1'; $port = 53; $server = new yswery\DNS\Server($stackableResolver, $eventDispatcher, $config, $storageDirectory, $useFilesystem, $ip, $port);
// Start DNS server $server->start();
<!--
$temp_file = tempnam(sys_get_temp_dir(), 'aaa');
\define('TEMP_RECORD_FILE', $temp_file);
register_shutdown_function(function(){
if (is_file(TEMP_RECORD_FILE)) {
unlink(TEMP_RECORD_FILE);
}
});
$json = <<< EOF
{
"shop-dev.theclub.com.hk": {
"A": "127.0.0.1"
}
}
EOF;
file_put_contents(TEMP_RECORD_FILE, $json);
// ipconfig /flushdns
// php localhost.php
// JsonResolver created and provided with path to file with json dns records
$jsonResolver = new yswery\DNS\Resolver\JsonResolver([TEMP_RECORD_FILE]);
-->
1. 这是启动的命令,可以把这个命令保存在一个用于启动的脚本文件
<!-- startup.bat startup.sh -->
php startup.php
1. 修改网卡的 dns 配置
<!-- 一般情况下 主DNS 访问失败时才会访问 备用DNS ,查询没有结果不算访问失败 -->
1. 可以用这样的命令来测试是否生效,如果没有生效可以尝试刷洗 dns 缓存
nslookup -debug -querytype=A -port=53 test.localhost.com 127.0.0.1
1. 如何写配置文件可以参考仓库里的文档或参考 example 里的文件
1. 如果不把设为服务,则每次开机后都要手工启动一次
## 在本地使用 unbound 搭建一个 DNS 服务
笔者原本是想用php的库来建一个本地的dns服务,但找了很久都没找到合适的,最后还是选择用 unbound ,
和 bind 相比, unbound 提供了免编译免安装的版本。
使用的是 v1.19.0 版本
1. unbound 的仓库
https://github.com/NLnetLabs/unbound
1. unbound 的文档
https://unbound.docs.nlnetlabs.nl/en/latest/index.html
1. 下载 unbound
https://nlnetlabs.nl/projects/unbound/download/
1. 下载完后,解压,然后复制一份配置文件
cp example.conf unbound.conf
1. 修改配置文件,整个配置文件非常大,在特定位置改好这几项就好了
interface: 127.0.0.1
local-data: "test.localhost.com A 127.0.0.1"
forward-zone: name: "." forward-addr: 系统原本的主dns地址 forward-addr: 系统原本的备用dns地址
1. 检测配置文件
unbound-checkconf unbound.conf ./unbound-checkconf.exe unbound.conf
1. 运行
unbound -vv -c unbound.conf ./unbound.exe -vv -c unbound.conf
unbound -d -vv -c unbound.conf ./unbound.exe -d -vv -c unbound.conf ```
<!-- unbound 如何设置 DNS-over-HTTPS? -->