关于

关于 哔u哔u

小站取名为:哔u哔u。这只是我随意取得,并没有什么特殊含义,感觉萌萌的也不错。我觉得,其实直接用我的名字更好一点。嘛,当初网站备案时,用的就是这个,也懒的改了。

小站的定位是我的个人博客,他不会提供太多功能,我只是想把我的文章找个地方发布而已。

我除了发布一些博客文章,也会发布一些总结性的文章集合,还会发布一些与技术毫不相关的东西,比如:吐槽。

关于 huanggefan.cn

小站的域名:huanggefan.cn 就是我的名字拼音,是不是很简单。

关于 黄舸帆

我叫黄舸帆,来自安徽。现在就读于安徽农业大学。我现在是名本科生,没有那么牛_B_的技术。不过未来谁知道呢(偷笑)……

我算是从高中就开始入坑编程,最早学的编程语言时传说中的“Visual Basic 6.0”。估计现在已经没几个人还知道这门奇葩的编程语言了吧。事实上,我学了一个学期后,就转入 C语言了,从此正式踏进编程的天坑之中。

如何联系我: 我的邮箱:huanggefan@aliyun.com

文章许可

本协议的目的是让任何人想要使用 www.huanggefan.cn(以下简称“小站”)的文章都无需考虑太多版权问题。

小站允许以下形式使用小站的文章:引用、参考、转载、出版

对小站文章内容不加修改加以修改后,进行以上行为,都在约束范围内

  1. 对于引用小站文章的行为,只需要在引用处附近的标注出原文地址。

  2. 对于参考小站文章的行为,只需要在文章任何地方标注出原文地址。

  3. 对于转载小站文章的行为,只需要在文章开始处标注出原文地址。

  4. 对于出版小站文章的行为,也是允许的,但需要满足以下条件:

    1. 在出版物的序言中标出以下内容:“文章出自:www.huanggefan.cn”。
    2. 保证任何人都可以免费获得出版物的 PDF 格式文档。

CDDA大灾变编译安装

CDDA 简述

CDDA 大灾变,是个不错的游戏。你在扮演一个在末世里幸存的一个普通人、探险家、生存狂、科学家……在这个世界里,你可以肆意破化、屠杀丧尸、建造基地……

不过嘛,这是字符终端下的游戏,额,这个画风不是所有人都可以接受的。

获取源码

不要去官网下载代码编译,官网的代码太旧,估计这个网站很久没更新了吧。而且提供的二进制包是 32 位的,一些库的位置和 64 位不一样。

所以,果断点去 GitHub 吧。

git clone https://github.com/CleverRaven/Cataclysm-DDA.git

开始编译

看看 makefile 吧,里面写了编译的方法,以及如何编译中文版本。

make -j4 NATIVE=linux64 RELEASE=1 LUA=1 LANGUAGES=zh_CN

如果报错没有 lua 就对了,想要使用完整的 mod 功能,就要在编译时加上 LUA=1 ,当然,你可以不用 mod。为了使用 mod 功能,就要安装 lua。

apt-get install lua5.3 liblua5.3-dev

这时执行 make 时依然会报错:没有 lua 命令,注意,这里安装的是 lua5.3,所以 lua 命令是 lua5.3。可以使用软链接解决。

ln -s /usr/bin/lua5.3 /usr/bin/lua

踩坑:编译图形界面版

上面的 make 是编译字符版的,编译 SDL 版时,编译成功,但无法运行,运行会给出个错误:libpng warning: iCCP: known incorrect sRGB profile

我不知道咋办,网上有说 png 图片问题,载入重新覆盖就好,我用 Gimp 试了,不行。也罢,字符界面版玩着更高大上。话说,有大神知道如何解决,告诉我一下啊,感激!!

踩坑:astyle报错

make 会使用到 astyle 这个软件,你可以先安装了试试。一般不安装这个,会提示缺少 astyle,但是不影响编译。如果你安装了,可能会无法编译了,这时,卸了 astyle 可以了。

踩坑:中文乱码

cdda 最近更新的版本,编译后可能会出现中文乱码,我当时编译时看了输出,发现没有链接 ncursesw 库,makefile 里现在链接的是 ncursesw6,然而你的系统现在的 ncursesw 可能还是 ncursesw5。现在奉上解决方案:更改 makefile 的第 566 到 572 行如下:把 ncurses 换成 ncursesw 即可

566:ifeq ($(HAVE_PKGCONFIG),1)
567: CXXFLAGS += $(shell pkg-config --cflags ncursesw)
568: LDFLAGS += $(shell pkg-config --libs ncursesw)
569:else
570: ifeq ($(HAVE_NCURSES5CONFIG),1)
571: CXXFLAGS += $(shell ncursesw5-config --cflags)
572: LDFLAGS += $(shell ncursesw5-config --libs)

这样会强制链接 ncursesw 库,不管系统的 ncursesw 版本是多少,不管 makefile 链接的版本是多少,都会链接 ncursesw。强烈建议,没有出现这个问题的,请不要更改 makefile。更改后,如果以后要更新时,请先撤销 makefile 的更改。

Hugo部署历程

情景描述

使用 WordPress 写博客有一个学期了,博客没写几篇,Nginx 和 WordPress 倒是折腾了不少。也是嘛,如果不是折腾了一个学期的 Nginx,这次学校网络更新架构,要给城市热点的服务分配域名,然后那个端口问题还真搞不定了。

不过,WordPress 的写作体验是真的不太好。不仅没有 MarkDown 写着舒服,每天还要担心有没有人进行网络渗透。WordPress 的速度的确不算快,我上了缓存插件,直接生成静态页面,然后还配置了 tmpfs。

现在,我决定迁移到 Hugo,纯静态网站,你来入侵啊。Hugo 生成的网站文件,我还给放到了 tmpfs 里,起飞吧,哔u哔u。

安装相关软件

首先是安装 Hugo,这个建议不要使用包管理器直接安装,建议到 GitHub 下载编译好的二进制安装包,实在不行,自己编译也好。

可以到 Hugo Release 页面 下载。

以 DEB 系的 32位 Linux 为例,首先下载 deb 包:

wget https://github.com/gohugoio/hugo/releases/download/v0.47.1/hugo_0.47.1_Linux-32bit.deb

然后进行安装

sudo dpkg -i hugo_0.47.1_Linux-32bit.deb

然后安装 Git、Nginx,这个直接安装就好

sudo apt install -y git nginx

配置 MathJax

我使用的 Hugo 主题已经支持了 MathJax,不过是从 CDN 那里加载的 MathJax 文件。而我想让所有的文件都在我自己的服务器上,于是我就魔改了一下下主题。这里对其他 Hugo 用户应该也有些参考价值。

首先是下载 MathJax,从 GitHub 下载。

wget https://github.com/mathjax/MathJax/archive/master.zip

解压这个压缩包,然后将这个压缩包里 unpacked文件夹移动到你的 Hugo 网站的目录下,最好这个文件夹重命名为 MathJax

然后,移动压缩包里的 fonts 文件夹,到 Hugo 网站的目录下,应该与 MathJax 文件夹在同一级目录里。

我将这两个文件夹放在了 static/lib/ 下面,最终生成网站后,应该在 /lib/ 下面。也就是 /lib/ 下面应该存在两个文件夹,/lib/MathJax/lib/fonts

然后你要想办法在你的生成的静态 Html 文件里加上如下几行:

<script type="text/javascript">
    window.MathJax = {
      tex2jax: {
            inlineMath: [['$','$'], ['\\(','\\)']],
            displayMath: [['$$','$$'], ["\\[","\\]"]],
            processEscapes: true
        },
      TeX: {equationNumbers: {autoNumber: "AMS"}},
      showProcessingMessages: true,
      messageStyle: 'normal'
    };
  </script>
  <script type="text/javascript" async src="/lib/MathJax/MathJax.js?config=TeX-AMS_HTML"></script>

注意最后那个引用 MathJax 的链接,建议你查查 MathJax 的文档。这里的配置是使用 Tex 语法书写公式,使用 Html 和 Css 渲染公式。

以下是一个测试,数学公式: \sum_1^2

行内显示公式:$ \sum_1^2 $

块显示公式:

$$ \sum_1^2 $$

使用 Git 发布文章

首先配置一下服务器端的 Git。我的做法是直接上传本地的 Git 配置文件。毕竟这个配置用了两年了。但是,仅仅这样还是不够的。

在服务器上找个目录放你的网站,然后:

git init
git add -A
git commit -m "迁移博客到 Hugo"

这些都是常规操作了。不过这个时候,本地的 push 操作是失败的。没错,之所以说使用本地的配置不够是因为,本地的配置少了一些。

[core]
  autocrlf = input
[receive]
  denyCurrentBranch = ignore

第一个配置是转换 Linux 的换行符与 Windows 的换行符,否则就会一直提示,很烦的。第二个配置是关键。进行 push 时,如果远程库是非 bare 库,本地 push 会被禁止。所以,加上这个配置,本地的 push 会同步过去,但是远程仓库工作区的文件内容不会更改。

其实,到了这里就结束了。

之后,本地的更改直接 push 就好了,然后 ssh 到服务器,直接检出、合并、构建就完事了。

这里提一下具体操作

git log
git status
git reset --hard dca8b26
hugo

首先查看我们提交的历史,以及版本号。然后我们看看此时仓库的状态。可以看到我们提交成功了,并且已经到了暂存区里,但是工作区还未同步。现在我们既可以让暂存区同步到工作区,也可以直接回滚到提交记录中去。

所以我们使用 reset --hard 强制使工作区回到 dca8b26 这次提交的状态去。

事实上,这里这样做更方便,操作是完全等价的。而且还可以做成钩子,实现 commit 后自动构建。

git reset --hard HEAD
hugo

因为 HEAD 是指向最新的 commit 的,所以 reset 到 HEAD 和 reset 到指定的 commit 在我们这里的情形下是完全等价的,因为我们指定的 commit 就是最新的那一个。

使用 Nginx 部署网站

一个静态网站,有啥好配置的。直接贴出来。

server {
    listen 0.0.0.0:443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate /website/nginx/sslcert/www.pem;
    ssl_certificate_key /website/nginx/sslcert/www.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;

    server_name www.huanggefan.cn;
    root /website/www.git/public;
    index index.html;

    access_log /website/log/www-access.log main;
    error_log /website/log/www-error.log;

    location ~* \.(jpg|jpeg|png|icon|bmp|gif|tty|js|css)$ {
        access_log off;
        log_not_found off;
    }

    error_page  404 403 500 502 503 504  /404.html;
}

使用内存进行加速

Hugo 默认会把构建的静态网站文件放到 public 目录下,我觉得这样挺好的,也没有更改路径。Ubuntu 有一个特性,就是 /dev/shm 其实是个目录,而且,是在内存里的一个目录,这个目录有内存的一半大。所以,我就直接在这里创建一个目录,通过软链接,链接到 public。这样,public 其实就在内存里了。Hugo 也就是把静态网站文件放到了内存里了。

阿里云 ECS 的磁盘性能不是很好,不过内存性能很好,这样算是进行了最大化的性能优化。

Linux环境指定动态链接库路径

目标

我们的目的是:链接这个动态链接库,并放在可执行文件目录下,使可执行文件执行时能找到这个库。

当然。我们最终应该可以将动态链接库放在任何位置,同时保证我们的可执行文件可以找到这些动态链接库。

这对我们组织、打包整个项目相当有帮助。你可以使用命令: ldd <可执行文件名> 看看可执行文件所链接的动态库,及其路径。

创建动态链接库

gcc -shared -fpic x1.o x2.o x3.o -o libqazwsx.so

上面这条命令将 x1.o、x2.0、 x3.o 三个文件打包成一个动态链接库文件 libqazwsx.so

指定位置

下面是我们的核心编译命令

gcc test.o -o test -Wl,-rpath,./ -L./ -lqazwsx

这条命令会告诉可执行文件,他需要的动态链接的位置,这个是我们创建的实验文件目录。

.--test
|-------test.c
|-------x1.c
|-------x2.c
|-------x3.c
|-------test.o
|-------x1.o
|-------x2.o
|-------x3.o
|-------libqazwsx.so

命令解释

现在我们已经有了一个指定了链接位置的动态链接库,来详细解释一下这条命令。

test.o -o testtest.o 与动态库链接并输出可执行文件 test

-Wl,-rpath,./ 告诉链接器,test 在执行时应当在 ./ 下找动态库

-L./ -lqazwsx 告诉链接器,链接时在 ./ 下找动态库

测试代码

// x1.c
#include <stdio.h>
void print_x1 (void) {
    printf("I am x1.o\n");
}
// x2.c
#include <stdio.h>
void print_x2 (void) {
    printf("I am x2.o\n");
}
// x3.c
#include <stdio.h>
void print_x3 (void) {
    printf("I am x3.o\n");
}
//test.c
#include <stdio.h>
extern void print_x1 (void);
extern void print_x2 (void);
extern void print_x3 (void);
int main (void) {
    print_x1();
    print_x2();
    print_x3();
    printf("I am main function\n");
    return 0;
}

这里是完整的编译指令

gcc -c x1.c
gcc -c x2.c
gcc -c x3.c
gcc -c test.c
gcc -shared -fpic x1.o x2.o x3.o -o libqazwsx.so
gcc test.o -o test -Wl,-rpath,./ -L./ -lqazwsx

执行测试

# ??? @ ??? in ~/workspace/cpp [19:18:35]
$ ./test
I am x1.o
I am x2.o
I am x3.o
I am main function

# ??? @ ??? in ~/workspace/cpp [19:18:39]
$ ldd test
linux-vdso.so.1 (0x00007fff755fd000)
libqazwsx.so => ./libqazwsx.so (0x00007f9708264000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9707ea2000)
/lib64/ld-linux-x86-64.so.2 (0x0000564acd3d3000)

# ??? @ ??? in ~/workspace/cpp [19:22:57]
$ rm libqazwsx.so
rm:是否删除普通文件 'libqazwsx.so'?y

# ??? @ ??? in ~/workspace/cpp [19:23:04]
$ ./test
./test: error while loading shared libraries: libqazwsx.so: cannot open shared object file: No such file or directory

# ??? @ ??? in ~/workspace/cpp [19:23:07] C:127
$ ldd test
linux-vdso.so.1 (0x00007ffda6fdb000)
libqazwsx.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f702f741000)
/lib64/ld-linux-x86-64.so.2 (0x000055c80d664000)

可以看到,我们创建的动态链接库放在了可执行文件的同级目录下,这时可执行文件可以找到这个动态链接库。当我们删除了这个库时,可执行文件就因为找不到链接库而无法运行了。

总结

现在,我们知道了指定动态链接库到可执行文件的同级目录下,换言之,我们也可以将库放到其他位置。这样我们可以做到系统的模块化。不同功能的代码封装到不同的动态链接库中,这样可以做到系统的热更新。

Linux内存JDK

目的

把 JDK 放到内存里是个好想法。可以加速 JDK 的调用。而且,我的电脑是固态硬盘,频繁的读写硬盘,会减少固态寿命。所以,我要把 JDK 扔到内存里。不过,固态其实已经很快了,即使把 JDK 放到内存里,速度的提升也感觉不到。

安装工具

# 安装 squashfs-tools
sudo apt install squashfs-tools

# 安装 openjdk
sudo apt install openjdk-8-jdk openjdk-8-jre

squashfs-tools 这个工具可以创建 squash 文件系统,将整个文件系统或者某个单一的目录压缩在一起, 存放在某个设备, 某个分区或者普通的文件中。

我们要做的就是,把 openjdk 的目录压缩到一个文件里,然后挂载到内存里。感觉就是把 JDK 打个包,变成镜像文件,然后挂在到内存。

做些准备

注意:由于 openjdk 的目录里 docs、src.zip 是链接符号,所以我们要先把他们替换成真正的文件。

# 把整个jdk目录复制到主目录下。
sudo cp -r /usr/lib/jvm/java-8-openjdk-amd64 ~/

# 替换文件链接符号为真正的文件
sudo rm -rf ~/java-8-openjdk-amd64/docs ~/java-8-openjdk-amd64/drc.zip
sudo cp -r /usr/share/doc/openjdk-8-jre-headless/ ~/java-8-openjdk-amd64/docs
sudo cp /usr/lib/jvm/openjdk-8/src.zip ~/java-8-openjdk-amd64/src.zip

创建 JDK 镜像

# 创建 squash 文件系统文件
sudo mksquashfs ~/java-8-openjdk-amd64 ~/openjdk-8.sqsh

# 移动到 /usr/lib/jvm 下
sudo mv ~/openjdk-8.sqsh /usr/lib/jvm/

挂载

# 创建目录以供挂载
sudo mkdir /media/memory-jdk-8

修改 /etc/fstab 文件,添加类似以下的一行:

/usr/lib/jvm/openjdk-8.sqsh  /media/memory-jdk-8  squashfs  ro,defaults,loop  0 0

完成。

Nginx代理城市热点

情景说明

学校部署了城市热点的服务,但是,领导不想让学生看到服务器的 IP,想给服务一个域名。但是,服务部署在 8080 端口。领导也不想让学生看到端口。

城市热点的人员考虑采用重新部署应用的方式,不过,似乎他用了很长的时间也没有搞定。然后我就里所应当的用了他从学校那里申请的虚拟机了。

嘛,虚拟机不是给我玩的,我的方案是采用 Nginx 进行反向代理。随便加上缓存、限速啥的。

在 CentOS 上安装 Nginx

在 CentOS 上安装 Nginx 可真麻烦,也许是虚拟机的 CentOS 版本太旧。反正没有 Debian、Ubuntu 用的舒服。

使用以下命令进行安装:

yum install -y nginx

恭喜,这是不可行的。你会被提示没有 Nginx 这个包。如果你不甘心,使用了以下命令:

yum search nginx

你会发现根本没有 Nginx,即使你随便安装了一个长的比较像的,也是不对的。

你要在 /etc/yum.repos.d 下添加一个 nginx.repo 文件,里面的内容如下:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

然后就可以开心的执行安装命令了。

yum install -y nginx

配置代理

这里直接贴上我的配置文件,我是不是泄露了一些信息。嘛,我也不担心你会渗透到服务器里,反正是学校内网,你又进不来。除非你也是安农的。话说,自己人黑自己人有意思吗。

server{
    listen 0.0.0.0:80;
    listen [::]:80;
    server_name ss.ahau.edu.cn;

    proxy_set_header Host $host:$server_port;
    proxy_set_header Remote_Addr $remote_addr;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Access-Control-Allow-Origin *;
    proxy_http_version 1.1;
    add_header Access-Control-Allow-Origin *;

    location / {
        access_log off;
        log_not_found off;
        rewrite ^.*$ http://ss.ahau.edu.cn/Self/;
    }
    location ~* \.(css|js|png|jpg|jpeg|ico|icon|gif) {
        access_log /var/log/nginx/access-static.log;
        error_log /var/log/nginx/error-static.log;
        proxy_cache web;
        proxy_cache_valid 200 304 7d;
        proxy_cache_valid 404 500 10m;
        add_header ProxyCache "$upstream_cache_status";
        proxy_pass http://114.213.145.00:8080;
    }
    location ~^/Self/login/verify$ {
        access_log /var/log/nginx/access-login.log;
        error_log /var/log/nginx/error-login.log;
        proxy_pass http://114.213.145.00:8080;
    }
    location ~^/Self.*$ {
        access_log /var/log/nginx/access-other.log;
        error_log /var/log/nginx/error-other.log;
        proxy_pass http://114.213.145.00:8080;
    }
}

我在这里配置缓存,除了缓存、日志那里我明白一切,其他部分感觉都有问题。但是,只有这样它工作了,如预期一般工作了。你可以进行各种更改尝试,反正只有这样写,location 的顺序也是这样的,它才会工作。

配置缓存

配置缓存,将各种静态文件缓存到虚拟机里,而且缓存到虚拟机的内存里。没错,内存里,内存大就是可以为所欲为。

不仅可以加速学生的访问,而且可以非常明显的减少真实服务器的压力。虽然它的抗压能力估计比虚拟机更好。

proxy_temp_path /var/lib/nginx/cache_temp;
proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=web:200m max_size=900m inactive=7d;

上面的一段要在 http 字段里设置,然后在 http 字段里的 server 下进行如下配置

proxy_cache web;
proxy_cache_valid 200 304 7d;
proxy_cache_valid 404 500 10m;
add_header ProxyCache "$upstream_cache_status";
proxy_pass http://114.213.145.00:8080;

配置限速

配置限速是为了防止有人进行大规模的密码爆破行为。因为城市热点的系统传输数据没有加密。没有加密不仅意味着可以进行嗅探,还可以进行密码爆破。一旦这个系统的密码被破解了,校园网的密码也就被破解了。这是绝对不能发生的。

嘛,估计没人会这样做,除了我……

limit_conn_zone $binary_remote_addr zone=proxy_conn:10m;
limit_conn proxy_conn 8;
limit_rate 200k;
limit_rate_after 10m;

不知道为啥,只能限制每个 IP 的连接数,不能限制并发数。一旦限制并发数,页面就无法加载。

踩坑

proxy_set_header Host $host:$server_port;

Nginx 代理的下游服务器,收到的 HTTP Header 里的 host 字段,需要是用户浏览器发送的。

这一行不加,就会变成 114.213.145.00:8080,但是,它不认啊,估计是服务器上跑了不少东西。

Nginx反向代理Google

情景简述

国内用不了 Google 对吧,但是,作为程序员必须要用 Google 对吧(当然,百度啥的也能用,就是有点难用)。所以,咋办呢。

翻墙。不管用什么方法翻墙,总要花钱的对吧。免费的 VPN 一点也不稳定。租国外的服务器,自己搭建 VPN 服务器,你确定,你愿意花那么多钱就为了翻个墙。

所以呢,我有一台服务器对吧,阿里云的 ECS。然后呢,我已经让它支持 IPv6 对吧。然后,之前在给 ECS 配置 IPv6 时,已经确定,在国内,可以使用 IPv6 ping 通 Google 的。那么,使用 IPv6 访问 Google 呢。

分析思路

现在我们已经确定。使用 IPv6 可以访问 Google,那么我们的策略是:本地电脑访问 ECS 的 Nginx 代理,ECS 使用 IPv6 访问 Google,然后将结果返回给本地电脑。

这不就是反向代理吗,Nginx 不是经常这样用吗。平时用 Nginx 反向代理内网的服务,这次是代理外网的而已,都一样嘛。

操作方法

编辑 /etc/nginx/conf.d/ 下的配置文件,我们创建一个 google.conf,添加如下配置

upstream google {
    server [2404:6800:4012:1::2004]:443;
}
server {
    listen 0.0.0.0:80;
    listen [::]:80;

    server_name xxx.xxx.xxx;
    proxy_set_header Host www.google.com.hk;
    proxy_set_header x-forwarded-for $remote_addr;
    location /{
        proxy_pass https://google;
    }
}

首先,我们在 upstream google 字段,配置了一个名为 google 的上游服务,这里把上游服务器指向 Google 服务器的 IPv6 地址,由于 Google 使用了 https 所以,要指定 443 端口。也就是说,所有发向 google 这个上游代理的数据,都会发向 2404:6800:4012:1::2004 的 443 端口。也就是说,我们把上游代理设置成了 Google 的服务器,有点不厚道。

然后,在 server 字段那里,配置了 nginx 的一个监听服务。它会监听 IPv4 和 IPv6 的 80 端口,然后把所有的数据都发向 google 这个上游代理。如果你想使用 https,请添加 ssl 支持。

注意

server_name xxx.xxx.xxx;

这一行,请把 xxx.xxx.xxx 换成你的服务器域名或 IP。

proxy_pass https://google;

这一行,表示,转发所有的数据到 google 这个上游代理。

然后 service nginx restart 吧。

后记

学习结束。

阿里云ECS开启IPv6

情景说明

首先说明我们要干什么:我们要让自己的网站支持 IPv6,谁让国家给 IPv6 下了文件呢。我们要确保,用户可以在 IPv6 网络环境下无障碍的访问我们的网站。

然后说明我们的系统环境:服务器是阿里云的 ECS,操作系统是 Ubuntu。我们用的是万网的域名解析。阿里一家的嘛。

获取 IPv6 地址

可以从 Tunnel Details 获取 IPv6。你需要注册一个账号,这没啥好说的。注意,你需要一个公网 IPv4 地址。然后,你就可以用一个公网 IPv4 领取到你的 IPv6 了。

阿里云ECSIPv6-1.png



阿里云ECSIPv6-2.png

配置 ECS 系统参数

现在配置系统参数,启动 IPv6。

修改 /etc/sysctl.conf (注意备份)更改如下,把这三个参数改为 0 就可以了:

net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0

配置 ECS 网络

下面就是配置你的 ECS 让它使用 IPv6 地址了(注意,这里用的是 Ubuntu 系统,阿里云支持其他的 Linux 操作系统,请自行调整)。

只要使用 Tunnel Details 给出的示例配置,稍加修改就好。看到给的那段英文提示没,注意,local 那里要填你的 ECS 的内网 IPv4,不是公网的哦。然后添加到你的 /etc/network/interfaces 文件里(注意备份),需要修改的也就只有 local 那里了。

阿里云ECSIPv6-3.png



阿里云ECSIPv6-4.png

配置 Nginx 监听 Ipv6

现在配置 Nginx,监听 Ipv6 请求

server {
    listen 0.0.0.0:80;
    listen [::]:80;
    …………
    …………
}

把监听参数改成这个,就可以同时监听 IPv4 和 IPv6 了: 想使用 https 就使用 ssl 监听 443 端口呗,这个和本文没啥关系。 使用 Apache 的嘛,…………

配置 IPv6 DNS 解析

添加一条 AAAA 记录,没啥好说的吧,至于你的公网 IPv6 地址是啥,重启 ECS 后使用 ifconfig 命令看看呗,肯定和你的 /etc/network/interfaces 里配置的 address 一致的。当然,这个 address 肯定也和你申请 IPv6 时的“Client IPv6 Address”一致的。

踩坑:IPv6 无法访问

注意,当你重启 ECS 后,应该可以看到自己的 IPv6 已经启动了,使用 ifconfig 命令查看。然后你在你的 ECS 里使用 ping6 命令去 ping6 ipv6.baidu.com 应该是可以的,但是嘛……

估计你是不能用自己的电脑 ping6 同你的 ECS 的,也是不能用 IPv6 访问到你的网站的,那么其他使用 IPv6 的用户也不能访问你的网站喽。(ping6 不同的一部分原因估计是你的电脑没 IPv6 地址)

要知道,阿里云的安全组规则不是假的。阿里的安全组规则虽然很好用,但它不支持 IPv6 啊,管你什么协议,什么端口,只要是 IPv6 的全禁了。所以,你只能添加一条入方向的规则:“允许所有的协议,所有的端口,所有的访问来源通过”,然后,嗯,其他的规则还需要存在的意义就有点尴尬。这个希望阿里云能解决一下。

博客迁移

第一次写博客

记得第一次写博客还是因为 CDDA 大灾变。当初为了玩这个游戏,花了一天的时间折腾。毕竟 makefile 我用的一直都不熟,我一直都是把 makefile 当作 shell 脚本来写。

在安装这个游戏时,被逼看了大概 500行 makefile 代码。这次应该是我第一次大量的阅读别人的代码。

虽然,我直到现在,依然写不好 makefile,不过,让我看懂一个 makefile 干了啥,还是很轻松的。

从那此开始,我就开始了写博客。写博客最初的目的就是当个记事本,方便日后,有的东西忘了,可以快速找到。这时,我应该是高三,高考最大嘛。于是,就写了几篇,就没在写过了。

这个时候,我的博客都在开源中国上面。

迁移到 Wordpress

大一入学时,买了一台阿里云的 ECS,还买下了 huanggefan.cn 这个域名,嗯嗯嗯,我自己的名字嘛。花了一个月的时间备案了域名,这个域名算是正是开通了。不过,我一直都没有开始部署博客,服务器上唯一的应用是我给学校写的网络报修系统。

到了大一下学期,我部署了 Wordpress。这时,我开始决定,运营一个自己的网站。写博客不再只是记日记了,我决定写一些对自己对别人都有用的内容。

奈何,Wordpress 写作体验确实不如 Markdown。而且,从部署了 Wordpress 我就开始折腾 Wordpress。改主题、安全配置、漏洞填补啥的。博客反而没写几篇。

迁移到 Hugo

现在,我把博客迁移到了 Hugo。还是 Markdown 写的舒服。纯静态网站安全性肯定比 Wordpress 高,性能就不用说了。最重要的是:部署简单、写作体验很棒。

Hugo 的部署真的很简单,直接使用 Nginx 就好。如果想进一步追求性能,可以把 public 目录挂载到 tmpfs。Ubuntu 自带了一个 /dev/shm,在这里面创建目录,然后使用软链接即可。都不用更改 /etc/fatab 文件。

Hugo 生成的静态网站的发布我选择了 Git。本地电脑通过 Git 推送到服务器端,然后 ssh 到服务器,手动执行构建命令。其实这样也不麻烦,没必要写一个自动脚本。ssh 后还可以看看访问日志。当然,直接使用 scp 更简单一些,不过使用 Git 给了自己一个后悔选项不是吗。

未来

说到未来,这个真的很难确定,也许以后还会迁移,不过,以后再迁移,也是换个静态网站生成器罢了,也许我会用 Python 写一个。Hugo 虽然已经很好用了,但是还是满足不了我的所有需求。

现在使用的时别人写的 Hugo 主题,虽然进行了不少修改,不过感觉还是自己写一个更合适。

静态链接Ncurses

情景描述

平时调用各种 C 库时,免不了各种链接。记得当初学习 C 语言时,为了使用 math 库,可没少折腾。Ncurses 作为一个字符终端的图形库,是相当实用的。不过,并不是所有的用户都会在他的系统上安装这个库,所以,我们可以考虑把 Ncurses 包含到我们的程序里。这就是静态链接。

先简要说明一下静态链接和动态链接。无论是静态库文件(.a)还是动态库文件(.so),都是二进制文件。不同的是,当我们的程序进行静态链接时,是直接把静态库文件给包含进程序里了。而动态链接不会这样做,程序会在运行时,加载库文件,同时,一个动态库文件,可以被多个程序共享加载。换言之,静态链接,是每一个程序都包含了库文件,动态链接是多个程序从同一个库文件共享代码。

显然,动态链接可以减小程序文件的大小,而且节约内存。毕竟一个库只需要加载到内存一次,其他程序使用时,不需要再次加载。而且程序本身并没有包含库文件,所以程序文件不会很大。但是,如果用户的系统没有这个库,就完了。程序就无法运行了。

静态链接就可以避免用户没有安装依赖库的问题。程序通过直接包含库文件,使得程序在加载到内存时,已经加载了库文件。但是,这种做法,会使程序文件比较大,而且,由于每个程序加载时,都加载了库文件,如果这些程序依赖同一个库,必然会造成内存浪费。不过,这样做不必考虑依赖问题,可以确信程序在用户那里能运行。

啰里啰嗦写了一堆不相关的,算是说明了为啥要静态链接 Ncurses,现在进入重点,如何静态链接。当然,你的系统肯定是要已经安装了 Ncurses 的,注意,不只是运行环境,还有开发环境。

安装开发环境

注意,这里是针对 DEB 系的 Linux 系统,Ncurses的版本是 5

sudo apt install libncurses5-dev ncurses-doc

测试代码

我们写一段测试代码,代码就放在主目录下吧。

// test.c
#include <ncurses.h>

int main(void) {
    initscr();
    printw("Hello world\n");
    refresh();
    getch();
    endwin();
    return 0;
}

常规链接

我们使用常规的编译指令,也是动态链接,编译一下。

gcc test.c -o test -lncurses

我们使用 ldd 命令查看生成的可执行文件的依赖

# xxx @ xxx in ~ [12:52:45]
$ ldd test
    linux-vdso.so.1 (0x00007ffd8990a000)
    libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007f69d5891000)
    libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f69d5667000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f69d52c8000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f69d50c4000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f69d5cb6000)

静态链接

现在我们使用静态链接,注意指令的链接依赖顺序。

gcc test.c -o test -static -lncurses -ltinfo

注意,先链接 ncurses(-lncurses),然后是 tinfo(-ltinfo)。下面是 ldd 命令的输出。

# xxx @ xxx in ~ [12:55:13]
$ ldd test
    不是动态可执行文件

由于我们使用了静态链接,所以,可执行文件 test 里包含了所有的动态库的静态库版本。也就是,test 里包含了 linux-vdso、libncurses、libtinfo、libc、libdl 这些库。

现在的可执行文件 test 可以在一个没有安装 ncurses 的系统上运行了。

中文支持

如果你想使用 Ncursesw 来支持中文等字符(当然你要安装 ncursesw 对吧),可以参考如下。

// test.c 支持中文
#include <ncurses.h>
#include <locale.h> //setlocale()函数

int main(void) {
    setlocale(LC_ALL,""); //使用本地字符集
    initscr();
    printw("Hello world.\n");
    printw("打得好的.\n");
    refresh();
    getch();
    endwin();
    return 0;
}

编译指令:

gcc test.c -o test -static -lncursesw -ltinfo

SSH 隧道

考虑到在宿舍无法直接访问工作室的网络环境,只能折腾一下各种隧道。

本地端口转发

发送到本地主机端口的请求,转发到远程主机端口

命令:-N -L 本地地址:本地端口:远程地址:远程端口

ssh -N -L 127.0.0.1:8080:101.101.101.101:443 www@101.101.101.101 -p 22

发送到 127.0.0.1:8080 的数据包会被转发到 101.101.101.101:443

远程端口转发

发送到远程主机端口的请求,转发到本地端口

命令:-N -R 远程地址:远程端口:本地地址:本地端口

ssh -N -R 101.101.101.101:443:127.0.0.1:8080 www@101.101.101.101 -p 22

发送到 101.101.101.101:443 的数据包会被转发到 127.0.0.1:8080

动态端口转发

命令:-N -D 本地地址:本地端口

ssh -N -D 127.0.0.1:8080 www@101.101.101.101 -p 22

发送到 127.0.0.1:8080 的数据包,由 101.101.101.101 转发到目的地

Chromium参考:SwitchyOmega

参数列表

  • -N 不执行何指令
  • -L 建立本地到远程的隧道
  • -R 建立远程到本地的隧道
  • -D 建立本地到远程的V动.态P隧.道N

建议参数

  • -f 后台执行
  • -o TCPKeepAlive=yes 确保链接长时间闲置不会被断开