f2h2h1.github.io

一些开发笔记

在 VSCode 里调试 JAVA

  1. 安装 JDK
  2. 把 JDK 添加进环境变量
  3. 安装 VSCode 的 JAVA extension pack 拓展
  4. 使用 VSCode 打开文件夹
  5. 新增一个 debug 的类型 JAVA ,点击右下角的添加配置,选择 JAVA Lanuch Program
  6. 写一份测试的代码,并在 mian 函数加个断点
  7. 然后在终端里运行编译命令和运行命令,如果编译命令不复杂,可以配合 code runner 拓展,直接点击右上角的运行图标,或设置一个任务

在 VSCode 里调试 Python

  1. 安装 Python
  2. 把 Python 的安装目录和安装目录下的 script 添加进环境变量里
  3. 在 VSCode 安装 Python 拓展( microsoft 出品的)
  4. 新增一个 debug 的类型 Python ,点击右下角的添加配置,选择 Python: Terminal (integrated)
  5. 写一份测试的代码,并加个断点
  6. 然后在终端里运行,可以配合 code runner 插件,直接点击右上角的运行图标,或设置一个任务

在 Windows10 里修改 administrator 帐号的帐号名的三种方式

  1. 通过管理里的系统工具修改
    选中桌面中的计算机图标,右键,点击管理
    系统工具
     本地用户和组
         用户
             选中Administrator,然后重命名
    重启电脑
    
  2. 通过策略租修改
    win+r 打开运行
    输入 gpedit.msc 打开策略组
    计算机配置
     windows设置
         安全设置
             本地策略
                 安全选项
                     拉到最下面
                     双击这个选选项 重命名系统管理员帐户
    重启电脑
    
  3. 通过 netplwiz (Network Places Wizard) 网上邻居向导 修改
    win+r 打开运行
    输入 netplwiz
    选中Administrator,然后双击,然后修改
    重启电脑
    

Windows10 无密码远程连接

  1. 允许任何远程着桌面的连接
  2. 修改 Windows 的安全策略,允许远程桌面连接使用空密码
    win+r 打开运行
    输入 gpedit.msc 打开策略组
    计算机配置
     windows 设置
         安全设置
             本地策略
                 安全选项
                     拉到最下面
                     禁用 使用空密码的本地账户只允许控制台登录
    

ss 的使用

需要一个在 wall 以外的服务器

ss 的各个版本 https://github.com/shadowsocks/shadowsocks/wiki/Feature-Comparison-across-Different-Versions

python

  1. 下载 python
  2. 安装 python
  3. 把 python 添加到环境变量
  4. 刷新环境变量
  5. 下载 ss
     python -m pip install shadowsocks
     # 如果上面那句下载失败,可以尝试用这句安装
     python -m pip install https://github.com/shadowsocks/shadowsocks/archive/master.zip -U
     # 如果上面那句还是下载失败,可以尝试先把 master.zip 文件下载到本地,再安装
    
  6. 在服务器的策略组放行相应的端口
  7. 在防火墙放行相应的端口
  8. 运行以下命令
     ssserver -p 61813 -k windows@163.qq -m aes-256-cfb
         -p 是端口号
         -k 是密码
         -m 是加密方式
     上面那条命令需要在 服务器的策略组 和 防火墙 放行 61813 端口
    
  9. 下载客户端
  10. 正确填写 ip 端口 密码
  11. 一些加密的算法会依赖这个库 libsodium ,最好把这个库也装上
     https://download.libsodium.org/libsodium/releases/
    
  12. 更新 ss
     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
    
  13. 失效时,可以尝试,更改端口,更改密码,更改加密方式,换一个ip
  14. 参考
     https://github.com/shadowsocks/shadowsocks/wiki/Shadowsocks-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E
    

libev

VS 和 VC 库 的对应关系

   
Visual 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

php 版本和 VC 库的对应关系

   
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

Windows 里的脚本

脚本语言

各种文件后缀

后缀 备注
.vbs  
.js  
.vbe 已编码的 VBScript 脚本文件
.jse 已编码的 JScript 脚本文件
.ws  
.wsc Windows Scripting Component
.sct  
.wsf Windows Scripting file
.wsh Windows Scripting Host
.hta  
.cmd  
.bat  
.ps1  
.pac  
.asp  
.aspx  
.shtm 包含服务器端指令的 HTML 文件
.shtml 包含服务器端指令的 HTML 文件
.stm 包含服务器端指令的 HTML 文件

参考

Microsoft Windows 脚本技术 https://www.jb51.net/shouce/script56/

如何不使用浏览器在 windows 里下载文件

使用 Windows 自带的程序

下载文件方式的一些总结

各种协议

下载链接的前缀

thunder, Flashget, qqdl 随便百度一下就能找到解码的方法

各种软件

p2p

BT种子: 用一个文本文件(通常以 .torrent 作为后缀)描述一个或多个 Tracker 服务器或 DHT 网络中的文件。 ed2k: 用一段字符描述一个 KAD 网络中的文件。 Magnet: 用一段字符描述一个 DHT 网络中的BT种子文件。

其他

BitTorrent 既是一个下载协议也是一个软件名称。 大概就是作为软件的 BitTorrent 是最早使用 BitTorrent 协议下载的软件。

eDonkey 是一个商业软件, eMule 是 eDonkey 的开源版, VeryCD电驴 是国内的公司的根据 eMule 修改而来的。 kad 网络还有很多客户端,但在国内都不流行。

前互联网时代,好像都很喜欢在产品或软件或服务的名称前面加一个字母 e (例如 eMule eDonkey)

理论上 telnet 和 ssh 也可以用来下载文件。 理论上只要有网络连接就能下载文件,即使只能传输文本,也可以用 base64 来传输二进制数据。

参考

Windows 安全地删除U盘

U盘 弹出失败的原因是进程占用了 U盘 ,只要占用 U盘 的进程都不在占用 U盘 或 都结束了, U盘 就可以安全地弹出了。

所以,让 U盘 安全地弹出的关键是找到占用 U盘 的进程。

当占用 U盘 的进程结束后,有时立即弹出 U盘 还是会失败的,这时再等待五六秒,再试一次弹出 U盘 就可以了。

可以安全退出 U盘 时也不要马上拔 U盘 ,最好等个五六秒再拔 U盘 。

这是各种方法的总结

  1. 最简单的,在系统托盘右键,弹出,或在此电脑的界面,选中 U盘,右键,弹出
  2. 关掉所有文件夹再试一次弹出 U盘
  3. explorer.exe 重启,再试一次弹出 U盘
  4. 注销当前的登录,再次登录,再试一次弹出 U盘
  5. 通过任务管理器找到占用 U盘 的进程
    1. 打开任务管理器
    2. 切换到性能页面
    3. 打开资源监视器
    4. 切换到 cpu 页面
    5. 在 关联的句柄 栏目的搜索框内输入你的 U盘 盘符(如G:\)
    6. 即可看到当前占用 U盘 的进程
  6. 关闭 U盘 的写入缓存
    1. 控制面板
    2. 管理工具
    3. 计算机管理
    4. 设备管理
    5. 磁盘驱动
    6. 选择当前的 U盘
    7. 右键 属性 策略
    8. 关闭写缓存
    9. 关闭写缓存可能会造成 U盘 数据的丢失,关闭了写缓存后,要确保 U盘 里的文件已经保存好再弹出 U盘
  7. 在磁盘管理里使 U盘 脱机
    1. 控制面板
    2. 管理工具
    3. 磁盘管理
    4. 选择当前的 U盘
    5. 右键 脱机
    6. U盘 脱机后下次插入要重新挂载,脱机之后可以马上联机,再安全弹出,这样 U盘 下次插入时就不用联机了
    7. 脱机会直接关掉所有的文件句柄,要确保 U盘 里的文件已经保存好再脱机
    8. 脱机选项不可选,可能是有虚拟内存分配到 U盘 ,这时取消在 U盘 上的虚拟内存即可
      • 进入电脑属性->高级系统设置->高级->性能设置->高级->更改,关闭自动管理分页文件大小,取消在该磁盘上设置的虚拟内存
    9. 有时脱机还会失败,这时就继续参考下面的步骤
  8. 通过 日志 查找占用 U盘 的进程
    1. 打开事件查看器
    2. windows日志
    3. 系统
    4. 找到最近的一条 来源 Kernel-PnP 的记录
    5. 记录的常规里有占用 U盘 的 进程id 的
    6. 再通过任务管理器的 pid 找到对应的进程
    7. 有时,即使找到占用 U盘 的进程,但却无法结束进程,或 进程是系统的核心进程
      • 这时可以尝试以这样的关键词(进程名 或 进程id + Kernel-PnP )在网上搜索解决的方法
  9. 如果是 Windows Defender 占用 U盘 可以试试这样操作
    1. 打开 Windows Defender 安全中心
    2. 病毒和威胁防护
    3. 病毒和威胁防护 设置
    4. 将在使用的 U盘 盘符添加为排除项
  10. 最后的方法,关机,关机后就肯定可以安全地拔 U盘

笔者通常在直接弹出 U盘 失败后,会多试几次,然后通过 日志 找到对应的进程,然后通过 任务管理器 结束对应的进程,如果结束进程失败,还是会再次在网上搜索解决方法。 脱机 和 关闭写缓存都有一点副作用; 关闭文件夹,重启 explorer.exe ,注销,关机,这类都有点麻烦。

windows 下的 linux 环境

下载 AcFun 视频

0. 需求

  1. 一部安卓手机
  2. AcFun 安卓版客户端
  3. ffmpeg

1. 使用手机客户端缓存视频

2. 在手机的文件管理器里找到缓存文件

  1. 用文件管理器打开手机的根目录
  2. 找到 acfun 文件夹
  3. 点进这个目录里 acfun→core→local
  4. 然后点进一个以数字名命的文件夹
  5. 这个文件夹里就是缓存的视频,文件名都没有后缀,可以通过创建时间大致判断出哪个是最新缓存的视频

3. 在电脑里下载 ffmpeg

  1. 打开 ffmepg 的下载网址,并选择系统对应的版本下载
    http://www.ffmpeg.org/download.html
    
  2. 把下载后的文件解压
  3. 解压后的文件里会有个一个名为 ffmpeg 的文件,这个就是 ffmpeg 的主程序,可以用来转换视频格式

4. 把缓存的视频文件复制进电脑,并使用 ffmpeg 转换为 MP4 格式

  1. 把缓存文件从手机复制进 ffempeg 的解压目录
  2. cd 进 ffempeg 的解压目录
  3. 运行以下命令,转换格式后的文件名必须带有 MP4 的后缀
    ffmpeg -i "缓存视频文件的文件名" "转换格式后的文件名"
    

在Windows下配置Tomcat服务器

0. 目标

1. 下载 JAVA

https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

选择,Windows 64 位

2. 安装 JAVA

打开下载的 exe 文件,一路点 next 直到安装完毕

3. 配置 JAVA 环境变量

  1. 新建一个环境变量 JAVA_HOME ,值为 JDK 的安装目录,例子
    C:\Program Files\Java\jdk1.8.0_161
    
  2. 把以下值加入到环境变量 Path
    %JAVA_HOME%\bin
    %JAVA_HOME%\jre\bin
    %JAVA_HOME%\lib
    

3. 下载 Tomcat

https://tomcat.apache.org/download-90.cgi

选择,core,Windows 64 位

4. 配置 Tomcat

  1. 解压下载的文件
  2. 把解压后的文件夹复制到 C 盘的根目录下(这里可以是任意目录)
  3. 把 Tomcat 目录下的 bin 文件夹的路劲加入的环境变量
  4. 把网站程序复制进 Tomcat 的 webapps 文件夹
  5. 启动 Tomcat ,启动 Tomcat 的脚本在 bin\startup.bat

安装 PHP7 的 GUI 扩展

1 下载拓展

2 安装拓展

  1. 把下载下来的压缩包解压
  2. 把 php_ui.dll 复制到 PHP 的 ext 目录下
  3. 把 libui.dll 和 pthreadVC2.dll 放到 PHP 的根目录下

3 运行 demo

注意

如果出现这种错误

无法启动此程序,因为计算机中丢失 libui.dll,尝试重新安装该程序以解决此问题。

这个提示出现说明你没有放入 libui 和 pthreadVC2 文件到 php 的根目录下

treminal tty console 和 shell

treminal , tty , console 是一开始都是硬件的概念。

一台电脑只有一个 console ,一般有电源开关等硬件操作的, 一台电脑可以有很多个 terminal 。 terminal 是负责 shell 的输入和输出。 console 也可以当作一个特殊的 terminal ,就是一个多了电源开关等硬件操作的 terminal 。 tty 是电传打印机。电传打印机是一种把键盘作为输入,纸带作为输出的硬件,是一种 terminal 。 一开始 terminal 就是指 tty 。 后来出现了使用显示器输出的 terminal 。使用显示器输出的 terminal 被称为 video terminal 简称 vt 。

旧时代的大型电脑为了能让多个用户可以同时使用,会提供多个物理终端。

软件意义上的终端出现,是为了让个人电脑的用户可以直接使用他的个人电脑来与大型计算机联系,而不必使用专门的物理终端。 现在的终端会被称为 emulator treminal 或 virtual terminal 。 因为现在已经没有物理意义上的终端了,都是由软件实现。 现在的 treminal , tty , console 都是指一种可以用来显示 shell 的软件, shell 可以是本地的也可以是远程的。

shell 是软件的概念。 shell 负责接收外部输入,调用各种程序或系统命令,然后输出结果。简单但不严谨的解释,负责人机交互的可以称为 shell ,负责显示 shell 的可以称为 terminal 。 shell 是通常是指命令行解释器,但图形界面一样可以有 GUI shll ,例如 Windows 的 explorer.exe 。 shell 通常会被翻译成 外壳 或 壳层。 shell 的概念其实是相对于操作系统内核 (kernel) 而言的。

shell 还可以分为 interactive 和 non-interactive 直接输入的命令运行在 interactive shell 上, shell 脚本代码就运行在 non-interactive shell 中。

词汇表

参考

https://www.zhihu.com/question/65280843

https://www.cnblogs.com/sparkdev/p/11605804.html

https://www.cnblogs.com/sparkdev/p/11460821.html

http://docs.linuxtone.org/ebooks/C&CPP/c/ch34s01.html

https://blog.csdn.net/dog250/article/details/78818612

https://taoshu.in/tty.html

各种 unix like shell

全称 简称 备注
thompson shell sh 第一个 unix like shell 。1971年至1975年随 Unix 第一版至第六版发布
borune shell sh 1978年随Version 7 Unix首次发布
borune again shell bash 在1987年由布莱恩·福克斯(Brian Fox)为了GNU计划而编写,是当前最常用的 shell
almquist shell ash 派生于 borune shell ,最初作为 bsd 的 shell ,目前已不再被广泛使用
debian almquist shell dash 派生于 almquist shell ,是 debian 的 shell
c shell csh 语法类似于C语言, c shell 目前已不再被广泛使用
tenex c shell tcsh csh 的增强版, FreeBSD 中的默认 shell
korn shell ksh AIX 中的默认 shell ,兼容 borune shell ,同时加入了一些 c shell 的特性
zsh zsh zsh 对 borune shell 做出了大量改进,同时加入了 bash , ksh 及 tcsh 的某些功能。 zsh 现在是 mac 的默认 shell
friendly interactive shell fish fish 的语法既不派生于 borune shell 也不派生于 c shell ,故被分类为一种“外来” shell 。

各种 shell 的发展脉络

+------------------------------------------------------------------------------------------------------------------+
|                                                                                                                  |
|                                                                                                                  |
|                                                                                                                  |
|                          Thompson shell                                                                          |
|                 +----------+     +--------------------------+                                                    |
|                 |                                           |                                                    |
|                 |                                           |                                                    |
|                 v                                           v                                                    |
|                c shell                                  Bourne shell                                             |
|                  +                                           +                                                   |
|                  |                                           |                                                   |
|            +-----+-----------------+                         | +------------------>                              |
|            |                       |                         |                    |                              |
|            v                       v                         v                    v                              |
|     tenex c shell             korn shell           Bourne-Again shell       almquist shell                       |
|         +                          +                        +                     +                              |
|         |                          |                        |                     |                              |
|         +--------------------------v--------+---------------+                     |                              |
|                                             |                                     v                              |
|                                             |                              debian almquist shell                 |
|                                             v                                                                    |
|                                            zsh                                                       fish        |
|                                                                                                                  |
+------------------------------------------------------------------------------------------------------------------+

sh 通常是指遵循 POSIX 标准的 shell 。 bash 有 3 种方式使其遵循 POSIX 标准 https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html

通常情况下 shell 脚本以这句开头 #!/bin/sh ,就是表示这份脚本遵循 POSIX 标准。 如果想脚本足够的通用,最好不要用 bash 的语法。

现在绝大部分 unix like 系统中, /bin/sh 和 /usr/bin/sh 一般都是链接文件,指向真正的默认 shell 。 现在绝大部分 shell 都兼容 POSIX 标准,但同时又会有一些自己的拓展。

新版本的 powershell 也能运行在 linux 上。

linux 实现后台不间断运行

gcc 编译流程

编译的四个步骤

  1. 预处理 由 .c 文件到 .i 文件。
    • 对各种预处理命令进行处理,包括头文件包含、宏定义的扩展、条件编译的选择等
  2. 编译 由 .i 文件到 .s 文件。
    • 将预处理得到的源代码文件,进行“翻译转换”,产生出机器语言的目标程序,得到机器语言的汇编文件
  3. 汇编 由 .s 文件到 .o 文件。
    • 将汇编代码翻译成了机器码,但是还不可以运行
  4. 链接 由 .o 文件到可执行文件。
    • 处理可重定位文件,把各种符号引用和符号定义转换成为可执行文件中的合适信息,通常是虚拟地址

编译的四个步骤对应的 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 的命令

其它

参考

感觉 GNU 真的除了内核之外,什么都有了。

让网站支持 ipv6

  1. 拥有一个 ipv6 地址
  2. 域名解释 aaaa 记录指向 ipv6 的地址
  3. 让网站程序支持 ipv6 地址
    • 通过网关翻译
      • 代码里用 ipv4 地址,域名解释 aaaa 记录到 网关,网关把 ipv6 的流量翻译成 ipv4 的流量再传递给网站
      • 代码里用 ipv6 地址,域名解释 a 记录到 网关,网关把 ipv4 的流量翻译成 ipv6 的流量再传递给网站
    • 让 web 服务器同时监听两个地址,代码里和 ip 相关的部分,都改成能兼容 ipv4 和 ipv6

用来测试网站对 ipv6 的支持,也可以用来查看 DNSSEC 的支持 https://ipv6.ustc.edu.cn/onlinechecklog.php

在命令行里格式化 json

  1. python 的 json.tool ,好像 python2 和 3 都可以这样用
     echo '{ "name": "xiaohong", "age": 18 }' | python -m json.tool
    
    • 会转义中文,如果想不转义中文
    • 需要修改标准库里的文件,这样不是很好,在 python 的标准库 json 文件夹下有个 tool.py 文件,更改其中调用的 json.dump 函数,传一个ensure_ascii = False 参数即可
  2. json_pp , windwos 的 git bash 和 大多数 linux 发行版都有这个工具
     echo '{ "name": "xiaohong", "age": 18 }' | json_pp
    
  3. jq , 虽然大多数 linux 发行版都没有这个工具,但中文互联网环境下有好多文章都推荐这个
    • 下载 https://stedolan.github.io/jq/download/
    • 文档 https://stedolan.github.io/jq/manual/
  4. 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 的首次启动配置不完整

可以尝试以下步骤来解决

  1. 打开 IE 的 internet 选项
  2. 点击安全选项卡,选中本地 intranet ,并点击站点按钮
  3. 新的窗口中点击高级
  4. 添加 about:security_powershell.exe 到输入框,点击添加
  5. 把所有 IE 窗口一个个关闭就好了,再次在 powershell 下运行 Invoke-WebRequest

Windows 里的 Java 环境配置

  1. 下载并安装 JDK
    • 这些是免费的 JDK
      • https://openjdk.java.net/
      • https://www.microsoft.com/openjdk
      • https://adoptopenjdk.net/
      • https://www.azul.com/downloads/?package=jdk
      • https://developers.redhat.com/products/openjdk/download
    • 这是 oracle 的 JDK
      • https://www.oracle.com/java/
    • 如果是 JDK 1.8 以上的版本,笔者比较倾向于用 microsoft 的 openjdk
    • 通常只有 oracleJDK 需要安装,其他的 JDK 都是压缩包,直接解压就好了
  2. 把 JDK 加入环境变量
    1. 新建一个新的环境变量 JAVA_HOME ,值是 JDK 的根目录
    2. 在 PATH 里加入 %JAVA_HOME%\bin 和 %JAVA_HOME%\lib 和 %JAVA_HOME%\jre\bin (如果没有这个目录就忽略)
    3. 如果是 JDK 1.5 及之前的版本还需要一个 CLASSPATH 的环境变量
      • CLASSPATH 的值是 .;%Java_Home%\bin;%JAVA_HOME%\lib;%Java_Home%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
  3. 下载并安装 maven
    • https://maven.apache.org/
  4. 把 maven 加入环境变量
    1. 新建一个新的环境变量 MAVEN_HOME ,值是 maven 的根目录
    2. 在 PATH 里加入 %MAVEN_HOME%\bin

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

无法执行 powershell 脚本

通常是执行策略的原因导致的。

设置脚本执行策略,通常把 策略 设为 RemoteSigned 就可以了

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine

查看 powershell 脚本执行策略

Get-ExecutionPolicy
Get-ExecutionPolicy -List

https://docs.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.2

python 的 http 服务和 cgi

python 一行命令启动 http 服务

# 最简单的 http 服务
python -m http.server
# 有 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

参考文档

debian 一句命令安装 docker

因为要经常部署和重装系统,所以就整理了这样一句命令,可能会因为 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

curl 断点续传

例子

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

github 好像不支持断点下载

在 debian 新建命令的别名

用于 git pull 和 git push 的脚本

因为 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 和 src

href 是 Hypertext Reference (超文本引用) 的缩写。 href 目的是为了建立联系,让当前标签能够链接到目标地址。

src 是 source (来源) 的缩写。 指向的内容将会应用到文档中当前标签所在位置。 例如 img 和 script 的 src 属性。

href 和 src 的值通常是 url 但也可以不是 url 。 其中一个例子就是 img 标签的 src 可以直接放 base64 的值。

可以简单但不严谨地理解为 href 不会加载, src 会加载。 这样解释好象很有道理。 但 link 标签是用 href 的。 link 标签能加载 css 和 页面图标 还有 manifest 还有 预加载的 js 。

URI URL URN

它们的全称

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 的作用是描述资源的身份,例如 一个人的名字。 URN 的其中一个应用例子是 图书的 ISBN 号码 。

URN 的语法

urn:NID:NSS

NID 是 namespace identifier (命名空间标识符) 的缩写。

NSS 是 namespace specific string (命名空间特定字符串) 的缩写。

URN 的 NID 和 NSS 部分相当于 URI 里的 path 部分。

URL

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斜杠开头?

参考

那些能作为工具的网站