Thanks to visit codestin.com
Credit goes to www.zhihanyue.com

Hi there 👋

Welcome to my blog.

fake-ip or redir-host?

最近有考虑用fake ip,对fake ip使用中可能存在的问题,进行了简单的调研。 不代理全部协议的情况:fake ip要透过clash才能访问,如果部分fake ip的流量没转发给clash就会造成麻烦。如果只代理TCP不代理UDP,UDP用到的域名都要加到fake ip filter里。如果是自己设置的,例如ntp、行情服务、语音服务等,用一个加一个,维护成本不高。但如果是第三方应用的去访问的,由于我们不能预判,可能出现未知问题,造成额外的维护成本。 ICMP问题:非TUN情况下(如iptables redir),fake ip不能ping通,也会造成一些问题,比如traceroute不能用、应用检查服务器连通性不通过等。常见问题有游戏掉线,UU加速器测速不通过、掉线等。 注:如果使用TUN,clash可以接管包括ICMP在内的流量,对ICMP作出假回应。这种情况下不管用不用fake-ip,ICMP都是残废的。有些应用通过ICMP选最优服务器,可能选到很远的服务器,甚至选到连不上的服务器。为解决这一问题,可以修改路由表使ICMP绕过clash。 应用缓存:如果错误的fake ip被缓存,会造成切换网络环境后暂时无法上网。尽管OS只缓存TTL=1秒,应用可以有自己的DNS缓存,例如chrome缓存1分钟。极端情况下,一些应用只在初始化时获取一次ip,后续一直使用这个ip,这会造成切换网络环境后不能继续使用,必须重启应用。 可识别性:本地应用能够通过dns解析结果知道是否为fake ip,进而发现代理的存在。部分app检测到fake ip,就会改变app行为(如windows的互联网可用性探测)。此外,正如本地代理会被某些app警告一样,fake ip也存在被识别并用于风控的可能性,这样的代理并不是完全透明的。 综上,我认为fake ip不是DNS问题的终极解决方案,尤其在第三方应用层面上的不可控性。 再来看看redir-host。使用redir-host时,clash的行为令人困惑。理论上,clash无法反解域名只会发生在「没建立ip-域名对应关系」或「多个域名对应一个ip」的情况,但实际测试并非如此,在服务端发现几乎没用过域名请求。我人工模拟了一个「被严重污染、但返回的IP不重叠」的DNS服务,理论上应该全部反解才对,但此时也全部无法访问。客户端日志上rAddr是域名(似乎识别成功?),服务端日志上就变成污染ip了(但如果用fake ip,客户端和服务端看到的都是域名)。我也查了一些issue,关于redir-host的issue一般被统一回复「请用fake ip」,因此我没能通过issue获取有用信息。不知道是bug还是我哪里做错了。 更新:已经找到问题所在! v1.8.0版本(2021.11.08)改变了redir-host的行为,不再进行remote DNS,这一改变使得redir-host在DNS污染环境中几乎不可用,且无法解析到最近的服务器IP。redir-host的用户体验直线下降,问题增多,自然能够名正言顺退出历史舞台。 在原理上redir-host的问题并非不可接受。尽管有大量域名被污染到同一ip的情况,但实际碰撞的概率并不高,如果能增加一个机制,出现碰撞、保留地址等情况才使用fake ip,这样就既能正常反解又能保证99.99%的ip不是fake ip。相当于把尽可能真实的IP当作fake ip使用。这样对于不在意多一次DNS解析的时间的用户,提供了更好的选择。如果这一思路会引入别的问题,欢迎邮件讨论。 很有意思的是,有一种特别的服务端,即使请求错误ip,也能正常应答,能很大程度上无视DNS污染。但无论我自行配置的,还是一些其他的服务端,都做不到这一点。实验中,我的验证方式是通过curl –resolve瞎编一个ip,clash看到后直接懵逼,反解不了,丢给服务端,很神奇的是这个服务端还能正常应答,也许是解析了HTTP报文中的域名?我不知道怎样配置服务端可以做到这一点。 由于相关文档的不完善,如果我的理解有误,欢迎邮件指出。

April 17, 2023

为什么L1正则化能产生稀疏性?

网上很多是用等高线来解释,这种解释显然不足以说明L1正则化产生稀疏性的原因 这里我给出一种更好的intuition 设J(X)=J1(X)+R(X),J1是原来的loss函数,R是正则化因子 那么它们的导数也满足J’=J1’+R' 我们等价地认为,对于梯度下降的每次迭代,都包含两步: J -= alpha * J1' J -= alpha * R' 由于正则化的影响,X很容易到达0的附近 此后: L1正则化始终坚定不移地把J推向0,|R’|始终不变,S2式的下降速度不变 而L2正则化,越接近x=0,|R’|就越小,这使得S2的更新小到相对于S1的更新可以忽略不计,在0的邻域内的更新就会被S1主宰,因此难以抵达0 这就是我的intuition。 如果想要严格的证明,请了解一下Fenchel’s duality theorem,可以证明L1的Fenchel dual是L∞,也就是max。

March 18, 2019

如何从着色的角度直观理解CMYK的广阔色彩空间?

我们知道,色彩的三要素是色相、纯度、明度。 绘画时,通过颜料三原色的减色混合,可以得到各种各样的色相,这是常识,没有讨论的价值。但我们也会不禁想到这样一个问题:颜料本身具有的属性,仅仅是某种色相+某种纯度。当我们稀释颜料时,直观理解是稀释了颜料的纯度。那么,难道我们通过打印或者绘画,无法掌控明度吗? 我们首先想到明度的概念,直观理解,是一束光的明亮程度。 我把一幅画用手电筒照亮,实际上这幅画的明度就提高了。 似乎明度与光有关,难道我们用颜料时,对明度无能为力? 答案当然是否定的——我们用打印机打印的照片,纸张上确实可以反映出照片的明暗细节。 下面,我就对这个问题作出解释。 首先,我们需要理解的是,打印机中出墨量的调整,和绘画中颜料的稀释,本质上是一回事,都是在改变单位面积的颜料多少,也就是在改变颜料的密度。 当颜料密度增加时,色彩纯度当然会增加(毕竟纯度的意义就是密度),同时明度在这个过程中也在悄悄减少——颜料吸收了一部分光。 既然随着密度的改变,纯度和明度在同时改变,那还怎么调节? 其实,CMY颜料对光的吸收作用是非常温和的。 我们假设这张纸接受到的光为单位1(100%明度),可以理解为白纸的空白区域拥有100%的明度。当某种颜料出墨量达到饱和时(比如C100),色彩纯度升到100%,明度也仅仅降低了10%左右! 接下来我想进一步降低明度。一个直接的想法是:让颜料的量进一步增大,这样就能吸收更多的光。事实上,这就是CMYK颜色模式所采取的方式——混入黑色来吸收光。常见两种获得黑色的方式:一种是CMY等比例混合,一种是用Y,两种方式都可以在不改变纯度的情况下,使明度显著下降。 总而言之,通过CMYK出墨量的搭配,我们能够做到同时满足色彩纯度与明度的需求。 注: 从HSB到CMYK的转换并不是打印机完成的,这种转换在计算机中就可以完成,这里只借它说明CMYK调色的直观原理(不涉及具体算法) 文中提到,明度和饱和度在一开始有短暂的同时变化的过程,这意味着CMYK颜色模式具有“盲区”——它并不能够描述所有颜色。的确如此,CMYK的“盲区”主要位于一些高饱和度高明度的区域,且范围较小。

February 13, 2019

Ruby on Rails (RoR) 总结

概要 结构 链条一:concern -> controller <-> model controller:管理params、cookies、session,并把它们里面的数据传送给模型 model:维护数据结构及其上的操作,所涉及的数据包括它维护的数据本身和数据的关联性对象(比如belongs_to);生成数据结构中的数据(类函数) 链条二:controller实例变量 / helper -> view helper:帮助view生成结构化html,可以有效简化视图的结构。helper的本质特点是:固定输入对应固定输出,相当于一个函数,没有依赖性。 generate/destroy 1 2 rails generate controller StaticPages home help rails destroy controller StaticPages home help 1 2 rails generate model User name:string email:string rails destroy model User migrate migration是完成某种数据库模式操作的文件。 Rails中的型态 说明 MySQL Postgres SQLite3 :string 有限长度字串 varchar(255) character varying(255) :text 不限长度文字 text text text :integer 整数 int(4) integer integer :float 浮点数 float float float :decimal 十进制数 decimal decimal decimal :datetime 日期时间 datetime timestamp datetime :timestamp 时间戳章 datetime timestamp datetime :time 时间 time time datetime :date 日期 date date date :binary 二进制 blob bytea blob :boolean 布尔值 tinyint boolean boolean :references 用来参照到其他Table的外部键 int(4) integer integer 另外,字段也还有一些参数可以设定:...

March 18, 2018

Ruby总结

语法严格定义了只有两种访问形式 常量访问:class/module::常量名 可使用对象的constants方法查看常量 除了一般常量以外,类、模块也是常量。 方法访问:任意对象.方法名 可使用对象的methods方法查看方法 方法并不是对象,除了被执行以外没有任何特征。 ruby不支持在class外部进行成员变量的访问!能访问的只有方法!“变量即视感”是用方法打造出来的。 定义在top-level的方法,处理方式是特殊的:它会成为所有对象的方法!只要不定义在top-level,就不会出现这种情况。 可见域 常量、类方法、实例方法的可见域:当前层次与内层,若公开则外部可见 局部变量的可见域:当前层次(若在top-level,也会限制到当前文件,不会影响其他文件) 注意:闭包不算作内层,也属于当前层次 类变量、实例变量可见域:在且仅在当前class/module语句的内部 class 访问权限控制(public/private/protected)仅对instance methods有效,我把这一部分称为模板,它不会立刻绑定到某个对象,而仅仅用于产生对象 哪些东西会被继承?除private块内的instance methods外的所有玩意都会被继承,但注意:“继承没有复制,只有引用”,任何类变量都不会在子类中复制一份,而是共享同一块内存区域。 def A.func与def func是两种截然不同的语法,它们有着本质区别:def A.func是立刻执行的,立刻把func方法绑定到A这个对象上,通过A这个class实例化的对象并没有这个方法;而def func只是作为一个模板,在new之后才会绑定给对象。 类的new方法会自动调用实例的initialize方法,但子类的initialize方法会覆盖父类的initialize方法,因此一般在initialize里用super调用父类的构造函数 @表示变量属于self对象,当前实例是谁就作用于谁 @@表示类变量(相当于全局变量),在当前类及其子类的模板内可被看到 如果方法不需要访问类的实例,就应该定义为类方法 ruby中super关键字只有一种作用:调用同名方法 super不带括号表示调用父类的同名函数,并将本函数的所有参数传入父类的同名函数 super()带括号则表示调用父类的同名函数,但是不传入任何参数 attr_accesstor 在类中使用成员变量,比如self.email,只要它不在等号左边,self就可以省略;在等号左边时,email表示名为email的局部变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Foo PI = 3.1415 @@width = 10 @@height = 100 def self....

March 18, 2018

Best Require —— node多层级相对路径引用最佳解决方案

这是我编写的一个node.js插件,用于解决多层级相对路径模块引用难以维护的问题,具体看下面的「Introduction」。 Best Require is a require() hook plugin for requiring a module in your project elegantly for Node.js. 1 2 3 require(':controllers/posts'); require(':models/Users'); require('~/application/apis/config'); Installation 1 npm install best-require --save Introduction Background Have you ever coded like this in your application? 1 2 3 4 5 6 // require the 'posts' module require('./posts'); require('./controllers/posts'); require('../controllers/posts'); require('../../controllers/posts'); require('../../../apis/controllers/posts'); When our project contains many layers of directory, the relative path of each module will become complicated, which not only makes us very confused, but also makes the project difficult to maintain....

March 1, 2018

npm uninstall sequelize --save

先前使用sequelize,是因为它在github上的star是node orm当中最多的,生态比较好。 在框架开发过程中,放弃sequelize,倒不是因为遇到了不适合使用sequelize的业务场景(当然众所周知不适合用orm的情况是存在的),而是因为它不太美。 对sequelize的模型扩展,比较官方的做法是: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 User = sequelize.define('User', { name: { type: DataTypes.STRING }, email: { type: DataTypes.STRING, unique: true, allowNull: false, validate: {notEmpty: true}, set: function(email) { this.setDataValue('email', email.toLowerCase()); } }, role: { type: DataTypes....

February 26, 2018

ES6中同对象不同属性的实用DRY技巧——解构

对于obj.property,我们考虑obj相同、property不同的情形。 举个实际的场景作为例子,models对象中有User, Post, Token, Page等属性,我们定义数据关系时可能写出如下代码: 1 2 3 4 models.User.hasMany(models.Token); models.Answer.belongsTo(models.Forum); models.Swiper.hasOne(models.Page); models.Token.belongsTo(models.User); models重复了很多次,我们希望把代码简化到如下形式: 1 2 3 4 User.hasMany(Token); Answer.belongsTo(Forum); Swiper.hasOne(Page); Token.belongsTo(User); 这时该怎么办? 最容易想到的做法是: 1 2 3 4 5 6 let User = models.User, Answer = models.Answer, Forum = models.Forum, Swiper = models.Swiper, Page = models.Page, Token = models.Token; 这样显得有点啰嗦,而且在定义时对models.和属性名的重复本身就不够DRY。 有的小伙伴可能想到了用eval,自动定义models中的属性: 1 2 for(let name in models) eval(`var ${name} = models.${name}`); 且不谈这里的细节问题,这两行代码是没办法直接复用的(必须在当前作用域下才有效,不可能封装到一个函数),这两行代码会一直在上下文中污染作用域。 想到这些,归根到底还是对ES6的特性不熟,实际上利用解构可以轻松解决问题: 1 const {User, Answer, Forum, Swiper, Page, Token} = models; 简洁优雅,很好地满足了我这种DRY强迫症的需求,不过可读性差了点,我们不妨定义一个函数:...

January 23, 2018

为什么我反对清除node.js中require的cache?

我曾经尝试用这种方式写module:“始终假设cache不存在,保证开发者在多次require时是否清除cache对module的工作没有影响”,后来发现与其这样不如禁止清除cache这种行为。 现在让我们设想“没有cache”的情形(这也是我这么实践时遇到的坑): 我们无法在module中直接写初始化代码(因为这样会导致多次require会进行多次初始化); 在module闭包中声明的变量,对于内部的一些function而言,不能视为“静态变量”,这种情况是反直觉的,因此容易造成错误(想避免“错误”需要用额外的设计模式进行约束); 1 2 3 4 var x = 0; function inc() { return ++x; } 对于需要初始化并且只能初始化一次的module,需要告诉某个和它交互的单例对象(比如‘app’module),它初始化完了;然后,module的每一次执行都询问那个对象,我是否已经初始化了,如果是就不用再次初始化,为什么会这样,因为这个module本身没有记录任何信息(module层面上没有传统意义上的“静态变量”),信息完全来自于外部;当然还有一种做法,直接由外部对此模块进行初始化(比方说module1.init()),但这不利于代码逻辑的分离,并且对此模块的ref可能还需要通过其他模块(初始化了它的模块)获得; 难以支持多入口的工程:总要有模块实际负责保存动态数据,不然程序怎么执行?显然,这样的模块只能是入口,就一个main入口的话还好,一层层往下写很OK,但假如我想加入另一个入口test,那么假如某模块(这样的模块必定存在)原本与main入口通信(从它那里知道它有没有初始化完成之类的),现在是不是还需要修改这个模块的代码使它与test通信?或者去调用main入口?这种情况下,工程最好只有一个入口,并通过一种十分不灵活的方式建构; 循环依赖。 就理想而言,我能想到的彻底的解决方案有两种: 把清除cache视为一类“hack”方式,从规范上讲,就应该是有cache的,清除了cache能不能用我不负责,如果遇到了看似需要清除cache才能解决的问题,请尝试改变自己的设计模式,而不是清除cache; 加入能直接实现module级别的static变量的语言特性,这样module就有了状态,有没有cache就无所谓了。 就现状而言,我认为:在编写module时,尽量假设处在没有cache(假如真的反复执行了也没影响)的情形中,是比较好的。但如果做这件事需要任何额外的工作甚至对工程逻辑结构的调整,那就千万不要这么做! 人对工程逻辑结构的思考和理解,应严格优先于这个不成熟的规则。 欢迎讨论!

January 7, 2018

对C++临时对象的内存位置的研究

首先,这是一个很少有人研究的问题:C++的临时对象是在堆里还是在栈里的。 但若不研究清楚内部原理,每次产生临时量时都会纠结于此, 网上能找到的资料也都是new在堆里、定义在函数内部就是栈里,或者是临时量通过复制构造函数构造这种废话。 所以自己研究了一下…… 首先,运算中的临时对象显然是栈内的, 对于参数上的临时对象,我推测是直接push进去的,应该也在栈内, 但是返回值上的临时对象就很让人费解了,应该是用rax传的地址,空间从哪来的呢。。 如果是new出来的空间,调用方如何确定合适的时机来delete以免内存泄漏? 如果是在函数栈内的,那函数结束后就不能保证原栈空间不被覆盖了。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <cstdio> #include <cstdlib> using namespace std; struct test { int a,b; long long asd; }; test f(test aaa) { test faf={0}; return faf; } void g() { test k; f(k); } int main() { g(); return 0; } 对三个函数反汇编看看。...

August 20, 2017