每天学习一个命令:uniq 筛选过滤重复的行

uniq 命令从标准输入读取过滤邻近的相同的行,然后写回标准输出,在此过程中 uniq 会将重复的行 merge 合并到第一个结果中,所以 uniq 可以用来排除文件中重复的行。因此 uniq 经常和 sort 合用,先排序,然后使用 uniq 来过滤重复行。

查看 man uniq 得知这个命令是用来显示,或者隐藏重复行的命令,一般情况下使用管道命令组合其他 cat, grep, awk, sort 等等使用。可用来过滤重复行,或者找到文本中重复的行。

基本使用

命令格式:

uniq [OPTION]... [INPUT [OUTPUT]]

uniq 会从标准输入读取数据,过滤相邻的行,并将结果输出到标准输出。如果没有其他选项,重复的行会合并到第一次出现的行上。

uniq 的基本使用如下:

一些常用参数

  • -c 在每一行前打印行出现的次数
  • -d 只打印重复的行,重复的行只打印一次
  • -D 打印出所有重复的行
  • -f 在比较时跳过前 N 个 fields
  • -i 在比较重复行时忽略大小写
  • -s 在比较时忽略前 N 字符
  • -u 只打印唯一的行
  • -w 比较时只比较每一行的前 N 个字符

通常情况下 field 是由空格或者 TABs 分割的。

通常情况下,uniq 会和 sort 搭配使用。

命令返回 0 或者 >0 的数值表示退出,如果为 0 表示运行成功,>0 的数值表示发生错误。

实例

假设有如下四行在文件 cat file.txt 中:

uniq line
repeat line
test line
repeat line

打印重复行的数量

最为常用的 -c 选项,可以打印重复行的数量

sort file.txt | uniq -c
  2 repeat line
  1 test line
  1 uniq line

打印重复的行

使用 -d 打印重复的行,那么不重复的行就不会输出

sort file.txt | uniq -dc
  2 repeat line

仅显示不重复的行

显示不重复的行 -u

sort file.txt | uniq -u
test line
uniq line

跳过行开头字符

可以使用 -s 参数跳过开头 N 个字符

cat /var/log/nginx.log | uniq -s 10

2018-02-06 uniq , linux , command , awk , sort

Linux 管理开机启动

如果想要科学的管理Linux 的开机启动项,那么了解 Linux 开机启动流程是非常有必要的。链接的文章将Linux开机启动流程讲述的非常通俗易懂,这里就不再详述。简单地归纳:

  1. 加载内核 ,读入 /boot 目录下内核文件
  2. 内核加载完成后,运行第一个程序 /sbin/init(PID为1),用来初始化系统环境
  3. 依据运行级别启动守护进程(daemon 或者称为服务)
  4. 加载开机启动程序
  5. 用户登录
  6. 进入login shell,依据不同的登录方式(命令行登录,ssh登录,图形界面登录),系统加载不同的shell配置,基本上就完成启动了

这篇文章涉及到的开机启动项内容主要就是集中在上述的第3,4步。Linux 预置七种运行级别(0-6),系统在 /etc 目录会有各个运行级别对应的子目录,目录中指定要加载的程序

  /etc/rc0.d   /etc/rc1.d   /etc/rc2.d   /etc/rc3.d   /etc/rc4.d   /etc/rc5.d   /etc/rc6.d

目录中的 rc 表示 run command, 最后的 d 表示 directory 目录。/etc/rcN.d(其中 N 表示的run level) 目录下是一系列启动脚本。文件都是以 字母S+两位数字+程序名 的形式构成。字母 S 表示 Start,如果第一个字母是 K,那么表示 Kill 关闭。中间两位数字表示处理顺序,数字越小表示处理越早。不建议直接手动修改 /etc/rcN.d 目录下的文件。这就要涉及到本文的重点,如何科学的管理Linux自启动脚本。

rcconf

使用命令 apt-get install rcconf 来安装, rcconf 使用了一个非常友好的界面来管理启动项,使用 sudo rcconf 就能看到一个开机启动时可以执行的程序列表,使用空格选中就能添加到开机启动,同理撤销选中就取消开机启动,最后OK,保存就行。rcconf 是 update-rc.d 命令的 TUI(Text User Interface)。

几个重要的文件

  • /var/lib/rcconf/services 用来保存服务启动number,如果服务的启动顺序不是 20(默认),那么 rcconf 会将服务的启动顺序保存到该文件中以备重新启用时恢复。
  • /var/lib/rcconf/lock Lock 锁
  • /var/lib/rcconf/guide 管理员用来定义的Guide

update-rc.d

上一个 rcconf 命令中就提到了其实 rcconf 就是这个 update-rc.d 命令的封装,update-rc.d 命令可以用来安装或者移除 init 脚本。

update-rc.d [-n] [-f] name remove
update-rc.d [-n] name defaults
update-rc.d [-n] name disable|enable [ S|2|3|4|5 ]

其中 -n 选项,不会做任何实际操作,但是会显示运行命令之后会执行的操作,可以用来检查命令。-f 命令可以记忆为 force 表示强行删除链接。

当执行该命令时,就是用将 /etc/rcN.d/[SK]NNname 指向 /etc/init.d/name ,如果有任何的 /etc/rcN.d/[SK]??name 存在的话,update-rc.d 不会做任何改动。

update-rc.d service enable
update-rc.d samba defaults
update-rc.d mysql defaults 10 10  # 启动优先级,顺序
update-rc.d apache2 start 10 2 3 4 5 . stop 90 0 1 6 .     # 指定优先级,启动时10,关闭时90,后面的 `2 3 4 5` 表示run level
update-rc.d -f samba remove       # 移除服务自启动 

sysv-rc-conf

使用命令安装 apt-get install sysv-rc-conf ,然后使用管理员运行 sudo sysv-rc-conf

systemctl

还有一个命令 systemctl 涉及太多 systemd 的内容,略过

手动

如果先要自己写一个服务,或者脚本开机启动,那么可以把文件放到 /etc/init.d/ 目录下,改权限

chmod +x /etc/init.d/startup.sh
ln -s /etc/init.d/startup.sh /etc/rc.d/

reference


2018-02-05 linux , startup , script , shell , command

每天学习一个命令:ed 行编辑器

ed 是一个面向行的文本编辑器。ed 命令还有一个严格的 red 命令,red 命令只能编辑当前目录中的文件,并且不能够执行shell命令。

当使用 ed 命令明确指定一个文件时,文件的一份拷贝被读入编辑器的缓存,所有的编辑都是保存在缓存中,而不是直接在文件中修改。如果退出 ed 却没有显示的使用 w 命令来保存修改的话,所有的修改内容都会丢失。

编辑的内容可以通过两种不同的方式:commandinput 两种模式。使用第一种命令模式时,ed 命令通过从标准输入读取命令并将修改执行在编辑器缓存中。一个典型的命令

,s/old/new/g

这一行命令会将文本中所有的 old 字符串替换为 new,这和vim中有些相似。

当使用命令输入比如,a(append), i(insert), c(change) 时,ed 编辑器会进入 input 模式,这意味着给文件添加内容。在这个模式中所有命令都不再支持,相反的,所有的输入都会被写到缓冲中。input 模式将在输入 . 时自动结束并退出。

ed 编辑器的命令针对的是整行,或者数行,比如,d 命令意味着删除行,m 命令意味着移动行。如果要修改某一行中的内容,唯一的方法就是使用替换,就和上面的例子中类似。例子中的 s 命令也是针对的整行。

通常来说,ed 编辑器包含0或者多行行序号,通常后面跟随着命令及参数,他的基本结构如下:

[address [,address]] command [parameters]

address 通常包含一行或者多行

Line Address

可以使用下面的方式来表示行序号,以下所有的行序号都是 buffer 缓冲中行序号:

Tag Description
. buffer 中 当前行
$ 最后一行
n 第 n 行,行的范围是 [0,$]
- or ^ 前一行
-n or ^n 前 n 行
+ or +n 后一行及后n行
, or % 全部行,等同于 1,$
; 当前行到最后一行 .,$
/re/ 下一个包含正则 re 的行
?re? 上一个包含正则 re 的行

Commands

所有的 ed 命令都是单个字符,一些需要其他额外的参数。如果命令跨越了多行,每一行都需要 \ 来结尾。p(print),l(list) 或者 n(enumerate) 打印。如果输入了 ed 不认识的命令,ed 会打印一个 ? 作为错误消息。

Command Description
(.)a 添加到行
(.,.)c 改变行
(.,.)d 删除行
(.)i 添加到行首

还有很多命令可以参考下面的链接。

通常情况下,输入数字开始的行号,可以直接跳转到该行。

脚本

ed 的一个更有趣的特征是脚本化编辑工作的能力,将编辑命令放到独立的文件中并将它们作为行编辑器的输入:

ed filename < ed_script

这个特征使得 ed 成为了可编程的编辑器,也就是说,可以脚本化任何手动执行的操作。

sed 是作为特殊目的的编辑器而创建,专门执行脚本,与 ed 不同,不能交互使用。 sed 与 ed 的主要区别在于它是面向字符流的。默认情况下 sed 的所有输入都会经过处理并且转为标准输出。输入文件本身并不发生改变。如果想要改变输入文件,一般使用 shell 的重定向。ed 不是面向字符流的,并且文件本身会发生改变,ed 脚本必须包含保存文件并且退出编辑器,不能输出到屏幕。

awk 是作为可编程的编辑器而开发的,同 sed 一样,面向字符流,并且解释编辑命令的脚本。awk 与 sed 不同的是它废弃了行编辑器的命令集,提供了仿效 C 语言的程序设计语言,例如使用 print 语句代替了p 命令,但延续了 寻址的概念

/regular/ { print }

用来打印匹配 regular 的行。脚本张使用程序语言的优点是提供了控制编程的语句,包括表达式,条件判断,循环等等结构。

reference


2018-02-02 linux , command , unix , ed , line , editor

每天学习一个命令: rename 批量修改文件名

虽然 Linux 下有很多方式可以重命名文件,比如 mv filename newfilename,设置可以使用 cat 命令来将一个文件输出重定向到文件 cat file > newfile,或者可以拷贝的时候重命名 cp file newfile

但是其实 Linux 下有一个命令 rename 顾名思义,就是用来重命名文件的,并且能够按照正则批量重命名文件。他的基本使用方式就是

rename [options] "s/oldname/newname/" file

这个命令可以分开几部分来讲,首先对于整体命令先不看选项(options) 部分

rename "s/oldname/newname/" file

其中包含三个部分:

  • 原字符串oldname:将要被替换的字符串;
  • 目标字符串newname:原字符替换成的目标字符串;
  • 文件file:指定要改变文件名的文件列表。

其中每一个部分都可以使用正则,以上命令的解释可以理解为对于要重命名的 file 匹配的文件列表,将文件名中的 oldname 替换为 newname。

然后再来看选项options 部分,rename 支持以下的选项:

  • -v 将重命名的内容都打印到标准输出,v 可以看成 verbose
  • -n 测试会重命名的内容,将结果都打印,但是并不真正执行重命名的过程
  • -f force 会覆盖本地已经存在的文件
  • -h -m -V 分别为帮助,帮助,版本
  • -e 比较复杂,可以通过该选项,写一些脚本来做一些复杂的事情

rename 支持通配符

?  可替代单个字符
*  可替代多个字符

当命令中最后 file 为 * 时表示,匹配当前文件夹下所有文件,如果为 ? 时则匹配只有一个字符的文件名。

rename支持正则表达式

rename 支持 perl 的正则表达式

替换文件名中特定字段

rename "s/AA/aa/" *  # 把文件名中的AA替换成aa

这一行命令的解释就是,对当前文件夹下满足 * 的所有文件,文件名中包含 AA 字符的替换为 aa 其中 "s/pattern/new/" 中的 / 一个都不能少。

修改文件后缀

rename "s/.html/.php/" *     # 把.html 后缀的改成 .php后缀
rename "s/.png/.jpg/" *      # 将 png 改为 jpg

批量修改文件后缀名

批量添加文件后缀

rename "s/$/.txt/" *     # 把所有的文件名都以txt结尾

因为支持正则表达式,那么 $ 表示的就是结尾,将结尾替换为 .txt 也就意味着给所有文件添加 .txt 的后缀

批量删除文件名

rename "s/.txt//" *      # 把所有以.txt结尾的文件名的.txt删掉

同理,结尾有 .txt 的内容替换为空,也就是删掉后缀了。

应用正则匹配的部分文件名

假如需要在批量修改的时候保留部分文件名,可以使用引用 \1 ,比如有下面格式的文件

Screenshot from 2019-01-02 15-56-49.jpg

我只希望保留其中的日期部分,那么可以

rename -n "s/Screenshot from ([0-9\\- ]+).jpg/\1.jpg/" *

() 匹配的内容取出来放到替换部分。


2018-01-31 linux , command , rename , file

mybatis 中 insert 和 insertSeletive 区别

MyBatis generator 自动生成的 mapper 文件中有两个 insert 方法,insertinsertSelective,这两个方法都可以插入一条数据

对于 insert:

int insert(T record);

对于 insertSelective

int insertSelective(T record);

insertSelective 对应的 SQL 语句加入了 NULL 检验,只会插入数据不为 null 的字段,而 insert 会插入所有字段,会插入 null 数据。

也就意味着如果定义了表 default 字段,使用 insert 还是会插入 null 而忽略 default

insertSelective 当字段为 null 时会用 default 自动填充

扩展

同理,更新 update 的操作也有对应的两个方法

  • updateByPrimaryKey 对你注入的字段全部更新(不判断是否为 Null)
  • updateByPrimaryKeySelective 会对字段进行判断再更新(如果为 Null 就忽略更新)

和 insert , insertSelective 类似,带有 selective 的方法会检查对象的值是否 null,如果为 null 则不会更新。


2018-01-30 mybatis , mysql , orm , java

v2ray

v2ray 是一个模块化的代理工具,支持 VMess,Socks,HTTP,Shadowsocks 等等协议,并且附带很多高级功能,HTTP 伪装, TLS 等等。

安装 install

root 账户下执行

bash <(curl -L -s https://install.direct/go.sh)

该脚本会自动安装 unzipdaemon。脚本执行成功后,进行如下操作:

  1. 编辑文件 vim /etc/v2ray/config.json 来配置
  2. 运行 service v2ray start 来启动 v2ray
  3. 使用 service v2ray start|stop|status|reload|restart|force-reload 来控制 v2ray

配置 config

v2ray 使用 JSON 格式的配置文件,大致配置格式如下:

{
  "log": {},
  "dns": {},
  "routing": {},
  "policy": {},
  "inbound": {},
  "outbound": {},
  "inboundDetour": [],
  "outboundDetour": [],
  "transport": {}
}

更加详细的配置详解可以参考官方的文档

v2ray 支持以下协议,默认的协议为 VMess

  • Blackhole
  • Dokodemo-door
  • Freedom
  • HTTP
  • Shadowsocks
  • Socks
  • VMess

如果想要修改 clients 下面的 id,可以访问 https://www.uuidgenerator.net/ 网站生成 UUID,对于服务端配置来说,主要关心 inbound 中配置,包括端口,协议,和 id 以及 alterId。这些配置需要和客户端一致。

{
  "log" : {   //日志配置
    "access": "/var/log/v2ray/access.log", //访问日志
    "error": "/var/log/v2ray/error.log",   //错误日志
    "loglevel": "warning" //日志等级
  },
  "inbound": {   // 主传入连接
    "port": 10800,  // 端口
    "protocol": "vmess",  //协议
    "settings": {
      "clients": [
        {
          "id": "d931e571-c9d2-4527-9223-9ef1cdeaf4b2",  // 客户端需要和服务端一致
          "level": 1,
          "alterId": 64   // 客户端需要和服务端一致
        }
      ]
    }
  },
  "outbound": {
    "protocol": "freedom",
    "settings": {}
  },
  "outboundDetour": [
    {
      "protocol": "blackhole",
      "settings": {},
      "tag": "blocked"
    }
  ],
  "routing": {
    "strategy": "rules",
    "settings": {
      "rules": [
        {
          "type": "field",
          "ip": [
            "0.0.0.0/8",
            "10.0.0.0/8",
            "100.64.0.0/10",
            "127.0.0.0/8",
            "169.254.0.0/16",
            "172.16.0.0/12",
            "192.0.0.0/24",
            "192.0.2.0/24",
            "192.168.0.0/16",
            "198.18.0.0/15",
            "198.51.100.0/24",
            "203.0.113.0/24",
            "::1/128",
            "fc00::/7",
            "fe80::/10"
          ],
          "outboundTag": "blocked"
        }
      ]
    }
  }
}

观察服务端配置基本上能看到两大块重点,一个重点就是 inbound 另一个重点就是 outbound,对应客户端也是同样的配置,对于服务端来说,他的流入就是客户端的流出,对于服务端来说,需要在 inbound 中配置,然后客户端需要在 outbound 中配置和服务端一致的配置,然后就能连入。

客户端配置

根据自己的系统选择下载客户端版本: https://github.com/v2ray/v2ray-core/releases

客户端配置中,需要特殊关心的就是 outbound 中内容,需要关心服务器地址,端口,ID,和 alterId。

{
  "inbound": {
    "port": 1080, // 监听端口
    "protocol": "socks", // 入口协议为 SOCKS 5
    "settings": {
      "auth": "noauth"  //socks的认证设置,noauth 代表不认证,由于 socks 通常在客户端使用,所以这里不认证
    }
  },
  "outbound": {
    "protocol": "vmess", // 出口协议
    "settings": {
      "vnext": [
        {
          "address": "serveraddr.com", // 服务器地址,请修改为你自己的服务器 ip 或域名
          "port": 16823,  // 服务器配置端口
          "users": [
            {
              "id": "b831381d-6324-4d53-ad4f-8cda48b30811",  // 用户ID,必须与服务器端配置相同
              "alterId": 64 // 此处的值也应当与服务器相同
            }
          ]
        }
      ]
    }
  }
}

总的来说,各大客户端只需要关心几个配置,服务器地址,配置协议,端口,及认证方式。对于 VMess 协议,需要知道 id,alterId。

Linux

下载对应 Linux 的客户端,执行 ./v2ray --config=config.json 来启动客户端,如果看到日志正常表示已经连接成功。

Windows/MacOS

类似 Linux,启动客户端配置本地,其他选择还有

Windows 下 V2RayW, MacOS 下 V2RayX

Android

Android 客户端现在为止有 V2RayNG、Actinium,本人测试前一个比较好用,但是也存在问题,长时间连接容易掉线。

Play Store 链接 备用 GitHub 地址

iOS

使用 ShadowRocket,美区下载,支持 VMess 协议。如果没有 ShadowRocket ,其他可供选择的还有 Kitsunebi 和 ShadowRay ,如果App Store搜不到请用美区账号。

安装 ShadowRocket 还有一个简单的方法,搜索 爱思助手

reference


2018-01-26 linux , windows , mac , socks , http , shadowsocks , proxy , vmess

自建网络硬盘 ownCloud

ownCloud 是一个文件分享服务,可以将个人的文件内容,比如文本,图片,音频等等存储到一个中心服务器上,类似于 Dropbox。但是与 Dropbox 不同之处在于 ownCloud 是开源的,任何人都可以检视其源代码并且可以为之贡献代码,这意味着他将文件的控制权交给了个人,敏感的文件任何人都无法查看,但于此同时他也将文件的安全交给了个人管理。

ownCloud 安装

安装之前确保有 sudo 权限,并且 ownCloud 需要

  • web 服务器,比如 nginx 或者 Apache
  • 数据库 MySQL
  • PHP

安装

apt install nginx mysql-server php7.0 php-bz2 php-curl php-gd php-imagick php-intl php-mbstring php-xml php-zip

更多的安装详细教程可以查看 DigitalOcean 的教程

Nextcloud

按照教程 使用 snap 安装。

或者手动安装

reference


2018-01-25 linux , cloud , drive , owncloud

使用 Celery Once 来防止 Celery 重复执行同一个任务

使用 Celery 的时候发现有的时候 Celery 会将同一个任务执行两遍,我遇到的情况是相同的任务在不同的 worker 中被分别执行,并且时间只相差几毫秒。这问题我一直以为是自己哪里处理的逻辑有问题,后来发现其他人 也有类似的问题,然后基本上出问题的都是使用 Redis 作为 Broker 的,而我这边一方面不想将 Redis 替换掉,就只能在 task 执行的时候加分布式锁了。

不过在 Celery 的 issue 中搜索了一下,有人使用 Redis 实现了分布式锁,然后也有人使用了 Celery Once。 大致看了一下 Celery Once ,发现非常符合现在的情况,就用了下。

Celery Once 也是利用 Redis 加锁来实现,他的使用非常简单,参照 GitHub 的使用很快就能够用上。Celery Once 在 Task 类基础上实现了 QueueOnce 类,该类提供了任务去重的功能,所以在使用时,我们自己实现的方法需要将 QueueOnce 设置为 base

@task(base=QueueOnce, once={'graceful': True})

后面的 once 参数表示,在遇到重复方法时的处理方式,默认 graceful 为 False,那样 Celery 会抛出 AlreadyQueued 异常,手动设置为 True,则静默处理。

另外如果要手动设置任务的 key,可以指定 keys 参数

@celery.task(base=QueueOnce, once={'keys': ['a']})
def slow_add(a, b):
    sleep(30)
    return a + b

总得来说,分为几步

第一步,安装

pip install -U celery_once

第二步,增加配置

from celery import Celery
from celery_once import QueueOnce
from time import sleep

celery = Celery('tasks', broker='amqp://guest@localhost//')
celery.conf.ONCE = {
  'backend': 'celery_once.backends.Redis',
  'settings': {
    'url': 'redis://localhost:6379/0',
    'default_timeout': 60 * 60
  }
}

第三步,修改 delay 方法

example.delay(10)
# 修改为
result = example.apply_async(args=(10))

第四步,修改 task 参数

@celery.task(base=QueueOnce, once={'graceful': True, keys': ['a']})
def slow_add(a, b):
    sleep(30)
    return a + b

更多详细的参数可以参考 GitHub,或者直接阅读源码。

reference


2018-01-24 celery , celery-once , redis , broker , queue , task , unique , python

pipenv 使用

pipenv 是目前官方 推荐使用的包管理工具。能够为项目创建和管理虚拟环境,从 Pipfile 文件添加或删除安装的包,Pipfile.lock 来锁定安装包的版本和依赖信息。

  • 不用再维护 requirements.txt, 使用 Pipfile 和 Pipfile.lock 来代替
  • 在安装了 pyenv 的条件下,可以自动安装需要的 Python 版本

这里就不得不提到 pyenv 了,pyenv 能用来管理不同的 Python 版本,结合 pyenv-virtualenv 也能够快速创建虚拟环境,不过这个 pipenv 提供了另外一种思路。

安装

pip install pipenv

基本使用

  • 虚拟环境如果不存在的话,会自动创建
  • --three / --two Use Python 3/2 when creating virtualenv.

常用命令

指定 Python 版本信息

在创建虚拟环境时,我们可以使用 python 版本信息

pipenv --python 3
pipenv --python 3.6.1
pipenv --python 2.7.13

pipenv 会自动扫描系统寻找合适的版本信息,如果找不到的话,同时又安装了 pyenv, 它会自动调用 pyenv 下载对应的版本的 python

安装包

类似 pip

pipenv install requests
pipenv install requests==2.19.1
pipenv install --dev requests       # 安装开发环境依赖

如果 install 后面没有任何 package 会自动安装所有,第一次安装包会自动生成 lock 文件

兼容 requirements.txt

pipenv install -r path/to/requirements.txt

同样可以使用 PipfilePipfile.lock 文件来生成 requirements.txt

pipenv lock -r
pipenv lock -r -d       # 生成 dev requirements

所以一个基本流程就是,对于 pipenv 管理的项目,使用 pipenv lock 来冻结管理,在分享给别人之后使用 pipenv install 来安装依赖。

指定安装包源

直接修改 Pipfile 文件

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[[source]]
url = "http://pypi.home.kennethreitz.org/simple"
verify_ssl = false
name = "home"

[dev-packages]

[packages]
requests = {version="*", index="home"}
maya = {version="*", index="pypi"}
records = "*"

激活和退出当前虚拟环境

pipenv shell
exit

图形显示包依赖关系

pipenv graph
requests==2.19.1
  - certifi [required: >=2017.4.17, installed: 2018.8.13]
  - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
  - idna [required: >=2.5,<2.8, installed: 2.7]
  - urllib3 [required: >=1.21.1,<1.24, installed: 1.23]

删除所有的安装包

pipenv uninstall --all

检查代码

pipenv 默认集成了 flake8

pipenv check --style hello.py

区别

关于 pipenv 和 pyenv 等等其他的区别,可以看这个回答 ,如果想要在 Intellij 中使用 pipenv ,2018.2 更新的版本中,也已经支持 了。

pipenv 也使用 pyenv 来做 Python 的版本管理,所以基本上,分工明确了,pyenv 用来区分 Python 版本,pipenv 用来管理包依赖。

reference


2018-01-23 python , virtualenv , pyenv , pipenv

又一款抓包分析软件 wireshark

Wireshark 是一款网络分析工具,也是学习网络协议的工具,原先介绍过的 Charlesmitmproxy 等 HTTP 抓包工具,都局限于 HTTP/HTTPS 请求,对于更底层的 TCP/IP,UDP 等协议就无能为力了。Wireshark 可以抓取网卡上的网络包,并实时展示,Wireshark 包括了过滤器,协议显示等等工具。

Wireshark 和其他工具的区别,比如 Charles,mitmproxy,Fiddler 等。Charles, mitmproxy,Fiddler 是专门用来捕获 HTTP,HTTPS 请求的。Wireshark 能获取 HTTP,也能获取 HTTPS,但是不能解密 HTTPS,所以 Wireshark 看不懂 HTTPS 中的内容。总结,如果是处理 HTTP,HTTPS 还是用 Charles, mitmproxy, Fiddler 等,其他协议比如 TCP,UDP,IP,ICMP 等就用 Wireshark

安装

各大系统的安装文件:https://www.wireshark.org/download.html

Linux 下可以使用 PPA

sudo add-apt-repository ppa:wireshark-dev/stable && sudo apt-get update
sudo apt-get install wireshark

安装过程中选择 YES,让普通用户也能够抓包。

如果启动之后遇到

couldn't run /usr/bin/dumpcap in child process: Permission Denied.

这样的问题,

sudo dpkg-reconfigure wireshark-common

选择 “YES”, 将当前用户添加到 group

sudo adduser $USER wireshark

然后再登出登入 1

简单使用

打开 Wireshark 就可以看到很多网络硬件可以选择,任选其中一块网卡就能够抓取经过这个网卡的所有流量包。常见的设备名字,或者网卡名字有这样几个:

  • eth0 物理网卡,一般连接网线会获取到 IP 地址
  • eth1 第二块网卡
  • wlan0 是无线网卡,一般连接无线网会获取到 IP 地址
  • lo 设备虚拟端口,自身回环,一般指向 127.0.0.1

还有一些设备名字可以参考之前的文章。比如我笔记本使用无线网卡连接了 WIFI,那么进入 Wireshark 之后选择 wlan0 设备,自动进入抓包,可以看到经过无线网卡的所有请求包。

wireshark-windows

Wireshark 的界面大致可以分成三个部分,最上面的部分为原始数据包预览,可以在该面板中看到抓取的包大致内容,包括序号,耗时,原始地址,目标地址,协议,长度,基本信息等等,分别使用不同的颜色标记了,这个颜色可以在设置 View -> Coloring Rules 中设置,根据不同的协议,或者自定义一些过滤规则,将关心的内容以不同的颜色标记出。

面板中间是封包详细信息 (Packet Details Pane),这个面板是最重要的,用来查看协议中的每一个字段。各行信息分别为

  • Frame: 物理层的数据帧概况
  • Ethernet II: 数据链路层以太网帧头部信息
  • Internet Protocol Version 4: 互联网层 IP 包头部信息
  • Transmission Control Protocol: 传输层 T 的数据段头部信息,此处是 TCP
  • Hypertext Transfer Protocol: 应用层的信息,此处是 HTTP 协议

面板最下面一栏是数据包真正传输的内容,以十六进制和 ASCII 显示出来。

过滤器

https://wiki.wireshark.org/CaptureFilters

两种过滤器的目的是不同的。

捕捉过滤器(CaptureFilters):用于决定将什么样的信息记录在捕捉结果中。需要在开始捕捉前设置。捕捉过滤器是数据经过的第一层过滤器,它用于控制捕捉数据的数量,以避免产生过大的日志文件。

显示过滤器(DisplayFilters):在捕捉结果中进行详细查找。他们可以在得到捕捉结果后随意修改。显示过滤器是一种更为强大(复杂)的过滤器。它允许您在日志文件中迅速准确地找到所需要的记录。

两种过滤器使用的语法是完全不同的。

http://openmaniak.com/cn/wireshark_filters.php

三次握手

Wireshark 实际分析下三次握手的过程

在 wireshark 中输入 http 过滤, 然后选中 GET /tankxiao HTTP/1.1 的那条记录,右键然后点击”Follow TCP Stream”,

这样做的目的是为了得到与浏览器打开网站相关的数据包

可以看到 wireshark 截获到了三次握手的三个数据包。第四个包才是 HTTP 的, 这说明 HTTP 的确是使用 TCP 建立连接的。

第一次握手数据包

客户端发送一个 TCP,标志位为 SYN,序列号为 0, 代表客户端请求建立连接。

第二次握手的数据包

服务器发回确认包,标志位为 SYN,ACK. 将确认序号 (Acknowledgement Number) 设置为客户的 ISN 加 1 以. 即 0+1=1

第三次握手的数据包

客户端再次发送确认包 (ACK) SYN 标志位为 0,ACK 标志位为 1. 并且把服务器发来 ACK 的序号字段 +1, 放在确定字段中发送给对方. 并且在数据段放写 ISN 的 +1

  1. https://askubuntu.com/a/778170/407870 


2018-01-16 wireshark , charles , mitmproxy , proxy

电子书

最近文章

  • Git worktree 作用及使用 在偶然逛 Stackoverflow 的时候看到一个提问,能不能在同一个 repo 中同时有两份代码,并且可以保持两份相似但不是完全相同的代码并行开发?虽然对其需求有些好奇和疑惑 ,但也关注了一下下方的回答。
  • CPU 负载 之前在 Openwrt 负载 中也曾经谈到过 CPU 的负载,通过 top, uptime 等等命令都可以非常快速的查询当前 CPU 的负载。
  • Jenkins 使用 流水线任务
  • jks pem cer pfx 不同种类的证书 通常在安全级别较高的场景经常需要对通信信息进行加密传输,有一种情况就是非对称加密,将信息使用对方提供的公钥加密传输,然后对方接收到之后使用私钥解密。今天在对接时对方发送了一个压缩包,其中包含了 SSL 不同类型的证书,包括了 jks, pem, cer, pfx 等等文件,现在就来了解一下。
  • Spring 中的 @Transactional 注解 Spring 中有两种不同方式实现事务 —- annotations 和 AOP。