文章

"不积跬步无以至千里,不积小流无以成江海"

综述

如果按照原本的计划,这篇杂记本因完成于九月30号上下,一来正好一个月总结,二来,节前通常不会太忙..
奈何,计划赶不上变化,节前并不清闲,进入十一后则忙着玩太吾卷轴去了,在这里提一嘴,这个EA测试的独立游戏远不算完善,于我来说多年来一直希望能玩到类似太阁V这种类型的游戏,虽然还不能比,不过未来可期。
这一个来月,除了工作上写写业务代码,有一锤没一锤的完善之前用NodeJs写的针对p站的爬虫外并无太大建树。
年初买的《UNIX编程艺术》看了差不多半本,只论思想,多少有些启发,而当它开始分析各种实现时,终于就看不懂了..
然,并不是说一月毫无长进,但是却不成体系,比如改业务逻辑上的BUG,更多的是一种调试的经验,无他,但手熟能尔,原本调不动的东西现在有思路了,这就是变化。
这篇杂记分为三个部分

  • 第一部分:主要是一些最近日常使用的linux语句之类的
  • 第二部分:阅读中一些关于设计模式编程思想之类的浅见
  • 第三部分:一些通常不是很有用但还算有趣的关于linux日志相关的知识,也许算是运维相关

    第一部分

    早年,在我转行编程之前linux和unix便早有耳闻,初学前端时稍微了解了一些,多少有些兴趣,不过一来感觉通常用不着并未深入,二来也着实没有时间。实际上一直到今年初看阿里云搞了个98买一年的活动,实际买了台云服务器装上centOS后我才真正搞明白unix和linux的关系与历史...
    之后,出于兴趣使然入手了树莓派3b+之类的东西,便一发不可收拾。然而,毕竟没有系统学习过,想用什么功能依赖现场百度,相当长的时间连"&&"和"|"的区别都分不清就这么稀里糊涂的用着。
    现在,树莓派在家里充当着DNS及梯子入口的作用,跑着Aria2和自己写着爬虫,定期爬取p站榜单,或者想做什么测试把代码传上去试之类的,不时有物外之趣。
    而阿里云的主机,通过SSH代理可以链接到家里的树莓派,让我在公司也能在只有一个代理浏览器用的条件下,学些东西,也算是物有所值,偶尔还会后悔为啥没有一买三年。
    关于树莓派之类的开发板,如果有兴趣,树莓派还是最合适的,资料最全,不过短板也很明显,百兆网+20MB/S左右的I/O,真想拿来做NAS肯定是不行的,作为替代曾经买过一个香蕉派的路由板,最后发现基本的路由功能都不是很稳定(可以说..没有官方固件)..别的更是无从谈起,于是组了个小台式来辅助,这里其实可以写一篇关于怎么把windows共享硬盘代理给Linux或者怎么把Linux的文件夹代理给windows用,前者总是有奇奇怪怪的坑,后者只要处理好权限问题还是蛮好用的,但是....当时做些事情的时候没有想要记录,现在也忘得差不多了,下次要做估计还是从头查起...所以还是作罢。于是吸取经验,一些零碎的东西也找个地方记下来,便有了这篇杂记。

    eclipse/che

    首先是这个,eclipse/che,这是一个基于网页的IDE,中文资料不多,按理说是有权限认证功能的,但没见谁提起,文档里倒是有,不过我现在能力有限,光搭起来就竭尽全力了。
    先说结论,相对coding开源的那个还是好用点,但也不是太好用..首先代码格式化我调不出来..不知道缺啥,代码高亮对于js的支持时有时无...它自身引用了两个基于谷歌cdn的字体,没有梯子的环境就悲剧了..
    没有字体的话..shell巨丑..但是优点也是有的,首先是基于docker安装,如果不出意外很顺滑,当然不出意外一般是不可能的...
    然后,各种开发环境(python,node,go,java,c++)都给你配好,一个工作区就是一个docker,用什么启什么,这点还是蛮友好的。
    然后这是官网:http://www.eclipse.org/che/
    安装配置:

    docker run -ti -v /var/run/docker.sock:/var/run/docker.sock -v /local/path:/data eclipse/che start

理论上上面一句话就够了,然后你就能认识到理论毕竟是理论...如果安装出问题..
你可以看看它给你得我提示..来看看到底哪个验证通不过...然后就是对症下药(比如去搜搜看issues里有没有解..),然后还有一些别的查看状态的语句..比如..

sudo docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v /local/path:/data eclipse/che info --network

这里输出的是网络状态,我安装失败的原因就在这里找到了..首先在防火墙中..开放8000,8080,32768/65535这些端口..也许不需要那么多...但是如果你想从外部访问docker里面的东西都开了是比较妥当的,工作区会随机选一个大于32768的端口把自己映射出去..
当然,你也可以手动指定,也可以通过docker port "CONTAINER ID "来查看映射那哪些端口,CONTAINER ID 可以通过docker ps来查看..不过通常因为docker ps可以查看到启动指令,而指令中一般会包含映射关系,如果不是映射了一大堆也是够用了...
回到安装,我还遇到一个坑,大概是安装脚本默认设置的是内网ip,而这个内网ip因为各种原因并不能支持它完成安装,最后去/local/path/eclipseche/che.env 修改CHE_HOST=""为公网ip就好了。

我还遇到javascript高亮时有时无,提了个issues,作者告诉我用浏览器的匿名模式来打开...emmmmm...总之每次都清缓存,这个bug遇到的概率会小很多..原因是这个组件在载入的时候报错了,可以在console里看到。

日常使用

说到linux的日常使用,其实会cd,cp,mv,mkdir,rm,vi大多数基本操作就都能干了...再加个ssh,scp...初出茅庐的胆子肥点也许就赶在简历里写“精通”了也说不定..
这里介绍一些常用的查看状态的简单指令

uptime
#  输出 1分钟,5分钟,15分钟的平均负载
top
# 非常综合全面的日志输出
free
# 内存状态 -m 可以以mb为单位
ps -aux
# 输出各pid的启动指令和状态,通过用管道连接grep列子: ps -aux | grep node
pidstat
#当前pid 占用cpu的状态,如果加个 1,1s刷新一次当前活跃pid的状态
iostat
# I/O 状态
# r/s, w/s, rkB/s, wkB/s:分别表示每秒读写次数和每秒读写数据量(千字节)。读写量过大,可能会引起性能问题。
# await:IO操作的平均等待时间,单位是毫秒。这是应用程序在和磁盘交互时,需要消耗的时间,包括IO等待和实际操作的耗时。如果这个数值过大,可能是硬件设备遇到了瓶颈或者出现故障。
sar -n DEV 1
# 网卡吞吐状态
sar -n TCP,ETCP 1
# TCP 连接状态
# active/s:每秒本地发起的TCP连接数,既通过connect调用创建的TCP连接;
# passive/s:每秒远程发起的TCP连接数,即通过accept调用创建的TCP连接;
# retrans/s:每秒TCP重传数量;
dmesg | tail
# 输出系统日志最后十行

对我来说越靠下越不常用...其实个人感觉最常用的是htop,不过这个很多情况下没装..
所幸apt-get一下或者yum一下..也蛮方便的..这个指令输出的更直观一下..其实top用好的话,也不差,然而,发现htop后我就没研究top了...
这些指令对于把握当前机器状态很有帮助有的时候也可以帮助排查自己写的代码有没有问题...
比如,有次我发现机器中的内存被大量吃掉..排查后发现其实是因为..如果在Node线程中再引入node-mysql线程池,即使你将mysql的线程释放了,这个node线程也不会释放,即使你发送disconnect也不管用,想想其实也正常,线程池中线程即使释放了,池子本身也不会关闭,
而,对线程发送disconnect其实是等当线程所有操作执行完才会关闭,而线程池本身不结束的话,线程也不会释放,于是就占用资源..这个问题很基础,但是,如果你只查看你执行的那个node进程会发现其实内存没占多少,因为它fork出来的线程占的内存并不算它的...所以,如果不从一个更大的视角来看,还真不一定能立刻发现。

其它工具:mycli与oh-my-zsh

这两个都是号称能提高shell的使用体验的小玩意,安装也都很简单,比较顺滑。
体验嘛,mycil的确很好用,尤其是各种提示对于不是很熟悉Mysql的人来说简直是福音。
相对而言,on-my-zsh虽然也有一堆提示..但感觉上可能不是那么解渴,主要是装了这个后我在网页中用shell有点卡,而提示功能也不是那么必要,有的时候还会带来一些麻烦,所以没有mycil给我带来的体验好。

第二部分

随着时间推移,经常能看到一些javascript的花式写法,比如能用数组自带的方法,就不用for循环啦,花式高阶函数,解构,柯里化之类的,如此种种有时反而让意大利面式的代码变得可爱起来
不过毕竟8012年了,要是还在用上个世纪的写法来写前端,不免让人嗤笑,不过个人感觉过犹不及,就和曾经有一句"JAVA的特点就是能把简单的东西写复杂"一般。
作为,给你鸡肉告诉你这是牛肉的javascript,为了避免徒增复杂性,写出又难懂又不好维护的代码,在接触那些花里胡哨的花式技巧前,我觉得有必要再来过一遍基本的设计原则,必将受益匪浅。
首先比较主要的设计原则有六条,补充的话就有很多了,对于设计原则个人感觉就好比教导队出的战术教案,不遵守你死都不知道怎么死的,但是完全照搬你会死的很难看,大多数时候需要考虑实际需求,必要的时候还需要搬出批判的继承那一套东西来。
鄙人才学疏浅,对于这一块大都走马观花,与其说是实践中的感悟,更多的是为实践做准备,以下的内容大都搬自网上的三手资料,翻译看起来很生硬..但我英语也不强这么凑合着看吧,而且虽然多少会加些自己的东西进去,假若有幸有人读到,我就这么一说,你就那么一听就好。

六大设计原则

1 单一职责原则(Single Responsibility Principle - SRP)

原文:There should never be more than one reason for a class to change.
译文:永远不应该有多于一个原因来改变某个类。
理解:对于一个类而言,应该仅有一个引起它变化的原因。对于没有类的js来说,我觉得理解成一个函数只做一种现象的改变比较妥当。
应用:把一个巨大的错综复杂的函数拆成多个小函数以便于维护。

2 开放封闭原则(Open Closed Principle - OCP)

原文:Software entities like classes, modules and functions should be open for extension but closed for modifications.
译文:软件实体,如:类、模块与函数,对于扩展应该是开放的,但对于修改应该是封闭的。
理解:简言之,对扩展开放,对修改封闭。换句话说,可以去扩展类,但不要去修改类。
应用:比如修改祖传代码的时候,你先不去管你要修改的部分的实现代码,在它执行完毕之后的结果上做扩展,比去修改它的执行过程保险的多。个人在这一点上受益匪浅,不过都这么做的话代码会腐化的很快,所以要斟酌,或者寻找更优的解,比如把执行过程拆分,修改其中的一部分。

3 里氏替换原则(Liskov Substitution Principle - LSP)

原文:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
译文:使用基类的指针或引用的函数,必须是在不知情的情况下,能够使用派生类的对象。
# 下面是我摘抄的文字
理解:父类能够替换子类,但子类不一定能替换父类。也就是说,在代码中可以将父类全部替换为子类,程序不会报错,也不会在运行时出现任何异常,但反过来却不一定成立。
应用:在继承类时,务必重写(Override)父类中所有的方法,尤其需要注意父类的 protected 方法(它们往往是让您重写的),子类尽量不要暴露自己的 public 方法供外界调用。
# 但是仔细思考一下..感觉这段描述明显反了。
# 父类能替换子类的话,还要子类做什么,介于我不熟悉传统具有类的语言,下面写上我自己的理解,其它就交予读者自行判断。
理解:子类不要去直接重写父类的方法,你可以把这个方法继承下来在不影响父类的实现的基础上进行扩展。也就是把父类替换成任意子类不会报错,但是反过来则不行。
应用:以js为列通过构造函数new 的对象可以有自己独特的方法,但不要顺着原型去改写构造函数的prototype,你可以把整个父类的prototype深拷贝给自己,但不能再覆盖回去,new 一个就改一次,假以时日构造函数就完全不可维护了。
# 虽然我也不敢说我一定对,但是..假如我完全不加理解的就相信之前看的那篇文章上写的知识,应用于生产实践,这将会是一种死的很难看的例子...

4 最少知识原则(Least Knowledge Principle - LKP)

原文:Only talk to you immediate friends.
译文:只与你最直接的朋友交流。
理解:尽量减少对象之间的交互,从而减小类之间的耦合。简言之,一定要做到:低耦合,高内聚。
应用:在做系统设计时,不要让一个类依赖于太多的其他类,需尽量减小依赖关系,放在js里则一个函数至多往下调用3层,不遵守当然也不会遭天谴,只是当这个函数不符合预期的时候也许全部删了重写会更快一些。

5 接口隔离原则(Interface Segregation Principle - ISP)

原文:The dependency of one class to another one should depend on the smallest possible interface.
译文:一个类与另一个类之间的依赖性,应该依赖于尽可能小的接口。
理解:不要对外暴露没有实际意义的接口。放在js里则是一个模块像外暴露的方法是必须要用的,没需求的话就先删了吧。
应用:也许可以拿出面向接口编程那一套,对于接口而言,用什么做什么。不需要搞那么多劳什子。

6 依赖倒置原则(Dependence Inversion Principle - DIP)

原文:High level modules should not depends upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.
译文:高层模块不应该依赖于低层模块,它们应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
理解:应该面向接口编程,不应该面向实现类编程。面向实现类编程,相当于就是论事,那是正向依赖(正常人思维);面向接口编程,相当于通过事物表象来看本质,那是反向依赖,即依赖倒置(程序员思维)。
应用:并不是说,所有的类都要有一个对应的接口,而是说,如果有接口,那就尽量使用接口来编程吧。
# 这是个我不怎么能理解的原则,对于抽象,细节,这一类词汇我不能确认我理解的是否准确,所以就直接整段摘抄摆在上面了,一点没改。
# 但是这不妨碍我提出自己的理解,还是那句话,我就这么一说,你就那么一听。
理解:对于js来说,这还是一个拆分规则,对于一个复杂到爆炸的功能,不要一个模块负责所有事情,这样你修改一个小小的执行实现都会引发不可预期的后果。
应用:把一个功能拆分,拆分之后再分类,不同类有不同的模块来负责,主模块只管控制公用的部分,具体的实现只对各自的控制模块负责。
# 一开始我是想用函数举列,但是写完发现只是徒增复杂度,杀鸡用牛刀,换成模块好些。

补充及其它设计原则

这一块我就不完全摘抄了,蛮多的,我捡一些来说。

  • 组合/聚合复用原则(Composition/Aggregation Reuse Principle - CARP)

    当要扩展类的功能时,优先考虑使用组合,而不是继承。大体上就是能复用就复用。
  • 无环依赖原则(Acyclic Dependencies Principle - ADP)

    当 A 模块依赖于 B 模块,B 模块依赖于 C 模块,C 依赖于 A 模块,此时将出现循环依赖。在设计中应该避免这个问题,可通过引入“中介者模式”解决该问题。
  • 共同封装原则(Common Closure Principle - CCP)

    应该将易变的类放在同一个包里,将变化隔离出来。该原则是“开放-封闭原则”的延生。
  • 共同重用原则(Common Reuse Principle - CRP)

    如果重用了包中的一个类,那么也就相当于重用了包中的所有类,我们要尽可能减小包的大小。
  • 好莱坞原则(Hollywood Principle - HP)

    好莱坞明星的经纪人一般都很忙,他们不想被打扰,往往会说:Don't call me, I'll call you. 翻译为:不要联系我,我会联系你。对应于软件设计而言,最著名的就是“控制反转”(或称为“依赖注入”),我们不需要在代码中主动的创建对象,而是由容器帮我们来创建并管理这些对象。

这一块感觉写的相对简单好懂。从中我萌生一个想法,在nodeJs的项目中用一个js文件来管理其它所有,或者大部分模块的引用,毕竟,如果都是写在页面顶部,改起来得一个页面一个页面改,很麻烦而且也不好管理,就是不知道有没有现成的实现。

第三部分

只看前面的介绍可能压根闹不明白这部分要提些什么,其实这也是我想要的效果之一,毕竟,通常来说这些知识虽然很有用..但是..
多少有些"脏"..记录下来,也算是为了不时之需,或者知己知彼吧。

图片盗链

通常各个图站为了防止盗链,都会对referer做验证,想绕过也很简单,搞个后端,然后在请求中修改headers,添加referer。
我试着用nodeJs写过类似代理的接口,接收一个参数,参数是一个转成16进制字符串的url,转回字符串,添加headers请求然后将返回的数据压到返回体里去,并声明这是一张图片。这样img标签也能正常显示图片。
后来我还听说可以通过Ngix做反向代理,在其中添加,这一块我就不是很懂了,只是听说。
其它,在前端可以禁用referer...这样的话,基于referer的防盗链完全就废掉了,还简单方便。
实现也很简单,在img中添加

<img src="" referrerpolicy="no-referrer" />

或者添加meta标签中指定

<meta name="referrer" content="never">

前者除了IE都支持,后者IE也支持。

端口扫描

实际开发中,经常会有需要确认某个端口倒地开没开的需求。如果只有一两个,用telnet或者ssh -v也能查看。
但,毕竟这两个不是专门干这个的,颇有曲线救国的意思。而且,一个两个还好,十个二十个就不好使了。
这个时候就到了nmap出场的时候了。
以前在学校用这个扫描过学校的内网,发现过没加密码的教师用FTP,在上面找到过一些电影,为日常生活增添了不少情趣。
那时候我是用的windows版,需要安装几个软件包,现在用上Linux这个工具就顺手多了。
附带一提,win10的子系统linux用不了,因为这个子系统调不了网卡..我也不知道为啥..
linux下的安装,去官网下载解压,编译。略过不表。
简单的使用:

nmap 127.0.0.1

没几秒,你本地开了什么常用端口就能扫描出来,不过需要注意,这里并不是从1~65535 都扫描了,就是说这里只是提供了快速的预览。
如果想扫描所有端口需要:

nmap -sS -p1-65535 127.0.0.1
# -sS 是一种扫描模式

这次可能会多要些时间,不过所有开放的端口都会显示。
其它,这款工具其实主要是做网络维护的,包括对某个网段进行扫描看看有没有开机,对端口后的服务做推测,对被扫描的主机系统及基本信息做推测,显示从你这里连接到远端中间会经过几层,还有各种扫描模式。这些我就没玩过了..由于网络基础知识的匮乏,就算尝试去了解也只是一知半解,留给以后如果有需求再去了解吧。

linux登录日志

linux有几个查看,登录日志信息的指令。比如
who:显示现在谁在登录
who am i :我是谁?
last: 近期的登录记录
lastlog: 所有用户最后一次登录的记录
其它,每次通过ssh登录都会在上面显示最后一个登录的ip和日期。
这些对于,系统有无被人入侵,或者入侵过非常有帮助..
比如我看到这些指令时尝试在阿里云上运行了一次结果发现,有一个奇怪的账户有登录记录:games
查了下,按理说这不是一个可以登录的账户,虽然最后登录是六月多的事情了,我还是改了密码和ssh的端口,并删除这个账户,聊以寄慰。
由于没有发现什么cpu异常占用,或者内存特别高之类的问题,服务器上也没有什么特别重要的数据,也就没有重装,希望日后不要后悔..
言归正传,众所周知,linux下,没有什么东西是不能改的。而且大都是文件。
这些日志也不例外。不出意外它们都是存在/var/log/或者/var/run/这两个目录下的。
这里还有很多其它的日志。不过,如果直接尝试去打开,会发现是乱码。

# 正确的打开方式
utmpdump /var/log/wtmp
# 这是打开last的日志
# utmpdump 属于 sysvinit-tools
# 附上常见的几个日志目录
/var/run/utmp #(用于记录当前打开的会话)被who和w工具用来记录当前有谁登录以及他们正在做什么,而uptime用来记录系统启动时间。
/var/log/wtmp #(用于存储系统连接历史记录)被last工具用来记录最后登录的用户的列表。
/var/log/btmp #(记录失败的登录尝试)被lastb工具用来记录最后失败的登录尝试的列表。

这样大多数的日志都可以查看,也许有人要问,我用指令查看不就好了,专门打开日志文件做什么呢?
答案是可以做分析和筛选,有些时候这些日志是非常多的,所以需要筛选过滤,才能发现自己想要的内容。
比如

utmpdump /var/log/wtmp | tail -15
#显示最后登陆的前15条

其它,还能统计,某个ip尝试的次数,诸如此类。
使用 sed 工具连用正则类似

utmpdump /var/log/utmp |sed -n 's/.*(\(.*\)).*/\1/p'
# 这是匹配括号里的内容

不过我正则学的不好,所以玩不出什么花样。
但是....既然记录可以查看,明显就可以删除或者修改

# 假如和 >连用
utmpdump /var/log/wtmp >/var/log/wtmp.file
# 保存成可以编辑的文件

sed -i '/'"ip"'/d' /var/wtmp.file
# 删除带某个ip的记录

utmpdump  -r < /var/log/wtmp.file > /var/log/wtmp
# 覆盖回去

这样大多数的日志都能修改,想应对也很简单,把日志文件写在别处并换个名字,或者写两份日志记录。
其实sed指令可以直接修改一些文件..不过我没有研究过。
不过,Linux编辑文本文件的指令如果能熟练应用实在很方便,删除替换,查找,匹配,各种花样很全。
虽然走马观花的看过一些,现在缺忘得差不多了,留着以后有需求的时候再研究吧。

结语

不知不觉,这篇杂记还是蛮长的,虽然竟是些边边角角的东西。
不过正如开篇引用的劝学一般,"君子博学而日参省乎己,则知明而行无过矣"。
通过对这些边边角角的整理,即使没有明显用到的一日,也还是会产生好的影响。
就如某句话说的:"当你花几分钟听完一首歌,听完这首歌后的你,和之前的你也是不一样的"。
也可以这么说,即使,从对技能了解这个角度看,写完这篇文章之前与之后并无太大区别,但思考方式,等看不见的地方还是潜移默化的受到影响了吧。

评论

This is just a placeholder img.