分类目录归档:IT

关于近期出现的大量公网 libtorrent BT 客户端的问题

经确认,如果 IP 来源为 CN,且客户端类型汇报为 libtorrent 这个库而非其他正常客户端的 peer,既有可能是迅雷等下载软件的离线客户端。对于一部分同样表现的海外 IP 暂时未能确认,不确定是否有一些极小众的客户端表现确实如此,对于此问题,在 qBittorrent 增强版未作修改之前,建议采取 ipfilter 的方式屏蔽这些客户端。

IP Filter 来源如下:https://emulefans.com/offline-server-ip-170205/

也可以直接下载

关于 qBittorrent 编译的一些问题

您可能是开源软件的受害者!

您可能是开源软件的受害者!

您可能是开源软件的受害者!

重要的事情说三遍。

实际上这次也没做什么理论上很麻烦的事情,就是 clone 一个 qBittorrent 4.0.4.3 的源码,配合 libtorrent 1.0.11 编译一下,理论上不应该有什么问题的对吧。然而就是出问题了……

编译的过程很顺利,安装 Deluge PPA 的 libtorrent-rasterbar-dev 和一些 boost 库之后开始编译,然后到了 linking 的过程就报错了:src/base/bittorrent/private/filterparserthread.cpp:99: reference to `boost::asio::ip::address_v4::address_v4(std::array<unsigned char, 4u> const&)'

按照 GitHub Issue #6721,这个问题可能是因为 std::arrayboost::array 这两个名称的选择在 libtorrent 和 qbittorrent 里面不同,在没有使用 stdc++11 编译的时候,使用的是 boost::array,反之使用 std::array,考虑到 qbittorrent 默认需要 C++ 11,所以 libtorrent 应该使用同样的 CXXFLAGS 编译才能在 linking 的时候不报错。因此既然出现了现在这个问题,就证明 Deluge PPA 的 libtorrent 是没有使用 C++11 编译的。

之前在编译 qb 3.3.16 的时候并没有出现这个错误,可能是 qb3 不要求 C++11 的原因。

那么如果要解决这个问题,就必须从源码开始编译 libtorrent。考虑到 lt1.1.x 至今无法解决 U2 的双栈 IP 汇报问题,因此只能采用 lt1.0。

git clone https://github.com/arvidn/libtorrent.git
cd libtorrent
git checkout $(git tag | grep libtorrent-1_0_ | sort -t _ -n -k 3 | tail -n 1)
./autotool.sh
./configure --disable-debug --enable-encryption --with-libgeoip=system CXXFLAGS=-std=c++11

在编译完成之后,checkinstall 安装,然后再去编译 qb 就应该可以了。

关于 Boost 版本

Boost 版本的选择也有一些讲究,Ubuntu Package 默认的是 1.58 版本的 boost,qb 经过测试,最高只能使用 1.65.1 版本的 boost,如果想要使用新一些的版本,只能自己编译。

我在编译 1.65.1 的时候,遇到了一个以前从来没有的问题,找不要 pyconfig.h,这个文件本应该存在于 /usr/include/python 或者 python2.7 或者 python3.5 的目录下(取决于默认 Python 版本),但是我那个 Python 2 就是没有这个文件,因此将 Python 默认改为 3.5(sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 10)才让 boost 的编译器找到对应的 Python 头文件。如果出现这样的问题需要注意。

使用 echo -e '#include <boost/version.hpp>\nBOOST_VERSION' | gcc -x c++ -E - 这个命令可以查看当前 include 的 boost 版本。

Python 版本切换的注意点

如果安装了 Deluge,然后再切换到 Python3,可能会让 Python 找不到 Deluge 的包,然后无法运行,解决方法是修改 /usr/bin/deluged 和 /usr/bin/deluge-web 的第一行,用 python2.7 运行。或者也可以编译完 boost 以后再把默认 python 改回来。

 

Syncthing 配合 Nextcloud 搭建私有云

写在前面

首先感谢 youlun 大佬介绍了 Syncthing 这个好用的文件同步工具,一次性解决了 Nextcloud 同步残废的问题。

有人可能会问,Nextcloud 不就已经可以搭建私有云平台了吗,为什么还要借助 Syncthing 这样一个同步工具呢?如果文件量不大的话,可能这并不是什么大问题,但是由于 Nextcloud 即使是使用它的客户端,也只能通过网页方式上传,在遇到较大的文件的时候,就会遇到各种各样的限制,比如上传超时或者是文件过大不能上传等等。但是 Syncthing 就不存在这样的问题,可以顺畅地进行文件同步。那么,有没有办法让二者配合工作,即 Syncthing 负责文件同步,Nextcloud 负责网页端的界面和移动端访问的功能呢?答案是有的,而且非常可行,考虑到没有现成的教程,因此在这里记录一下。

LNMP 环境部署

WebServer 环境依然使用了 LinuxEye 的 LNMP 一键包,需要注意的问题是 PHP 选择 7.1 版本(Nextcloud 13.0.1 的依赖),以及需要通过 addon.sh 安装 fileinfo 这个 PHP 模块。

Nextcloud 安装

在部署完成环境之后,添加一个 nginx vhost,现在最新版的一键包中已经加入了 Nextcloud 的 Rewrite Rule,这个给我们的安装带来了极大的方便,再也不用去折腾那些重写规则了。

然后需要调整一下 Zend OPcache 的设置,不然在下载源码之后无法进入配置。具体步骤为在 /usr/local/php/etc/php.d/ 文件夹中找到 opcache 的 .ini 配置文件,将里面的数值按照如下的错误信息调整:

之后在官网下载 tar.bz2 的安装包,解压之后拷贝进 wwwroot,注意这里需要将所有的文件权限改为 www:www,默认一般是登录的用户,会造成无法访问,之后在 MariaDB 中创建一个数据库,在初始化的时候填进 Nextcloud 中,这一步还是比较方便的。

然后更改一下 Nextcloud 的配置,消除缓存的警告。在 <site root>/config/config.php 中添加如下字段即可:

'memcache.local' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => array(
   'host' => 'localhost',
   'port' => 6379,
),

至此 Nextcloud 应该就可以正常使用了。

Syncthing 的配置

首先需要安装 Syncthing,官方文档中给出了 Ubuntu .deb 的链接,按照它配置即可。

这时候就会遇到一个问题,Syncthing 需要以 www 用户启动才能在和 Nextcloud 一同工作时避免一些权限的问题,但是 www 用户默认是 nologin 配置的,如何登陆进这个用户完成一些初始的设置是一个比较麻烦的问题。由于 www 用户无法登录,所以不能使用一般的 su <user> 来进行用户切换,以该用户的权限启动一个 bash 又不能完成完整的用户环境切换操作。在搜索之后,以一种比较 Tricky 的方法登录了进去:

su -s /bin/bash www

这条命令的意思是 override www 默认的 shell,再登录,然后就会发现你已经切换到 www 用户下了。运行 syncthing,该做什么做什么。

Nginx 反代

Syncthing 默认监听 localhost:8384 端口,那么在远端 VPS 上,如何进行配置呢?有两个方案,一个是修改监听端口,让程序监听 0.0.0.0:8384,另外一个是通过 nginx 配置一个反代。显然,第二个方案无论是在安全性,还是便利性(不用在域名后面输入端口号)上都优于第一个,所以我们就采用第二个方案。

Nginx 配置文件的关键部分如下:

server {
  listen 80;
  listen 443 ssl http2;

  if ($ssl_protocol = "") { return 301 https://$host$request_uri; }

  location / {
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host localhost;
          proxy_set_header X-NginX-Proxy true;
          proxy_pass http://localhost:8384;
  }
}

需要注意的一点就是 proxy header 中的 Host 字段必须改为 localhost,否则 Syncthing 发现你的访问地址不是它的监听地址,就会拒绝访问,返回“Host check error“。

之后就是正常的 Syncthing 使用,这个不难,看官方文档就可以了。

Syncthing 和 Nextcloud 配合工作

一开始我以为,把 Syncthing 的同步文件夹设置为我的 Nextcloud 的数据目录就可以完成同步,实际上 Nextcloud 的文件列表并不是实时的,需要运行 OCC 重新进行扫描,但是这样的扫描并不能保证数据完全无损,而且在使用时也不可能频繁 SSH 上去进行重扫,因此必须采取其他的方法。

关于这个问题,官方给出的答案是 External Storage,在 Nextcloud 中启用 External Storage 这个组件以后,在设置中挂载外部的文件夹,这个可以是本地,也可以是 SFTP/FTP/Amazon S3/WebDAV 等等,在这个情况下,我们选择本地,然后添加对应的文件夹就可以在 Nextcloud 文件列表中看到我们的文件了,无论是网页版还是手机都可以。

Syncthing 自动启动

在 Ubuntu 上,我们通过 systemd 服务来完成:

[Unit]
Description=syncthing
After=network-online.target

[Service]
ExecStart=/usr/bin/syncthing -no-browser -home="/home/www/.config/syncthing"
ExecStop=/bin/kill -9 $(/bin/cat /run/syncthing.pid)
Restart=always
PIDFile=/run/syncthing.pid
TimeoutStopSec=300
User=www

[Install]
WantedBy=multi-user.target

在 Windows 上,我们可以通过这样一个 .bat 完成启动:

start "Syncthing" syncthing.exe -no-console -no-browser

参考资料

https://docs.syncthing.net/
https://docs.nextcloud.com/server/13/admin_manual/
https://serverfault.com/questions/333321/executing-a-command-as-a-nologin-user
https://www.jianshu.com/p/4235cc85c32d

Ubuntu HWE Kernel 与 Linux CPU Frequency Scaling

其实 HWE Kernel 和 Frequency Scaling 是两个东西,只不过频率调节的工具是 Kernel 里面的一个组件,我因为没找到对应的 meta-package 而没有安装上正确的版本,然后发现是 HWE Kernel 和 GA Kernel 的不同版本造成的,所以想着干脆一起写篇东西解释一下这些东西的不同。

HWE Kernel

首先要说一说的是 HWE Kernel,按照官网的说法,是为了让 LTS 的 Linux 系统能够迅速支持最新的硬件,所以才命名为 HWE (HardWare Enable)。实际在使用过程中,可能也是我经验不足的原因,没碰上什么硬件太新 Kernel 不支持造成的 bug,所以这个名字怎么定义的其实意义不大。

在使用 Ubuntu 的过程中,应该都会遇到这样一种情况,Ubuntu 会帮我们自动更新内核,在 LTS 版本的 Roadmap 中,我们也可以看到不同的 point release 对应了不同的内核版本,比如 16.04.4 LTS 对应的就是 4.13 的内核。但有的时候,我们会发现,明明自己的系统已经是 16.04.4,为什么内核还是 4.4 版本呢?这是因为 HWE kernel 和 4.4 这样长期支持的 GA Kernel 其实是两个 meta-package,GA Kernel 对应的包是 linux-generic,下有 linux-image-generic 和 linux-headers-generic 这两个包,再往下才是具体的内核包。如果想要跟随 point release 更新系统的内核,那么就应该安装对应的 HWE 内核,HWE 内核是和 LTS 版本绑定的,比如 16.04 就需要加上 -hwe-16.04 后缀,那么对应的内核包就是 linux-generic-hwe-16.04,下面的包是 linux-headers-generic-hwe-16.04 和 linux-image-generic-hwe-16.04。使用这个包,就能安装最新的 4.13 内核(LTS 16.04.04)。

除了普通的 HWE 内核之外,还有一个更加激进的更新版本是 Rolling HWE Stacks,将上面的 -hwe-16.04 换成 -hwe-16.04-edge 就可以使用到这个 Stack。在这个 Stack 中可以提前使用 下一个 point release 中使用的 HWE 内核版本,就有点类似于 beta 测试的分支,这个可能会存在一定的稳定性问题,所以是否使用请自行斟酌。

CPU Frequency Scaling

接下来要说一说的是 CPU 频率调节的问题,在 Windows 上很多人应该都使用过的一个功能是电源方案,里面对 CPU 的最大频率、最小频率,散热方式等等可以做出一些自定义设置,Linux 上同样也提供了这样的功能。

在 Arch Wiki 中,对于这个问题有比较详细的介绍,在这里就简单地说一说:Linux 内核有自己的 CPU 调频实现,称为 cpufreq,这个在 3.4 的内核之后,必要的模块都会自行加载,用户也可以通过一些工具实现自己的调节。

CPU 频率的驱动程序随着 CPU 型号的不同会有很多的版本,具体可以查看 Arch Wiki 上面的说明,对于现在使用的 SandyBridge 以后架构的 CPU,通常使用 intel_pstate 来对频率进行调节。可以通过如下命令来查看 pstate 是否已经启用:

$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_driver

如果显示的都是 intel_pstate,那么你的 CPU 调节使用的就是 p-state 驱动。

CPU 频率的手动调节通常使用 cpupower 这个工具,可以通过如下的命令安装(需要和内核版本一直,这里使用 HWE Kernel 对应的版本):

$ sudo apt-get install linux-tools-common linux-tools-generic-hwe-16.04

之后运行 $ cpupower frequency-info就可以看到 CPU 的信息,大概是这样的输出:

$ cpupower frequency-info
analyzing CPU 0:
  driver: intel_pstate
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency:  Cannot determine or is not supported.
  hardware limits: 1.60 GHz - 3.90 GHz
  available cpufreq governors: performance powersave
  current policy: frequency should be within 1.60 GHz and 3.90 GHz.
                  The governor "performance" may decide which speed to use
                  within this range.
  current CPU frequency: Unable to call hardware
  current CPU frequency: 3.70 GHz (asserted by call to kernel)
  boost state support:
    Supported: yes
    Active: yes
    3700 MHz max turbo 4 active cores
    3800 MHz max turbo 3 active cores
    3900 MHz max turbo 2 active cores
    3900 MHz max turbo 1 active cores

可以发现,信息比我们从 Windows 上面获取的要多得多,不仅可以看到当前的频率,还能看到最大睿频的信息。

Scaling Governors

Scaling Governor 相当于预设的 CPU 电源方案,在文档中有 6 种不同的调速器,但是在实际使用中,通常只有 performance 和 powersave 两种。performance 相当与强制 CPU 运行在最高频率,而 powersave 可以让 CPU 按需自动调节频率。当前在使用的调速器可以通过如下命令查看:

$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

通常来说默认配置是 powersave 模式,如果想调整为 performance,可以执行如下的命令:

$ sudo cpupower frequency-set -g performance

之后再进行查看,应该就是 performance 模式了,CPU 也会被固定在最大睿频上。

固定 Governor 不被修改

直接使用 cpupower 修改之后会存在一个问题,重启之后会被修改回 powersave,可以安装 cpufrequtils 将其固定:

$ sudo apt-get install cpufrequtils
$ sudo systemctl disable ondemand

一定要将 ondemand 这个服务关闭,这个服务会将 governor 设置为 ondemand 模式,但是通常 CPU 都不支持这个模式,然后就会 fallback 到 powersave。

之后在/etc/default/cpufrequtils中添加GOVERNOR="performance",重启即可。

Reference

https://wiki.archlinux.org/index.php/CPU_frequency_scaling_(简体中文)

https://wiki.ubuntu.com/Kernel/LTSEnablementStack

https://wiki.ubuntu.com/Kernel/RollingLTSEnablementStack

http://www.webupd8.org/2014/04/prevent-your-laptop-from-overheating.html

Cisco IOS 命令体系

Command Modes

Cisco 的设备配置时一般分为四种模式,分别为:

  • User EXEC (Router> )
  • Privileged EXEC (Router# )
  • Global Configuration (Rounter(config)# )
  • Interface Configuration (Router(config-if)# )

各模式间切换如下:

User EXEC -> (enable) -> Privileged EXEC -> (configure terminal) -> Global Configuration -> (Specify Interface) -> Interface Configuration

Interface Configuration -> (exit) -> Global Configuration -> (exit / end / Ctrl-Z) -> Privileged EXEC -> (disable) -> User EXEC

Interface Configuration -> (end / Ctrl-Z) -> Privileged EXEC

VLAN

创建一个 VLAN

# configure terminal
(config)# vlan <vlan-id>
(config)# name <vlan-name> [Optional]
(config)# mtu <mtu-size> [Optional]
(config)# end
# show vlan { name <vlan-name> | id <vlan-id> }
# copy running-config startup-config

关联网络接口到 VLAN

# configure terminal
(config)# interface <interface-id>
(config-if)# switchport mode access
(config-if)# switchport access vlan <vlan-id>
(config-if)# end
# show running-config interface <interface-id>
# copy running-config startup-config

杂项

如果手抖输错了命令,交换机开始进行 DNS 查询,并且一直卡在那里,可以用 Shift + Ctrl + 6 停下来。使用 no ip domain-lookup 可以彻底禁用该功能。

Router

SubInterface

Router#configure terminal
Router(config)#interface fastethernet0/0.1
Router(config-if)#encapsulation dot1q 1
Router(config-if)#ip address 10.1.1.128 255.255.0.0
Router(config-if)#no shutdown

该命令创建了 Fa0/0 下的一个 SubInterface Fa0/0.1,配置为属于 VLAN 1,IP 地址为 10.1.1.128/16,将端口状态设置为 up。

Reference:

Cisco IOS IP Configuration Guide

YACC 基本用法

YACC 文件格式

yacc 文件分为三部分:
… definitions …(%{}%)
%%
… rules …
%%
… subroutines …

定义部分

第一部分包括标志(token)定义和 C 代码(用“%{”和“%}”括起来)。
如在定义部分定义标志:
%token INTEGER
当运行 yacc 后,会产生头文件,里面包含该标志的预定义,如:
#ifndef YYSTYPE 
#define YYSTYPE int 
#endif 
#define INTEGER 258 
extern YYSTYPE yylval;
lex 使用该头文件中的标志定义。Yacc 调用 lex 的 yylex() 来获得标志(token),与标志对应的值由lex 放在变量 yylval 中。yylval 的类型由 YYSTYPE 决定,YYSTYPE缺省类型是int。如:
[0-9]+ { 
yylval = atoi(yytext); 
return INTEGER; 
}
标志0-255被保留作为字符值,一般产生的token标志从258开始。如:
[-+] return *yytext; /* return operator */
返回加号或减号。注意要把减号放在前面,避免被认作是范围符号。
对于操作符,可以定义 %left 和 %right:%left表示左相关(left-associative),%right 表示右相关(right-associative)。可以定义多组 %lef t或 %right,在后面定义的组有更高的优先级。如:
%left ‘+’ ‘-‘
%left ‘*’ ‘/’
上面定义的乘法和除法比加法和减法有更高的优先级。
改变 YYSTYPE 的类型。如这样定义 TTSTYPE:
%union
{ 
     int iValue; /* integer value */ 
     char sIndex; /* symbol table index */ 
     nodeType *nPtr; /* node pointer */ 
};

则生成的头文件中的内容是:

typedef union
{ 
     int iValue;      /* integer value */ 
     char sIndex;    /* symbol table index */ 
     nodeType *nPtr; /* node pointer */ 
} YYSTYPE; 
extern YYSTYPE yylval;

可以把标志(token)绑定到 YYSTYPE 的某个域。如:

%token <iValue> INTEGER
%type <nPtr> expr
把 expr 绑定到 nPtr,把INTEGER绑定到 iValue。yacc 处理时会做转换。如:
expr: INTEGER { $$ = con($1); }
转换结果为:
yylval.nPtr = con(yyvsp[0].iValue);
其中 yyvsp[0] 是值栈(value stack)当前的头部。
定义一元减号符有更高的优先级的方法:
%left GE LE EQ NE ‘>’ ‘<‘
%left ‘+’ ‘-‘
%left ‘*’
%nonassoc UMINUS
%nonassoc 的含义是没有结合性。它一般与 %prec 结合使用表示该操作有同样的优先级。如:
expr: ‘-‘ expr %prec UMINUS { $$ = node(UMINUS, 1, $2); }
表示该操作的优先级与 UMINUS 相同,在上面的定义中,UMINUS 的优先级高于其他操作符,所以该操作的优先级也高于其他操作符计算。

规则部分

规则部分很象 BNF 语法。
规则中目标或非终端符放在左边,后跟一个冒号(:),然后是产生式的右边,之后是对应的动作(用{}包含)。如:
%token INTEGER
%%
program: program expr '\n' { printf("%d\n", $2); } 

;
expr: INTEGER { $$ = $1; }  
     | expr '+' expr { $$ = $1 + $3; } 
     | expr '-' expr { $$ = $1 - $3; } 
;
%%
int yyerror(char *s) 
{ 
     fprintf(stderr, "%s\n", s); 
     return 0; 
}

其中,$1 表示右边的第一个标记的值,$2 表示右边的第二个标记的值,依次类推。$$ 表示规约后的值。

第三部分

该部分是函数部分。当 yacc 解析出错时,会调用函数 yyerror(),用户可自定义函数的实现。

main 函数是调用 yacc 解析入口函数 yyparse()。如:

int main(void) 
{ 
     yyparse(); 
     return 0; 
}

递归的处理

递归处理有左递归和右递归。
左递归形式:
list: item
| list ‘,’ item;
右递归形式:
list: item
| item ‘,’ list
使用右递归时,所有的项都压入堆栈里,才开始规约;而使用左递归的话,同一时刻不会有超过三个项在堆栈里。
If-Else的冲突
当有两个 IF 一个 ELSE 时,该 ELSE 和哪个 IF 匹配是一个问题。有两种匹配方法:与第一个匹配和与第二匹配。现代程序语言都让 ELSE 与最近的 IF 匹配,这也是 yacc 的缺省行为。
虽然 yacc 行为正确,但为避免警告,可以给 IF-ELSE 语句比 IF 语句更高的优先级:
%nonassoc IFX
%nonassoc ELSE
stmt: IF expr stmt %prec IFX
| IF expr stmt ELSE stmt
出错处理
当 yacc 解析出错时,缺省的行为是调用函数 yyerror(),然后从 yylex 返回一个值。一个更友好的方法是忽略一段错误输入流,继续开始扫描。这里要涉及到 YACC 中错误保留字 error 的应用。
Yacc源程序的风格
建议按照如下风格来写:
(1)终端符名全部用大写字母,非终端符全部用小写字母;
(2)把语法规则和语义动作放在不同的行;
(3)把左部相同的规则写在一起,左部只写一次,而后面所有规则都写在竖线“|”之后;
(4)把分号“;”放在规则最后,独占一行;
(5)用制表符来对齐规则和动作。
语法分析中的错误处理
当进行语法分析时发现输入串有语法错误,最好能在报告出错信息以后继续进行语法分析,以便发现更多的错误。
Yacc 处理错误的方法是:当发现语法错误时,yacc 丢掉那些导致错误的符号适当调整状态栈。然后从出错处的后一个符号处或跳过若干符号直到遇到用户指定的某个符号时开始继续分析。Yacc 内部有一个保留的终结符 error,把它写在某个产生式的右部,则Yacc就认为这个地方可能发生错误,当语法分析的确在这里发生错误时,Yacc 就用上面介绍的方法处理,如果没有用到 error的产生式,则 Yacc打印出 “Syntax error”,就终止语法分析。
下面看两个使用 error 的简单例子:
1.下面的产生式
stat: error
;
使 yacc 在分析 stat 推导出的句型时,遇到语法错误时跳过出错的部分,继续分析(也会打印语法错误信息)
2.下面的产生式
stat: error ‘;’
;
使 yacc 碰到语法错时,跳过输入串直到碰到下一个分号才继续开始语法分析。
嵌入式动作
对于语法分析程序中的每一个语法规则,都有相应的 C/C++ 语句来做一些额外的处理,这个额外的处理就是语法动作。不过语法动作和词法动作的不同之处在于,语法动作允许嵌入式的语法动作,而词法动作不行。
尽管 yacc 的语法分析技术只允许动作在规则的末端,但 yacc 可以自动模拟嵌入在规则内部的动作。如果在规则内部写入一个动作,yacc 就会创造一个右侧为空并且左边是自动生成的名字规则,使得嵌入的动作进高规则的动作里去,用自动成成的名字代替最初的规则内的动作。
例如: 下面的句子是等价的
thing : A {printf(“I am A”) ;} B
thing : A fakename B;
fakename : {printf(“I am A”);}
这种方式将A值作为 $1,  规则末端的动作可将嵌入式动作的值作为 $2 ,B 的值为 $3.
Example:
//L文件:
%{
#include "FIRST_TA.H"
#include <stdio.h>
#include <stdlib.h>
%}
%%
a    {return A_STATE;}
b    {return B_STATE;}
c     {return C_STATE;}
not   {return NOT;}
%%

//Y文件:
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token    A_STATE B_STATE C_STATE NOT
%%

program :    
    A_STATE B_STATE {
        int c, d;
        c = 20;
        d = 25;
    }
      c_state_not  {
            int e,f;
            e = 30;
            f = 35;
        }
    |
    A_STATE B_STATE  {
            int a, b;
            a = 10;
            b = 15;
    }
    c_state_not : C_STATE NOT{}
%%

输入文件的字符:a, b, c, f, c, not

使用 KCPTun 加快 VPS 到本地的连接速度

碰上垃圾 VPS 提供商怎么办,商家说是亚洲优化,到本地还是绕 GTT 怎么办?不用担心,KCPTun 来帮你。

说来,网上那堆教程实在是写得不怎么好,要么太复杂,我就想加速一下网络连接,写那么多原理干什么……要么就是太简单,我真的不喜欢一键包。所以还是自己来吧。

KCP 简单来说,就是一个 UDP 暴力发包软件,如果原先建立的连接是这样
Client -> (TCP) -> Server
那么加入 KCP 以后就变成了这样
Client -> (TCP) -> KCP Client -> (UDP) -> KCP Server -> (TCP) -> Server

KCP 无论是客户端,还是服务端,都涉及到两个端口,在客户端有一个 listening port 和 remote,服务端有 一个 listening port 和一个 target。从连接的角度来说,是这样的一个流程:

Client -> KClient_Listening_Port -> KClient -> KRemote
KRemote = KServer_Listening_Port -> KServer -> KTarget = Server

原先 C->S 怎么连接,只要把地址改成对应的 KCP 端地址就可以无缝工作。

举个例子来说,比如我本地有个程序需要连接 Server:8388,原先直接连接就可以了,但是特别慢,打算用 KCP 来加速一下,且 KServer 监听 3389 端口。那么本地需要做的事情是:

"client_windows_amd64.exe" -l :1081 -r Server:3389 -key "test" -crypt none -mode fast2

这个的意思是说,KClient 监听 1081 端口并转发至 Server 的 3389 端口,密码是 test,没有加密,使用的模式是 fast2。

服务端要做的事情是:

server_linux_amd64 -l :3389 -t 127.0.0.1:8388 --key test --crypt none --mode fast2 --quiet

监听 3389 端口的传入连接,转发至本地的 8388 端口,也就是原来的服务端,其他和 Client 的配置相同。

这么简单就配置好了。

项目的 Github 在这里:https://github.com/xtaci/kcptun

这是一个图形化的 Windows 客户端:https://github.com/dfdragon/kcptun_gclient

git 使用小结

Git 是一个很好用的工具,相信不用我说大家也承认。以下记录一些会用到的命令行:

  • 创建 Git 仓库:git init
  • 克隆 Git 仓库:git clone /path/to/repository 或 git clone username@host:/path/to/repository
  • 克隆某一分支:git clone -b <branch> <remote git>
  • 将改动添加到缓存区:git add <filename> 或 git add *
  • Git commit: git commit -m “Commit Message”
  • 设置远端:git remote add origin <server>
  • 推送本地改动至远端:git push origin <branch>
    • 强制推送至远端:git push -f origin <branch
  • 添加分支:git checkout -b <branch name>
  • 切换回主分支:git checkout master
  • 删除分支:git branch -d feature_x

关于 qBittorrent 部分问题的记录

首先是这个反复弹出 Tracker Authentication 窗口的问题,这个是因为 Tracker 对未授权的种子返回了 HTTP/401 错误,导致 qb 弹出窗口要求验证。这是一个正常行为,如果不需要它:

  • 在 qBittorrent/src/base/bittorrent/torrenthandle.cpp 文件的 void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p) 函数中注释掉关于 401 错误的两行即可。

然后就是在 qb 中有大量种子的情况下,同时开始会导致 Tracker 始终处于 “Not Working” 状态,如果一个一个启动,那么就是好的,这个应该是qb本身并发设计不良导致的问题。

控制 AWS p2 实例的 GPU 频率

AWS p2 实例虽然方便,不用本地买显卡,但是碰到比较大的网络,p2 开一天就得 50 块钱,还是有点肉疼的。那么,既然付了钱,就把实例的性能发挥到极致吧。

Tesla K80 显卡通常工作在 AutoBoost 模式,这个模式会动态调整显卡的频率,在很多情况下都比最大频率要低,并且显卡驱动默认的功率限制并没有被开到最大,因此这两点都会影响我们最终获得的性能。

设置显卡工作频率比较简单:

sudo nvidia-persistenced
sudo nvidia-smi --auto-boost-default=0
sudo nvidia-smi -ac 2505,875 #(2505,875) for p2; (877,1530) for p3; (2505,1177) for g3

关于功率的调整,首先我们要查看显卡的最大功率限制 nvidia-smi -q | grep 'Power Limit',如果是 p2 实例,发现这个值是 175W,而驱动默认的限制是 149W,我们需要提高这个限制,使用  nvidia-smi -pl 175 即可,如果权限不足,用 sudo 运行。

参考资料:

https://www.ibm.com/support/knowledgecenter/en/SSFHY8_5.5.0/com.ibm.cluster.essl.v5r5.essl100.doc/am5gr_nvidcap.htm
https://devblogs.nvidia.com/increase-performance-gpu-boost-k80-autoboost/
https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/optimize_gpu.html