linux捕捉信号sigint失败,为shell布置陷阱:trap捕捉信号方法论

本文目录:

1.1 信号说明

1.2 trap布置陷阱

1.3 布置完美陷阱必备知识

家里有老鼠,快消灭它!哎,又给跑了。老鼠这小东西跑那么快,想直接直接消灭它还真不那么容易。于是,老鼠药、老鼠夹子或老鼠笼就派上用场了,它们都是陷阱,放在那静静地等待着老鼠的光顾。

在shell中,也可以捉"老鼠",捉到"老鼠"后,可以无视它、杀死它或者抓起来逗一番。只需使用内置命令trap(中文就翻译为陷阱、圈套)就可以布置一个陷阱,这个陷阱当然不是捕老鼠的,而是捕捉信号。

通常trap都在脚本中使用,主要有2种功能:

(1).忽略信号。当运行中的脚本进程接收到某信号时(例如误按了CTRL+C),可以将其忽略,免得脚本执行到一半就被终止。

(2).捕捉到信号后做相应处理。主要是清理一些脚本创建的临时文件,然后退出。

1.1 信号说明

详细的信号说明见:信号。常见的信号以及它们的数值代号、说明如下:

Signal Value Comment

─────────────────────────────

SIGHUP1终止进程,特别是终端退出时,此终端内的进程都将被终止

SIGINT2 中断进程,几乎等同于sigterm,会尽可能的释放执行clean-up,释放资源,保存状态等(CTRL+C)

SIGQUIT3从键盘发出杀死(终止)进程的信号

SIGKILL9 强制杀死进程,该信号不可被捕捉和忽略,进程收到该信号后不会执行任何clean-up行为,所以资源不会释放,状态不会保存

SIGTERM15 杀死(终止)进程,几乎等同于sigint信号,会尽可能的释放执行clean-up,释放资源,保存状态等

SIGSTOP19该信号是不可被捕捉和忽略的进程停止信息,收到信号后会进入stopped状态

SIGTSTP20 该信号是可被忽略的进程停止信号(CTRL+Z)

每个信号其真实名称并非是SIGXXX,而是去除SIG后的单词,每个信号还有其对应的数值代号,在使用信号时,可以使用这3种方式中的任一一种。例如SIGHUP,它的信号名称为HUP,数值代号为1,发送HUP信号时,以下3种方式均可。

kill -1PIDkill -HUP PIDkill -SIGHUP PID

在上面所列的信号列表中,KILL和STOP这两个信号无法被捕捉。一般来说,在设置信号陷阱时,只会考虑HUP、INT、QUIT、TERM这4个会终止、中断进程的信号。

1.2 trap布置陷阱

trap的语法格式为:

1. trap [-lp]2. trap cmd-body signal_list3. trap ''signal_list4. trap signal_list5. trap -signale_list

语法说明:

语法1:-l选项用于列出当前系统支持的信号列表,和"kill -l"一样的作用。-p选项用于列出当前shell环境下已经布置好的陷阱。

语法2:当捕捉到给定的信号列表中的某个信号时,就执行此处给定cmd-body中的命令。

语法3:命令参数为空字符串,这时shell进程和shell进程内的子进程都会忽略信号列表中的信号。

语法4:省略命令参数,重置陷阱为启动shell时的陷阱。不建议此语法,当给定多个信号时结果会出人意料。

语法5:等价于语法4。

trap不接任何参数和选项时,默认为"-p"。

(1).查看当前shell已布置的陷阱。

[root@linuxidc ~]# trap

trap-- ''SIGTSTP

trap-- ''SIGTTIN

trap-- '' SIGTTOU

这3个陷阱都是信号忽略陷阱,当捕获到TSTP、TTIN或TTOU信号时,将不做任何处理。

(2).设置一个可以忽略CTRL+C和15信号的陷阱。

[root@linuxidc ~]# trap ''SIGINT SIGTERM

[root@linuxidc~]# trap

trap-- ''SIGINT

trap-- ''SIGTERM

trap-- ''SIGTSTP

trap-- ''SIGTTIN

trap-- '' SIGTTOU

这样一来,当前的shell就无法被kill -15杀死。

[root@linuxidc ~]# kill $BASHPID;echo killcurrent bash failedkill current bash failed

(3).设置一个陷阱,当这个陷阱捕捉到15信号时,就打印一条消息。

[root@linuxidc ~]# trap 'echo caught the TERM signal'TERM

[root@linuxidc~]# kill$BASHPID

caught the TERM signal

再查看已设置的陷阱,之前设置为忽略TERM信号的陷阱已经被覆盖。

[root@linuxidc ~]# trap

trap-- ''SIGINT

trap-- 'echo caught the TERM signal'SIGTERM

trap-- ''SIGTSTP

trap-- ''SIGTTIN

trap-- '' SIGTTOU

(4).重置针对INT和TERM这两个信号的陷阱为初始状态。

[root@linuxidc ~]# trap -SIGINT SIGTERM

[root@linuxidc~]# trap

trap-- ''SIGTSTP

trap-- ''SIGTTIN

trap-- '' SIGTTOU

(5).在脚本中设置一个能忽略CTRL+C和SIGTERM信号的陷阱。

[root@linuxidc ~]# cat trap1.sh#!/bin/bash

# script_name: trap1.sh#

trap''SIGINT SIGTERMsleep 10

echo sleep success

当执行该脚本后,将首先陷入睡眠状态,按下CTRL+C将无效。仍会执行完所有的命令。

[root@linuxidc ~]# ./trap1.sh

^C^C^C^Csleep success

(6).布置一个当脚本中断时能清理垃圾并退出立即脚本的陷阱。

[root@linuxidc ~]# cat trap1.sh#!/bin/bash

# script_name: trap1.sh#

trap'echo trap handling...;rm -rf /tmp/$BASHPID$BASHPID;echo TEMP file cleaned;exit'SIGINT SIGTERM SIGQUIT SIGHUPmkdir -p /tmp/$BASHPID$BASHPID/

touch /tmp/$BASHPID$BASHPID/{a.txt,a.log}sleep 10

echo first sleepsuccesssleep 10

echo second sleep success

这样,无论是什么情况中断(除非是SIGKILL),脚本总能清理掉临时垃圾。

1.3 布置完美陷阱必备知识

(1).陷阱的守护对象是shell进程本身,不会守护shell环境内的子进程。但如果是信号忽略型陷阱,则会守护整个shell进程组使其忽略给定信号。

以下面这个脚本为例,设置的陷阱会捕捉到SIGING和SIGTERM两个信号,捕捉到信号时将输出陷阱做出处理的时间点。

[root@linuxidc ~]# cat trap2.sh#!/bin/bash

# script_name: trap2.sh#

trap'echo trap_handle_time: $(date +"%F %T")'SIGINT SIGTERMecho time_start: $(date +"%F %T")sleep 10

echo time_end1: $(date +"%F %T")sleep 10

echo time_end2: $(date +"%F %T")

执行该脚本,并另开一个会话窗口,杀死trap2.sh脚本。

[root@linuxidc ~]# ./trap2.sh[root@linuxidc~]# killall -s SIGTERM trap2.sh

执行结果如下。

time_start: 2017-08-14 12:59:23trap_handle_time:2017-08-1412:59:33time_end1:2017-08-14 12:59:33time_end2:2017-08-14 12:59:43

结果中的trap_handle_time证明,脚本所在shell进程收到SIGTERM信号后,trap成功进行了处理。如果细心的话,会发现trap处理的时间正好是10秒之后,这并不是因为正好10秒之后才发送SIGTERM信号,而是因为trap就是这么工作的,这是另一个需要注意的点,稍后见下文的(2)。

再次执行脚本,在另个会话窗口下杀死脚本中正在运行的sleep进程和trap2.sh脚本所在进程。

[root@linuxidc ~]# ./trap2.sh[root@linuxidc~]# killall -s SIGTERM sleep ;sleep 3; killall -s SIGINT trap2.sh # 另一个会话终端下执行此命令

最终将返回如下结果:

time_start: 2017-08-14 12:23:06Terminated # 接收到对sleep发送的SIGTERM信号

time_end1:2017-08-14 12:23:09# 没有trap_handle_time,陷阱没有守护sleep进程

trap_handle_time:2017-08-14 12:23:19# shell进程本身收到了SIGINT信号,并被陷阱处理了

time_end2:2017-08-14 12:23:19

结果说明脚本中的trap陷阱没有守护shell内的sleep进程,只守护了shell本身。同样也发现了,虽然是在3秒后发送INT信号给脚本进程,但陷阱同样是在10秒之后才开始处理的。

再修改脚本中的陷阱为信号忽略陷阱。

[root@linuxidc ~]# cat ./trap3.sh#!/bin/bash

# script_name: trap3.sh#

trap''SIGINT SIGTERMecho time_start: $(date +"%F %T")sleep 10

echo time_end1: $(date +"%F %T")sleep 10

echo time_end2: $(date +"%F %T")

执行trap3.sh,并在另一个会话终端下杀死sleep进程。

[root@linuxidc ~]# ./trap3.sh[root@linuxidc~]# killall -s SIGTERM sleep;sleep 3;killall -s SIGINT sleep # 另一个会话终端下执行此命令

结果如下。从时间差可以看出,无论是SIGTERM还是SIGINT信号,sleep进程都被忽略型trap守护了。

time_start: 2017-08-14 12:31:54time_end1:2017-08-14 12:32:04time_end2:2017-08-14 12:32:14

(2).如果shell中针对某信号设置了陷阱,则该shell进程接收到该信号时,会等待其内正在运行的命令结束才开始处理陷阱。

其实(1)中的几个示例的结果已经证明了这一点。只要是向shell进程发送的信号,都会等待当前正在运行的命令结束后才处理信号,然后继续脚本向下运行。

(3).CTRL+C和SIGINT不是等价的。当某一时刻按下CTRL+C,它是在向整个当前运行的进程组发送SIGINT信号。对shell脚本来说,SIGINT不仅发送给shell脚本进程,还发送给脚本中当前正在运行的进程。

所以,如果shell中设置SIGINT陷阱,不仅会终止脚本中当前正在运行的进程,trap还会立即进行对应的处理。

以下面的脚本trap4.sh为例。

[root@linuxidc ~]# cat trap4.sh#!/bin/bash

# script_name: trap4.sh#

trap'echo trap_handle_time: $(date +"%F %T")'SIGINTecho time_start: $(date +"%F %T")sleep 10

echo time_end1: $(date +"%F %T")sleep 10

echo time_end2: $(date +"%F %T")

如果使用kill命令向trap4.sh发送信号,正常情况下trap会在当前运行的sleep进程完成后才进行相关处理。但如果是按下CTRL+C,先看结果。

[root@linuxidc ~]# ./trap4.shtime_start:2017-08-14 13:41:30

^Ctrap_handle_time: 2017-08-14 13:41:31time_end1:2017-08-14 13:41:31

^Ctrap_handle_time: 2017-08-14 13:41:32time_end2:2017-08-14 13:41:32

结果中显示,两次按下CTRL+C后,不仅sleep立刻结束了,trap也立即进行处理了。这说明CTRL+C不仅让脚本进程收到了SIGINT信号,也让当前正在运行的进程收到了SIGINT信号。

需要特别说明的是,如果当前正在运行的进程处在循环内,当该进程收到了终止进程后,仅仅只是立即终止当次进程,而不会终止整个循环,也就是说,它还会继续向下执行后续命令并进入下一个循环。如果此时是使用CTRL+C发送SIGINT,则每次CTRL+C时,trap也会一次次进行处理。

注意点(1)(2)(3)很重要,因为搞清楚了它们,才能明白脚本中当前正在运行的进程是先完成还是立即结束,这在写复杂脚本或任务型脚本极其重要。例如大量文档中www.example.com需要替换成www.example.net,假如使用sed进行处理,我们肯定不希望替换了一部分文件的时候被临时终止。

(4).每个陷阱都有守护范围。每一个陷阱只将守护它后面的所有进程,直到遇到下一个相同信号的陷阱。

以shell脚本为例,如下图所示。

39eb77ec19c6270de2dcc14e6480beb5.png

(5).当shell环境下设置了信号忽略陷阱时,子shell在启动时将继承该陷阱,且这些信号忽略陷阱不可再改变或重置。信号忽略陷阱是子shell唯一继承的陷阱类型。

先在当前shell环境下设置一个忽略SIGINT的陷阱,和一个不忽略SIGTERM的陷阱。

[root@linuxidc ~]# trap ''SIGINT

[root@linuxidc~]# trap 'echo haha' SIGTERM

以下是测试脚本。脚本中首先输出脚本刚启动时的最初陷阱列表,随后修改陷阱并输出新的陷阱列表,最后重置陷阱并输出重置后的陷阱列表。

[root@linuxidc ~]# cat trap6.sh#!/bin/bash

# script_name: trap6.sh

echo old_trap:--------trap-p

trap'echo haha'SIGINT SIGTERMecho new_trap:--------trap-pecho "reset trap:------"trap-SIGINT SIGTERM

trap-p

执行结果如下。

[root@linuxidc ~]# ./trap6.shold_trap:--------trap-- ''SIGINT

new_trap:--------trap-- ''SIGINT

trap-- 'echo haha'SIGTERM

reset trap:------trap-- '' SIGINT

从结果中可以看出,启动脚本时,父shell中忽略SIGINT的陷阱被继承了,但不忽略信号的陷阱未被继承。而且脚本继承的信号忽略陷阱无法被修改和重置。

(6).交互式的shell下,如果没有定义任何SIGTERM信号的陷阱,则会忽略该信号。

所以,在默认(未定义SIGTERM陷阱)时,无法直接通过15信号杀死当前bash进程。

[root@linuxidc ~]# kill $BASHPID;echo passed;kill -9$BASHPID

passed

# 此处当前bash已被kill-9强制杀死

(7).除了kill -l或trap -l列出的信号列表,trap还有4种特殊的信号:EXIT(或信号代码0)、ERR、DEBUG和RETURN。DEBUG和RETURN这两种信号陷阱无需关注。

EXIT信号也是0信号,当设置了EXIT陷阱时,每次exit的时候都会被捕捉,并做相关处理。

ERR陷阱是在设置了"set -e"时生效的,当设置了"set -e"选项,每次遇到非0退出状态码时会退出当前shell,如果写在脚本中,就是退出脚本。有了它就不用再在脚本中书写对"$?"是否(不)等于0的判断语句,不过它主要用于避免脚本中产生错误时,错误被滚雪球式的不断放大。很多人将这一设置当作写shell脚本的一项行为规范,但我个人不完全认同,很多时候非0退出状态码是无关紧要的,甚至有时候非0状态码才是继续执行的必要条件。

回到话题上。先看看"set -e"的效果。以下面的脚本为例,在脚本中,mv命令少给了一个参数,它是错误命令,返回的是非0状态码。

[root@linuxidc ~]# vim trap8.sh#!/bin/bash

set-eecho "right here"

mv ~/a.txt

["$?" -eq 0 ] && echo "right again" || echo "wrong here"

如果不设置"set -e",那么会被下一条语句判断,但因为设置了"set -e",使得在mv错误发生时,就立即退出脚本所在的shell。也就是说,对"$?"的判断语句根本就是多余的。结果如下。

[root@linuxidc ~]# ./trap8.shright heremv: missing destination file operand after ‘/root/a.txt’

Try'mv --help' for more information.

可以设置ERR陷阱,专门捕获"set -e"起作用时的信号。例如,当命令错误时,做一些临时文件清理动作等。注意,当捕获到了ERR信号时,脚本不会再继续向下运行,而是trap处理结束后就立即退出。例如:

[root@linuxidc ~]# vim trap8.sh#!/bin/bash

set-e

trap'echo continue'ERRecho "right here"

mv ~/a.txt

["$?" -eq 0 ] && echo "right again" || echo "wrong here"

echo haha

执行结果如下:

[root@linuxidc ~]# ./trap8.shright heremv: missing destination file operand after ‘/root/a.txt’

Try'mv --help' for moreinformation.

continue

(8).在trap中两个很好用的变量:BASH_COMMAND和LINENO。BASH_COMMAND变量记录的是当前正在执行的命令行,如果是用在陷阱中,则记录的是陷阱触发时正在运行的命令行。LINENO记录的是正在执行的命令所处行号。

例如:

[root@linuxidc ~]# vim trap8.sh#!/bin/bash

set-e

trap'echo "error line: $LINENO,error cmd: $BASH_COMMAND"'ERRecho "right here"

mv ~/a.txt

执行结果。

[root@linuxidc ~]# ./trap8.shright heremv: missing destination file operand after ‘/root/a.txt’

Try'mv --help' for moreinformation.

error line:5,error cmd: mv ~/a.txt

(9).处理脚本中启动的后台进程。

通常trap在脚本中的作用之一是在突然被中断时清理一些临时文件然后退出,虽然它会等待脚本中当前正在运行的命令结束,然后清理并退出。但是,很多时候会在脚本中使用后台进程,以加快脚本的速度。而后台进程是独立挂靠在init/systemd下的,所以它不受终端以及shell环境的影响。换句话说,当脚本突然被中断时,即使陷阱捕获到了该信号,并清理了临时文件后退出,但是那些脚本中启动的后台进程还会继续运行。

这就给脚本带来了一些不可预测性,一个健壮的脚本必须能够正确处理这种情况。trap可以实现比较好的解决这种问题,方法是在trap的命令行中加上向后台进程发送信号的语句,然后再退出。

以下面的脚本为例。

[root@linuxidc ~]# vim trap10.sh#!/bin/bash

trap'echo first trap $(date +"%F %T");exit'SIGTERMecho first sleep $(date +"%F %T")sleep 20 &

echo second sleep $(date +"%F %T")sleep 5

该脚本中首先将一个sleep放入后台运行。正常情况下,该脚本执行5秒后就会退出,但在20秒后后台进程sleep才会结束,即使突然发送中断信号TERM触发trap也一样。

于是现在的目标是,在sleep 5的过程中突然中断脚本时,能杀死后台sleep进程。可以使用"!"这个特殊变量。修改后的脚本如下。

[root@linuxidc ~]# vim trap10.sh#!/bin/bash

trap'echo first trap $(date +"%F %T");kill $pid;exit'SIGTERMecho first sleep $(date +"%F %T")sleep 20 &pid="$!"

sleep 30 &pid="$! $pid"

echo second sleep $(date +"%F %T")sleep 5

执行该脚本,并在另一个会话窗口发送SIGTERM信号给该脚本进程。

[root@linuxidc ~]# ./trap10.sh ; ps aux | grep sleep[root@linuxidc~]# kill trap10.sh # 另一个会话窗口执行

执行结果如下。可见sleep被正常终止。

first sleep 2017-08-14 21:29:19secondsleep 2017-08-14 21:29:19first trap2017-08-14 21:29:24root69096 0.0 0.0 112644 952 pts/0 S+ 21:29 0:00 grep --color=auto sleep

0b1331709591d260c1c78e86d0c51c18.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/496182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Trade Stages - The Trade Path

Gieno Trade Stages - The Trade Path STARTS OFF “greed orientated.”Loses because:1 Market problemsNot a zero sum game, a “very negative” sum gameMarket psychology – doing the wrong thing at the wrong timeThe majority is always wrongMarket exists on ch…

win10、oneplus7pro 使用 Kali

1、Windows 10 使用 Kali Linux子系统 微软为 Windows Subsystem for Linux (WSL) 带来了著名的 Kali Linux ,无虚拟机,无Docker实现Windows 和 Kali Linux 交互。 window 开启 wsl 功能: 1.打开控制面板( winR,输入…

干货|十大产业方向深度解析!《2020科技产业趋势报告》

来源:机器人大讲堂报告下载:https://pan.baidu.com/s/1BKf2rINXx0CVLhgokfYrgQ未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能,互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括:建立AI智能系统智商评…

交互式数据包处理程序 Scapy 用法

From:https://www.cnblogs.com/hongxueyong/p/5641475.html Scapy 用法官方文档:http://scapy.readthedocs.io/en/latest/#starting-scapyAbout ScapyScapy is a Python program that enables the user to send, sniff and dissect and forge network pa…

展望2021年:智能机器人可监督工业机器人干活,效率提升30%

来源:极客网会帮我们吸地板、在公共场所担任导引员或是拆除炸弹的机器人呢可能感觉比较有趣,但那些负责组装汽车以及在工厂生产在线帮忙拾取物品的机器人,在整体价值上要高得多,而且也有越来越多的工/商业或消费性应用产品是由这种…

ASP。NET的设计思想

自从有了html与http,就有了浏览器与Web服务器,并有了Web应用,最初的交互模式是这样的: 该模式很好地运行了很多年。然而,随着计算机应用的发展,人们越来越不满足于只有静态内容的页面,而由某种机…

Kali linux 渗透测试技术之搭建WordPress Turnkey Linux及检测WordPress 应用程序漏洞

From:https://bbs.ichunqiu.com/thread-15716-1-1.html 怎样用 WPScan,Nmap 和 Nikto 扫描和检查一个 WordPress 站点的安全性:https://www.cnblogs.com/chayidiansec/p/7989274.html 为了收集用于测试的应用程序, Turnkey Linux…

AI芯片格局分布

来源:中国科学院自动化研究所 作者: 吴军宁如果说2016年3月份AlphaGo与李世石的那场人机大战只在科技界和围棋界产生较大影响的话,那么2017年5月其与排名第一的世界围棋冠军柯洁的对战则将人工智能技术推向了公众视野。阿尔法狗(…

科学互驳:大脑细胞活到老,长到老?

来源:中国生物技术网 作者:格格科学家发现,人脑中与学习、记忆和情感相关的区域在成年后依然会持续产生新的神经元。这与过去的理论恰恰相反,即青春期之后大脑停止产生新的神经元。这项发现有助于我们开发治疗神经系统疾病的新方…

AI综述专栏 | 朱松纯教授浅谈人工智能:现状、任务、构架与统一

作者:朱松纯来源:人工智能前沿讲习班导读本文作者:朱松纯,加州大学洛杉矶分校UCLA统计学和计算机科学教授,视觉、认知、学习与自主机器人中心主任。文章前四节浅显探讨什么是人工智能和当前所处的历史时期,…

联想linux笔记本评测,联想(lenovo)G460AL-ITH Linux笔记本电脑接口评测-ZOL中关村在线...

模具和外观的“革新”让我们见识到不一样的联想G460,而在整机的接口扩展能力方面依旧主打实用性。机身左侧从左至右依次是安全锁孔、散热孔、RJ-45以太网接口、VGA视频输出接口、USB2.0接口、e-SATA接口(兼容USB2.0)、Express Card卡槽和HDMI高清视频输出接口。与前…

联合国召开会议讨论“杀手机器人”问题

来源:中国科学报 作者:赵熙熙来自29个国家的57位科学家日前呼吁联合抵制一所韩国大学,因为设立在该校的一个新的中心旨在利用人工智能强化国家安全。人工智能科学家表示,该大学正在开发自主武器,又称“杀手机器人”&a…

【转】近期Coolite控件的技术点总结

1。Coolite下如何自定义控件样式表Code1<style type"text/css"> 2 .x-grid3-td-fullName .x-grid3-cell-inner {}{ 3 font-family:tahoma, verdana; 4 display:block; 5 font-weight:normal; 6 font-style…

Anaconda 完全入门指南

From&#xff1a;https://www.jianshu.com/p/eaee1fadc1e9 Anaconda官网&#xff1a;https://www.anaconda.com/ Anaconda 官网 文档&#xff1a;http://docs.anaconda.com/anaconda/user-guide Anaconda介绍、安装及使用教程&#xff1a;https://zhuanlan.zhihu.com/p/32925…

linux资源使用统计指南,指南:工作量分析文档

指南&#xff1a;工作量分析文档工作量分析文档工作量分析文档用于在不同的性能测试中确定要使用的变量并定义变量值&#xff0c;利用这些性能测试可以模拟主角特征、最终用户业务功能(用例)、负载和容量。主题软件质量要从不同的维度来进行评估&#xff0c;其中包括可靠性、功…

Python爬取大量数据时防止被封IP

From&#xff1a;http://blog.51cto.com/7200087/2070320 基于scrapy框架的爬虫代理IP设置&#xff1a;https://www.jianshu.com/p/074c36a7948c Scrapy: 针对特定响应状态码&#xff0c;使用代理重新请求&#xff1a;http://www.cnblogs.com/my8100/p/scrapy_middleware_aut…

最近发包给朋友,搞定软件小活儿、解决小功能模块的感受

有时候也想&#xff0c;所有的事情都靠自己解决&#xff0c;太辛苦了太累了&#xff0c;在不差钱的这个年代&#xff0c;有些能让别人做的事情&#xff0c;就让别人做吧&#xff0c;但是一直找不到合适的人&#xff0c;什么叫合适的人&#xff1f;我简单的说几下&#xff0c;不…

利用自定义web-font实现数据防采集

From&#xff1a;https://blog.csdn.net/fdipzone/article/details/68166388 完整源码&#xff1a;https://download.csdn.net/download/fdipzone/9798142 web-font介绍 web-font 是 CSS3 中的一种标记 font-face&#xff0c;在 font-face 声明里&#xff0c;你可以声明一种字…

数字证书~证书链

来源&#xff1a;客户端认证https服务端证书过程详解——证书链_huzhenv5的博客-CSDN博客_证书链认证过程 基本概念 证书 首先&#xff0c;我们看看在wikipedia上对证书的定义&#xff0c;In cryptography, a public key certificate (also known as a digital certificate o…

反反爬技术,破解猫眼网加密数字

From&#xff1a;https://blog.csdn.net/qq_31032181/article/details/79153578 From&#xff1a;http://www.freebuf.com/news/140965.html 利用自定义web-font实现数据防采集&#xff1a;http://blog.csdn.net/fdipzone/article/details/68166388 利用前端字体文件(.ttf)混…