Sign-Magnitude, Ones' Complement, Two's Complement 为什么要使用原码、反码、补码

为什么要使用原码 反码 补码. 前言: 随着学习计算机知识的加深,许多地方都遇到原码、反码、补码。很多关于计算机的书籍都介绍原码、反码、补码的表示方法,但是为什么要用到原码、反码、补码却没详细说。为什么要使用?它们的原理是什么呢?我搜索了许多资料,也查找了许多书籍,终于弄明白了这个问题,收集整理如下。 我们知道数值在计算机中表示形式为机器数,计算机只能识别0和1,使用的是二进制。而在日常生活中人们使用的是十进制,并且我们用的数值有正负之分。于是在计算机中就用一个数的最高位存放符号(0为正,1为负)。这就是机器数的原码了。 有了数值的表示方法就可以对数进行算术运算,但是很快就发现用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题,如下: 假设字长为8bits (1) <sub>10</sub> - (1)<sub>10</sub> = (1)<sub>10</sub> + (-1)<sub>10</sub> = (0)<sub>10</sub> (0 0000001)<sub>原</sub> + (1 0000001)<sub>原</sub> = (1 0000010)<sub>原</sub> = ( -2 )显然不正确。 因为在两个整数的加法运算中是没有问题的,于是就发现问题出现在带符号位的负数身上。对除符号位外的其余各位逐位取反就产生了反码。反码的取值空间和原码相同且一一对应。下面是反码的减法运算: (1)<sub>10</sub> - (1)<sub>10</sub> = (1)<sub>10</sub> + (-1)<sub>10</sub> = (0)<sub>10</sub> (0 0000001)<sub>反</sub> + (1 1111110)<sub>反</sub> = (1 1111111)<sub>反</sub> = ( -0 )有问题。 (1)<sub>10</sub> - (2)<sub>10</sub> = (1)<sub>10</sub> + (-2)<sub>10</sub> = (-1)<sub>10</sub> (0 0000001)<sub>反</sub> + (1 1111101)<sub>反</sub> = (11111110)<sub>反</sub> = (-1)正确。 ...

Created 3036-07-03 · Updated 9096-10-09 · 1 min · 154 words · -

关于 XML standalone 的解释

关于 XML standalone 的解释 http://www.blogjava.net/javafuns/articles/257525.html XML standalone 定义了外部定义的 DTD 文件的存在性. standalone element 有效值是 yes 和 no. 如下是一个例子: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE s1 PUBLIC "http://www.ibm.com/example.dtd" "example.dtd"> <s1>.........</s1> 值 no 表示这个 XML 文档不是独立的而是依赖于外部所定义的一个 DTD. 值 yes 表示这个 XML 文档是自包含的(self-contained). 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 xml-standalone.md;url 改为 xml-standalone;旧 url 加入 aliases;categories 改为 CS 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 8086-11-08 · Updated 9096-10-09 · 1 min · 62 words · -

ISO 8859-1

ISO 8859-1 ISO/IEC 8859-1,又称Latin-1或"西欧语言",是国际标准化组织内ISO/IEC 8859的第一个8位字符集。它以ASCII为基础,在空置的0xA0-0xFF的范围内,加入192个字母及符号,藉以供使用变音符号的拉丁字母语言使用。 此字符集支援部分于欧洲使用的语言,包括阿尔巴尼亚语、巴斯克语、布列塔尼语、加泰罗尼亚语、丹麦语、荷兰语、法罗语、弗里西语、加利西亚语、德语、格陵兰语、冰岛语、爱尔兰盖尔语、意大利语、拉丁语、卢森堡语、挪威语、葡萄牙语、里托罗曼斯语、苏格兰盖尔语、西班牙语及瑞典语。 英语虽然没有重音字母,但仍会标明为ISO 8859-1编码。除此之外,欧洲以外的部分语言,如南非荷兰语、斯瓦希里语、印尼语及马来语、菲律宾他加洛语等也可使用ISO 8859-1编码。 法语及芬兰语本来也使用ISO 8859-1来表示。但因它没有法语使用的 œ、Œ、 Ÿ 三个字母及芬兰语使用的 Š、š、Ž、ž ,故于1998年被ISO/IEC 8859-15所取代。 (ISO 8859-15同时加入了欧元符号) ISO/IEC 8859-2 Latin-2或"中欧语言",是国际标准化组织内ISO/IEC 8859的其中一个8位字符集 ISO/IEC 8859-3 南欧语言字符集 ISO/IEC 8859-4 北欧语言字符集 ISO/IEC 8859-5 是国际标准化组织内ISO/IEC 8859的其中一个8位字符集。此字集收录西里尔字母,供俄语、白俄罗斯语、保加利亚语、马其顿语、塞尔维亚语、乌克兰语使用。(哈萨克语及蒙古语尽管不是斯拉夫文字,但也使用西里尔字母书写) ISO/IEC 8859-6 供现代阿拉伯语使用 ISO/IEC 8859-7 供现代希腊语使用 ISO/IEC 8859-8 供希伯来语使用 ISO/IEC 8859-9是国际标准化组织内ISO/IEC 8859的其中一个8位字符集。它主要用以表示土耳其语及库尔德语文字。 这个字符集由ISO/IEC 8859-1演化而来,它把原属冰岛语的 &ETH;、&eth;、&Yacute;、&yacute;、&THORN;、&thorn; 字母移走,换上 Ğ、ğ、İ、ı、Ş、ş 六个土耳其语字母。 ISO/IEC 8859-10 北欧语言 ISO/IEC 8859-11 泰语 ISO/IEC 8859-12 取消 ISO/IEC 8859-13 波罗的语 ISO/IEC 8859-14 爱尔兰,马恩岛,苏格兰盖尔语,威尔士语,康沃尔,和布列塔尼 ISO/IEC 8859-15 西欧语 ISO/IEC 8859-16 阿尔巴尼亚,克罗地亚,匈牙利,波兰,罗马尼亚,塞尔维亚,斯洛文尼亚,但也有法国,德国,意大利和爱尔兰的盖尔 (新正字法) 。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;categories 改为 CS 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 3036-06-03 · Updated 9096-10-09 · 1 min · 92 words · -

XML 编码

xml 编码 前同天和同事在讨论xml里的encoding属性和文件格式的关系,终于彻底的弄清楚了。 以前理解的是,xml里的encoding里定义必须与文件格式相匹配。即有这样的xml Introduction <?xml encoding="utf-8" .. ?>,那么,文件格式必须是一个utf-8文件,即文件的前两个字节要是一个utf-8头FF FE。 (后来才弄清楚,FF FE不是utf-8的BOM。。就是说我的错误理解持续了相当长一段时间。。) 下面把讨论的几个阶段大概说一下。 刚开始讨论时,我很肯定的告诉他,encoding的值必须和文件格式 (即BOM,BOM就是 byte order mark的缩写) 相匹配,不然在解析XML时,可能会出现 (比如文档含有某个UNICODE字符,而encoding或BOM指定的格式不匹配,就会出错,当时我是这样的意思) ,然后他又告诉我,好像不是这样,我用DELPHI创建的XML文件,没有BOM,XML里面有中文内容,encoding里指定的是UTF-8,用IE可以正常打开啊。 他在发现他所创建的XML文件没有BOM时,有个有趣的地方,就是用UE打开这类含有UNICODE字符的文件时,UE会自动在文件前面加上FF FE,使得文件可以正常显示,所以原本没有BOM的文件,在UE下的十六进制下浏览,会看到多了个BOM,这个功能可以在UE的OPTIONS里去掉的,想知道的可以自己去找找。 然后我有点大头了,怎么会这样呢,然后想啊想,突然他发了一条信息过来,内容如下: W3C定义了三条XML解析器如何正确读取XML文件的编码的规则: 1,如果文挡有BOM(字节顺序标记,一般来说,如果保存为unicode格式,则包含BOM,ANSI则无),就定义了文件编码 2,如果没有BOM,就查看XML声明的编码属性 3,如果上述两个都没有,就假定XML文挡采用UTF-8编码 有了这三条规则,那这个规则就清楚多了。 首先,XML解析器根据文件的BOM来解析文件;如果没找到BOM,由用XML里的encoding属性指定的编码;如果xml里encoding没指定的话,就默认用utf-8来解析文档。然后又可以推出,BOM和ENCODING都有的话,则以BOM指定的为准。 啊!突然觉得有标准文档多好!虽然是那么的理所当然。 至此,终于把xml里的encoding和文件格式的关系弄懂了。虽然这篇记录只有那几百个字内容,但是我们当时在讨论的时候,总时间差不多花了2个小时。 http://blog.csdn.net/fzy112001/article/details/4183139 http://www.cnblogs.com/azol/articles/1137035.html 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 xml-encoding.md;title 改为「XML 编码」;url 改为 xml-encoding;旧 url 加入 aliases 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 10106-06-10 · Updated 9096-10-09 · 1 min · 58 words · -

死锁 (Deadlocks)

死锁 (Deadlocks) deadlocks (死锁) 所谓死锁 (Deadlock): 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程. 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。 一种情形,此时执行程序中两个或多个线程发生永久堵塞 (等待) ,每个线程都在等待被其他线程占用并堵塞了的资源。例如,如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象。 计算机系统中,如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。 产生死锁的原因主要是: (1) 因为系统资源不足。 (2) 进程运行推进的顺序不合适。 (3) 资源分配不当等。 如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则 就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。 产生死锁的四个必要条件: (1) 互斥条件: 一个资源每次只能被一个进程使用。 (2) 请求与保持条件: 一个进程因请求资源而阻塞时,对已获得的资源保持不放。 (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之 一不满足,就不会发生死锁。 死锁的解除与预防: 理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和 解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确 定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态 的情况下占用资源,在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配 。因此,对资源的分配要给予合理的规划。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 deadlocks.md;url 改为 deadlocks;旧 url 加入 aliases;categories 改为 CS 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 24246-10-24 · Updated 9096-10-09 · 1 min · 64 words · lcf

Regex Lazy Matching 正则惰性匹配 .*?

正则, 惰性匹配(lazy) .*? http://www.nowamagic.net/librarys/veda/detail/1038 使用场景 有时,我们想用正则匹配以某个子串开头,且以某个子串或字符结尾的子字符串,但是结尾的字串或字符在原字符串中出现了多次,但我们只想匹配从开始处到第一次出现的地方,换句话说,想得到开始和结尾之间内容最少的匹配。 正则的贪婪与非贪婪(惰性) 通常使用如下字符类描述前导字符的重复特征: ?: 告诉引擎匹配前导字符0次或一次。事实上是表示前导字符是可选的。 +: 告诉引擎匹配前导字符1次或多次。 *: 告诉引擎匹配前导字符0次或多次。 {min, max}: 告诉引擎匹配前导字符min次到max次。min和max都是非负整数。如果有逗号而max被省略了,则表示max没有限制;如果逗号和max都被省略了,则表示重复min次。 因此 {0,} 和 * 一样,{1,} 和 + 的作用一样。 贪婪 默认情况下,? + * {min, max}都是贪婪的,也就是说,它会根据前导字符去匹配尽可能多的内容。 非贪婪(惰性) 非贪婪就是匹配尽可能少的内容。 原理浅析 结合实例来分析哈基于正则的引擎对文本的匹配过程。原始字符串:This is a <EM>first</EM> test,使用正则 <.+> 来匹配HTML标签,期望第一次匹配得到<EM>,第二次匹配得到</EM>,实际却是第一次匹配就得到了 <EM>first</EM>。 来看看匹配过程,第一个记号是 <,这是一个文本字符,匹配其自身。第二个符号是.,匹配了字符E,然后+一直可以匹配其余的字符,直到一行的结束。然后到了换行符,匹配失败(.不匹配换行符)。于是引擎开始对下一个正则表达式符号进行匹配,即试图匹配 >。到目前为止,<.+ 已经匹配了 <EM>first</EM> test。引擎会试图将 > 与换行符进行匹配,结果失败了。于是引擎进行回溯。回溯后的匹配状况是 <.+ 匹配 <EM>first</EM> tes。于是引擎将 > 与 t 进行匹配。显然还是会失败。这个过程继续,直到 <.+ 匹配 <EM>first</EM,> 与 > 匹配。于是引擎找到了一个匹配 <EM>first</EM>。记住,正则导向的引擎是急切的,所以它会急着报告它找到的第一个匹配。而不是继续回溯,即使可能会有更好的匹配,例如<EM>。所以我们可以看到,由于+的贪婪性,使得正则表达式引擎返回了一个最左边的最长的匹配。 如果想得到期望的结果,就需要启用非贪婪模式:<.+?> 总结:如果是贪婪匹配模式,正则引擎会一直匹配到字符串最后;当匹配为false时,就回溯以找到倒数第一个匹配位置,返回匹配结果。 如果是非贪婪匹配模式,正则引擎会匹配到符合pattern的末尾位置那个字符,然后再往后走一步,发现匹配为false时,就回溯以找到最近一个匹配为true的位置,返回匹配结果。 实例 例如,原始字符串: ...

Created 24246-09-24 · Updated 9096-10-09 · 1 min · 103 words · -

Blocking, Non-blocking, Sync, Async 阻塞、非阻塞、同步、异步

阻塞,非阻塞,同步,异步 作者: 萧萧 链接: https://www.zhihu.com/question/19732473/answer/241673170 来源: 知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 IO 概念区分四个相关概念: 同步 (Synchronous) 异步( Asynchronous) 阻塞( Blocking ) 非阻塞( Nonblocking) 这四个概念的含义以及相互之间的区别与联系,并不如很多网络博客所写的那么简单, 通过举一些什么商店购物, 买书买报的例子就能讲清楚。 进程间通信的同步/异步, 阻塞/非阻塞首先强调一点, 网络上很多博文关于同步/异步, 阻塞非阻塞区别的解释其实都经不起推敲。 例如在 严肃 的这一高赞回答中 , 有如下解释 (不准确) : 同步/异步关注的是消息通信机制 (synchronous communication/ asynchronous communication) 。 所谓同步,就是在发出一个调用时,在没有得到结果之前, 该调用就不返回。异步则是相反,调用在发出之后,这个调用就直接返回了, 所以没有返回结果阻塞/非阻塞关注的是程序在等待调用结果 (消息,返回值) 时的状态.阻塞调用是指调用结果返回之前,当前线程会被挂起。 调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。粗一看, 好像同步/ 非同步, 阻塞/非阻塞 是两种维度的概念, 可以分别对待, 但是稍微推敲一下就会发现上述的解释存在不妥之处。如果“同步”是发起了一个调用后, 没有得到结果之前不返回, 那它毫无疑问就是被“阻塞”了 (即调用进程处于 “waiting” 状态) 。如果“异步”调用发出了以后就直接返回了, 毫无疑问, 这个进程没有被“阻塞”。 所以, 上述的解释是不准确的。 让我们看一下《操作系统概念 (第九版) 》中有关进程间通信的部分是如何解释的: 翻译一下就是: 进程间的通信是通过 send() 和 receive() 两种基本操作完成的。具体如何实现这两种基础操作,存在着不同的设计。 消息的传递有可能是阻塞的或非阻塞的 – 也被称为同步或异步的: 阻塞式发送 (blocking send) . 发送方进程会被一直阻塞, 直到消息被接受方进程收到。非阻塞式发送 (nonblocking send) 。 发送方进程调用 send() 后, 立即就可以其他操作。阻塞式接收 (blocking receive) 接收方调用 receive() 后一直阻塞, 直到消息到达可用。非阻塞式接受 (nonblocking receive) 接收方调用 receive() 函数后, 要么得到一个有效的结果, 要么得到一个空值, 即不会被阻塞。上述不同类型的发送方式和不同类型的接收方式,可以自由组合。也就是说, 从进程级通信的维度讨论时, 阻塞和同步 (非阻塞和异步) 就是一对同义词, 且需要针对发送方和接收方作区分对待。———- 下面对理解同步异步,阻塞非阻塞所需的知识点进行详细叙述———————先修知识用户空间和内核空间进程切换 系统调用 (system call) 中断 (interrupt) 进程的阻塞用户空间和内核空间操作系统为了支持多个应用同时运行,需要保证不同进程之间相对独立 (一个进程的崩溃不会影响其他的进程 , 恶意进程不能直接读取和修改其他进程运行时的代码和数据) 。 因此操作系统内核需要拥有高于普通进程的权限, 以此来调度和管理用户的应用程序。于是内存空间被划分为两部分,一部分为内核空间,一部分为用户空间,内核空间存储的代码和数据具有更高级别的权限。内存访问的相关硬件在程序执行期间会进行访问控制 ( Access Control) ,使得用户空间的程序不能直接读写内核空间的内存。有《微机原理》 课程基础同学可以 Google 搜索 DPL, CPL 这两个关键字了解硬件层面的内存访问权限控制细节进程切换上图展示了进程切换中几个最重要的步骤: 当一个程序正在执行的过程中, 中断 (interrupt) 或 系统调用 (system call) 发生可以使得 CPU 的控制权会从当前进程转移到操作系统内核。操作系统内核负责保存进程 i 在 CPU 中的上下文 (程序计数器, 寄存器) 到 PCBi (操作系统分配给进程的一个内存块) 中。从 PCBj 取出进程 j 的CPU 上下文, 将 CPU 控制权转移给进程 j , 开始执行进程 j 的指令。几个底层概念的通俗 (不严谨) 解释: 中断 (interrupt) CPU 微处理器有一个中断信号位, 在每个CPU时钟周期的末尾, CPU会去检测那个中断信号位是否有中断信号到达, 如果有, 则会根据中断优先级决定是否要暂停当前执行的指令, 转而去执行处理中断的指令。 (其实就是 CPU 层级的 while 轮询) 时钟中断( Clock Interrupt )一个硬件时钟会每隔一段 (很短) 的时间就产生一个中断信号发送给 CPU,CPU 在响应这个中断时, 就会去执行操作系统内核的指令, 继而将 CPU 的控制权转移给了操作系统内核, 可以由操作系统内核决定下一个要被执行的指令。系统调用 (system call) system call 是操作系统提供给应用程序的接口。 用户通过调用 systemcall 来完成那些需要操作系统内核进行的操作, 例如硬盘, 网络接口设备的读写等。从上述描述中, 可以看出来, 操作系统在进行进切换时,需要进行一系列的内存读写操作, 这带来了一定的开销: 对于一个运行着 UNIX 系统的现代 PC 来说, 进程切换通常至少需要花费 300 us 的时间进程阻塞上图展示了一个进程的不同状态: New. 进程正在被创建.Running. 进程的指令正在被执行Waiting. 进程正在等待一些事件的发生 (例如 I/O 的完成或者收到某个信号) Ready. 进程在等待被操作系统调度Terminated. 进程执行完毕 (可能是被强行终止的) 我们所说的 “阻塞”是指进程在发起了一个系统调用 (System Call) 后, 由于该系统调用的操作不能立即完成,需要等待一段时间,于是内核将进程挂起为等待 (waiting) 状态, 以确保它不会被调度执行, 占用 CPU 资源。友情提示: 在任意时刻, 一个 CPU 核心上 (processor) 只可能运行一个进程 。I/O System Call 的阻塞/非阻塞, 同步/异步这里再重新审视 阻塞/非阻塞 IO 这个概念, 其实阻塞和非阻塞描述的是进程的一个操作是否会使得进程转变为“等待”的状态, 但是为什么我们总是把它和 IO 连在一起讨论呢?原因是, 阻塞这个词是与系统调用 System Call 紧紧联系在一起的, 因为要让一个进程进入 等待 (waiting) 的状态, 要么是它主动调用 wait() 或 sleep() 等挂起自己的操作, 另一种就是它调用 System Call, 而 System Call 因为涉及到了 I/O 操作, 不能立即完成, 于是内核就会先将该进程置为等待状态, 调度其他进程的运行, 等到 它所请求的 I/O 操作完成了以后, 再将其状态更改回 ready 。操作系统内核在执行 System Call 时, CPU 需要与 IO 设备完成一系列物理通信上的交互, 其实再一次会涉及到阻塞和非阻塞的问题, 例如, 操作系统发起了一个读硬盘的请求后, 其实是向硬盘设备通过总线发出了一个请求,它即可以阻塞式地等待IO 设备的返回结果,也可以非阻塞式的继续其他的操作。 在现代计算机中,这些物理通信操作基本都是异步完成的, 即发出请求后, 等待 I/O 设备的中断信号后, 再来读取相应的设备缓冲区。 但是,大部分操作系统默认为用户级应用程序提供的都是阻塞式的系统调用 (blocking systemcall) 接口, 因为阻塞式的调用,使得应用级代码的编写更容易 (代码的执行顺序和编写顺序是一致的) 。但同样, 现在的大部分操作系统也会提供非阻塞I/O 系统调用接口 (Nonblocking I/O system call) 。 一个非阻塞调用不会挂起调用程序, 而是会立即返回一个值, 表示有多少bytes 的数据被成功读取 (或写入) 。非阻塞I/O 系统调用( nonblocking system call )的另一个替代品是 异步I/O系统调用 (asychronous system call) 。 与非阻塞 I/O 系统调用类似,asychronous system call 也是会立即返回, 不会等待 I/O 操作的完成, 应用程序可以继续执行其他的操作, 等到 I/O 操作完成了以后,操作系统会通知调用进程 (设置一个用户空间特殊的变量值 或者 触发一个 signal 或者 产生一个软中断 或者 调用应用程序的回调函数) 。此处, 非阻塞I/O 系统调用( nonblocking system call ) 和 异步I/O系统调用 (asychronous system call) 的区别是: 一个非阻塞I/O 系统调用 read() 操作立即返回的是任何可以立即拿到的数据, 可以是完整的结果, 也可以是不完整的结果, 还可以是一个空值。而异步I/O系统调用 read () 结果必须是完整的, 但是这个操作完成的通知可以延迟到将来的一个时间点。下图展示了同步I/O 与 异步 I/O 的区别 (非阻塞 IO 在下图中没有绘出) . 注意, 上面提到的 非阻塞I/O 系统调用( nonblocking system call ) 和 异步I/O系统调用 都是非阻塞式的行为 (non-blocking behavior) 。 他们的差异仅仅是返回结果的方式和内容不同。非阻塞 I/O 如何帮助服务器提高吞吐量考虑一个单进程服务器程序, 收到一个 Socket 连接请求后, 读取请求中的文件名,然后读请求的文件名内容,将文件内容返回给客户端。 那么一个请求的处理流程会如下图所示。R 表示读操作W 表示写操作C 表示关闭操作在这个过程中, 我们可以看到, CPU 和 硬盘IO 的资源大部分时间都是闲置的。 此时, 我们会希望在等待 I/O 的过程中继续处理新的请求。方案一: 多进程每到达一个请求, 我们为这个请求新创建一个进程来处理。 这样, 一个进程在等待 IO 时, 其他的进程可以被调度执行, 更加充分地利用 CPU 等资源。问题: 每新创建一个进程都会消耗一定的内存空间, 且进程切换也会有时间消耗, 高并发时, 大量进程来回切换的时间开销会变得明显起来。方案二: 多线程和多进程方案类似,为每一个请求新建一个线程进行处理,这样做的重要区别是, 所有的线程都共享同一个进程空间问题: 需要考虑是否需要为特定的逻辑使用锁。引申问题: 一个进程中的某一个线程发起了 system call 后, 是否造成整个进程的阻塞? 如果会, 那么多线程方案与单进程方案相比就没有明显的改善。解决办法1: 内核支持的线程 (kenerl supported threads) 操作系统内核能够感知到线程, 每一个线程都会有一个内核调用栈 (kenerl stack) 和 保存CPU 寄存器下文的 table 。在这种方案中, 如果 CPU 是多核的, 不同的线程还可以运行在不同的 CPU processor 上。 既实现了IO 并发, 也实现了 CPU 并发。问题: 内核支持线程可移植性差, 其实现对于不同的操作系统而言有所差别。解决办法2: 用户支持的线程 (user supported threads) 内核感知不到用户线程, 每一个用户的进程拥有一个调度器, 该调度器可以感知到线程发起的系统调用, 当一个线程产生系统调用时, 不阻塞整个进程, 切换到其他线程继续运行。 当 I/O 调用完成以后, 能够重新唤醒被阻塞的线程。实现细节: 应用程序基于线程库 thread libray 编写线程库中包含 “虚假的” read(), write(), accept()等系统调用。线程库中的 read(), write(), accept() 的底层实现为非阻塞系统调用 (Non-blocking system call) , 调用后,由于可以立即返回, 则将特定的线程状态标记为 waiting, 调度其他的可执行线程。 内核完成了 IO 操作后, 调用线程库的回调函数, 将原来处于 waiting 状态的线程标记为 runnable.从上面的过程可以看出,用户级支持线程 (User-Supported Threads) 的解决方案基于非阻塞IO系统调用( non-blocking system call) , 且是一种基于操作系统内核事件通知 (event-driven) 的解决方案, 该方案可以降低系统处理并发请求时的进程切换开销。 基于这个方案, 可以引申到更为宽泛的 event-driven progreamming 话题上。 但是这里就不作赘述了。总结: 阻塞/非阻塞, 同步/异步的概念要注意讨论的上下文: 在进程通信层面, 阻塞/非阻塞, 同步/异步基本是同义词, 但是需要注意区分讨论的对象是发送方还是接收方。发送方阻塞/非阻塞 (同步/异步) 和接收方的阻塞/非阻塞 (同步/异步) 是互不影响的。在 IO 系统调用层面 ( IO system call ) 层面, 非阻塞 IO 系统调用 和 异步 IO 系统调用存在着一定的差别, 它们都不会阻塞进程, 但是返回结果的方式和内容有所差别, 但是都属于非阻塞系统调用 ( non-blocing system call ) 2. 非阻塞系统调用 (non-blocking I/O system call 与 asynchronous I/O system call) 的存在可以用来实现线程级别的 I/O 并发, 与通过多进程实现的 I/O 并发相比可以减少内存消耗以及进程切换的开销。编辑于 03-02 ...

Created 13136-11-13 · Updated 9096-10-09 · 3 min · 607 words · -

Date Format 日期格式标准

日期格式标准 如时间为: 2020-01-12T15:17:21 国际标准化组织的国际标准ISO 8601是日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》 原文如下: 日期和时间的组合表示法编辑 合并表示时,要在时间前面加一大写字母T,如要表示北京时间2004年5月3日下午5点30分8秒,可以写成2004-05-03T17:30:08+08:00或20040503T173008+08。 所以这个T date和time合并表示时,中间加个T。 iso 8806的百度地址是: https://baike.baidu.com/item/ISO%208601/3910715?fr=aladdin ———————————————— 版权声明:本文为CSDN博主「chushiyunen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/enthan809882/article/details/103946177 https://www.cnblogs.com/tzyy/p/5099207.html ISO日期格式标准,浏览器到服务器到MySQL中的时区 章节目录 时区简单理解 ISO_8601 日期格式标准 HTML5 input 标签datetime属性 MySQL时区 时区简单理解 https://zh.wikipedia.org/wiki/%E6%97%B6%E5%8C%BA 上面的链接是时区的wiki说明,下面说说我记住的部分: GMT时区是格林威治标准时间,我把它理解为 “真实时间” UTC时区是根据GMT得来的"世界标准时间",它的时间和GMT是相同的 CST可以指下列的时区: 澳洲中部时间,Central Standard Time (Australia) 中部标准时区 (北美洲) ,Central Standard Time (North America) 北京时间,China Standard Time 古巴标准时间,Cuba Standard Time,参见北美东部时区 其中我们所在的时区背景时间 CST=UTC+8小时,也就是说,真实时间是0点的时候,背景时间是8点 ISO_8601日期格式标准 https://zh.wikipedia.org/wiki/ISO_8601 上面是日期格式标准的wiki 当前的UTC时间是2016-01-07T01:58Z, 其中Z是4位数字格式的时间偏移量, 不写的时候默认不偏移。 其中,字母T代表使用UTC时间,字母Z代表时间偏移量,实际写法中字母Z应该被偏移量替换,例如 “2017-1-7T10:21+0800"或者"2017-1-7T10:21-0800”,字母Z被+0800和-0800替换了。 在浏览器中直接new一个date对象,因为我们处于UTC+0800的时区,所以控制台给我们打印出来的时间是GMT+0800的时间 2016-01-07T00:00 代表UTC时区1月7日0时0分 (在控制台中显示UTC+0800时区为8时0分) 2016-01-07T00:00 0800 代表UTC+0800时区1月7日0时0分,2016-01-07T00:00 -0800 代表UTC-0800时区1月7日0时0分,在控制台中显示分别如下 ...

Created 25256-07-25 · Updated 9096-10-09 · 2 min · 245 words · -

ASCII、Unicode、UTF-8 编码的区别

ASCII、Unicode,UTF-8编码的区别 Unicode unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。 UCS 通用字符集 (Universal Character Set,UCS) 是由ISO制定的ISO 10646 (或称ISO/IEC 10646) 标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。 UNICODE与UCS实际上是两个不同组织的产物,为了编码一体化而进行协商,可以把unicode看做UCS-2的父集,UCS-4的子集,以为UNICODE只支持U+0FFFF-U+10FFFF的编码,而UCS-4支持31个平面。 https://www.jianshu.com/p/1a39be00f5b8 Unicode ASCII UTF-8 GBK关系 首先必须知道一个概念 - 字符集 计算机中的所有字符, 说到底都是用二进制的 0/1 排列组合来表示的, 因此就需要有一个规范来规定每个字符对应 0/1 排列组合, 这样的规范就是字符集. Unicode, ASCII, GB2312, GBK 都是字符集. UTF-8不是! ASCII 最早的计算机在设计时采用 8 个 bit 作为一个字节 - byte, 所以, 一个字节能表示的范围就是 00000000 到 11111111, 也就是 0 到 255, 一共 256 种状态, 每一个状态对应一个符号, 可以表示 256 个符号. 美国有关的标准化组织就出台了 ASCII 编码, 对英语字符, 数字以及部分符号与二进制位之间的关系, 做了统一规定, 一共规定了 128 个字符的编码. 只占用了一个字节的后面 7 位, 最前面一位统一规定为 0, 一直沿用至今. ...

Created 24246-10-24 · Updated 9096-10-09 · 3 min · 584 words · -

race condition, 竞态条件

race condition 数据争用 (data race) 和竞态条件 (race condition) 在有关多线程编程的话题中,数据争用 (data race) 和竞态条件 (race condition) 是两个经常被提及的名词,它们两个有着相似的名字,也是我们在并行编程中极力避免出现的。但在处理实际问题时,我们应该能明确区分它们两个。 数据争用 (data race) 定义: 多个线程对于同一个变量、同时地、进行读/写操作的现象并且至少有一个线程进行写操作。 (也就是说,如果所有线程都是只进行读操作,那么将不构成数据争用) 后果: 如果发生了数据争用,读取该变量时得到的值将变得不可知,使得该多线程程序的运行结果将完全不可预测,可能直接崩溃。 如何防止: 对于有可能被多个线程同时访问的变量使用排他访问控制,具体方法包括使用mutex (互斥量) 和monitor (监视器) ,或者使用atomic变量。 竞态条件 (race condition) 竞态条件(race conditions),多个线程以非一致性的顺序同时访问数据资源 相对于数据争用,竞态条件(race condition) 指的是更加高层次的更加复杂的现象,一般需要在设计并行程序时进行细致入微的分析,才能确定。 (也就是隐藏得更深) 定义: 受各线程上代码执行的顺序和时机的影响,程序的运行结果产生 (预料之外) 的变化。 后果: 如果存在竞态条件(race condition),多次运行程序对于同一个输入将会有不同的结果,但结果并非完全不可预测,它将由输入数据和各线程的执行顺序共同决定。 如何预防: 竞态条件产生的原因很多是对于同一个资源的一系列连续操作并不是原子性的,也就是说有可能在执行的中途被其他线程抢占,同时这个“其他线程”刚好也要访问这个资源。解决方法通常是: 将这一系列操作作为一个 critical section (临界区) 。 代码示例 下面以C++实现的一个银行存款转账操作为例,说明数据争用(data race) 和竞态条件(race condition)的区别。 该系统的不変性条件: 存款余额≥0,不允许借款。 3.1.数据争用的例子 int my_account = 0; //我的账户余额 int your_account = 100; //你的账户余额 // 转账操作: 存在数据争用(data race)! bool racy_transfer(int& src, int& dst, int m) { if (m <= src) { //操作结果不可预测 src -= m; //操作结果不可预测 dst += m; //操作结果不可预测 return true; } else { return false; } } // 将下面两个函数在两个线程分别运行 racy_transfer(your_account, my_account, 50); racy_transfer(your_account, my_account, 80); 运行上面的的代码后,不光我们双方账号的余额不可预测,甚至整个系统会发生什么事情都无法保证。 ...

Created 1016-07-01 · Updated 9096-10-09 · 2 min · 294 words · -

编译器指令重排, Compiler Instruction Reordering

编译器指令重排, Compiler Instruction Reordering compiler的主要工作就是将对人们可读的源码转化成机器语言,机器语言就是对CPU可读的代码。因此,compiler可以在背后做些不为人知的事情。我们考虑下面的C语言代码: int a, b; void foo(void) { a = b + 1; b = 0; } 使用 aarch64-linux-gnu-gcc 在不优化代码的情况下编译上述代码,使用 objdump 工具查看 foo() 反汇编结果 <foo>: … ldr w0, [x0] // load b to w0 add w1, w0, #0x1 … str w1, [x0] // a = b + 1 ... str wzr, [x0] // b = 0 我们应该知道 Linux 默认编译优化选项是-O2,因此我们采用-O2 优化选项编译上述代码,并反汇编得到如下汇编结果: <foo>: ldr w2, [x0] // load b to w2 str wzr, [x0] // b = 0 add w0, w2, #0x1 str w0, [x1] // a = b + 1 比较优化和不优化的结果,我们可以发现。在不优化的情况下,a 和 b 的写入内存顺序符合代码顺序 (program order)。但是-O2 优化后,a 和 b 的写入顺序和 program order 是相反的。-O2优化后的代码转换成C语言可以看作如下形式: ...

Created 9096-07-09 · Updated 9096-10-09 · 3 min · 586 words · -

foo 是什么意思

Foo 是什么意思 参考:http://www.cnblogs.com/felicity/archive/2010/11/30/1892100.html 不管是 Java、C++ 还是 PHP,每次都能看到 foo = bar 的例子,这两个单词很让人费解,foo 查不到字典,bar 的解释又让人跟编程联系不上,更弄不清楚这个神秘的 foo 是个什么关系。 语意不清,学起来心里老是有疙疙瘩瘩的感觉,于是查吧,终于揭开了这两个东西的不正常关系,讲给各个处在闹心中的初学者们听吧。 参考了众多的网络资料,最后,明确地告诉大家,foo 和 bar 就是外国人的张三、李四、王二麻子,只是一种随便的命名方式,跟 C 语言里面的 i、j、k 同出一辙。 也就是说 foo = bar 跟"变量张三 = 李四的侄子"是一个意图,所以童鞋们就不要再找 foo 到底是个啥了。 问 foo 是啥就跟问张三是谁一样,我想外国人一定也很想知道张三到底是谁,这个人怎么这么有名,总能看到这个名字,但是历史上记载却又找不到他。 为了这个可恶的 foo,居然还动用 RFC 给 foo 下了一个明确的词源追踪,无聊的童鞋可以看 RFC 3092 解解闷。 民间说法 下面是网上搜刮来的各种解释: Foo:本意指程序员用来代表数据、功能或命令的变量。O’Reilly 媒体认为 FOO 是 Friends of O’Reilly 的缩写,并把他们在 2003 年举办的年会命名为 “2003 FOO”,现在则更多地指声势浩大的某行业大会 foo = fuck oriented object foo 是"你要让它是什么就是什么",FOO 可以具有用户赋予的任何意义 foo 是潦草的意思,表示很随便的定义 foo 没有意义 foo 的意思是 Factory Of Objects foo:一塌糊涂;bar:一团糟 foo 不同的字典对其解释相去甚远,一说来自中国"福"字的发音,又有解释为二战时期的一种武器。然而若把众多的解释放在编程领域,关于 foobar 的说法是最贴切的解释:foobar 又为 foo-bar,其中 bar 是 beyond all recognition 的缩写,通俗点就是无法识别、一塌糊涂的意思,而 foo 是 fu 的变体,fu 是英语习语 fuck-up 的缩写,同样是一团糟的意思。于是,若你有些编程经验,应该已经明白了为何如今许多编程实例所涉及的事物均被冠名为 foo。 ...

Created 4046-04-04 · Updated 16166-07-16 · 6 min · 1067 words · -

Android APK 加壳技术方案

Android APK加壳技术方案 本文章由Jack_Jia编写,转载请注明出处。 文章链接: http://blog.csdn.net/jiazhijun/article/details/8678399 作者: Jack_Jia 邮箱: 309zhijun@163.com 一、什么是加壳? 加壳是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作。大多数病毒就是基于此原理。PC EXE文件加壳的过程如下: 二、加壳作用 加壳的程序可以有效阻止对程序的反汇编分析,以达到它不可告人的目的。这种技术也常用来保护软件版权,防止被软件破解。 三、Android Dex文件加壳原理 PC平台现在已存在大量的标准的加壳和解壳工具,但是Android作为新兴平台还未出现APK加壳工具。Android Dex文件大量使用引用给加壳带来了一定的难度,但是从理论上讲,Android APK加壳也是可行的。 在这个过程中,牵扯到三个角色: 加壳程序: 加密源程序为解壳数据、组装解壳程序和解壳数据 解壳程序: 解密解壳数据,并运行时通过DexClassLoader动态加载 源程序: 需要加壳处理的被保护代码 阅读该文章,需要您对DEX文件结构有所了解,您可以通过以下网址了解相关信息: http://blog.csdn.net/jiazhijun/article/details/8664778 根据解壳数据在解壳程序DEX文件中的不同分布,本文将提出两种Android Dex加壳的实现方案。 (一) 解壳数据位于解壳程序文件尾部 该种方式简单实用,合并后的DEX文件结构如下。 加壳程序工作流程: 加密源程序APK文件为解壳数据 把解壳数据写入解壳程序Dex文件末尾,并在文件尾部添加解壳数据的大小。 修改解壳程序DEX头中checksum、signature 和file_size头信息。 修改源程序AndroidMainfest.xml文件并覆盖解壳程序AndroidMainfest.xml文件。 解壳DEX程序工作流程: 读取DEX文件末尾数据获取借壳数据长度。 从DEX文件读取解壳数据,解密解壳数据。以文件形式保存解密数据到a.APK文件 通过DexClassLoader动态加载a.apk。 (二) 解壳数据位于解壳程序文件头 该种方式相对比较复杂, 合并后DEX文件结构如下: 加壳程序工作流程: 加密源程序APK文件为解壳数据 计算解壳数据长度,并添加该长度到解壳DEX文件头末尾,并继续解壳数据到文件头末尾。 (插入数据的位置为0x70处) 修改解壳程序DEX头中checksum、signature、file_size、header_size、string_ids_off、type_ids_off、proto_ids_off、field_ids_off、 method_ids_off、class_defs_off和data_off相关项。 分析map_off 数据,修改相关的数据偏移量。 修改源程序AndroidMainfest.xml文件并覆盖解壳程序AndroidMainfest.xml文件。 解壳DEX程序工作流程: 从0x70处读取解壳数据长度。 从DEX文件读取解壳数据,解密解壳数据。以文件形式保存解密数据到a.APK 通过DexClassLoader动态加载a.APK。 四、加壳及脱壳代码实现 http://blog.csdn.net/jiazhijun/article/details/8809542

Created 20206-03-20 · Updated 5056-06-05 · 1 min · 62 words · -

Android APK 反编译

Android APK反编译 http://blog.csdn.net/ithomer/article/details/6727581 这段时间在学Android应用开发,在想既然是用Java开发的应该很好反编译从而得到源代码吧,google了一下,确实很简单,以下是我的实践过程。 在此郑重声明,贴出来的目的不是为了去破解人家的软件,完全是一种学习的态度,不过好像通过这种方式也可以去汉化一些外国软件。 本文Android反编译教程,测试环境: Win7 Ultimate x64 Ubuntu 12.04 x86_x64 反编译工具包 下载 (2012-10-10更新) 一、Apk反编译得到Java源代码 下载上述反编译工具包,打开apk2java目录下的dex2jar-0.0.9.9文件夹,内含apk反编译成java源码工具,以及源码查看工具。 apk反编译工具dex2jar,是将apk中的classes.dex转化成jar文件 源码查看工具jdgui,是一个反编译工具,可以直接查看反编译后的jar包源代码 dex2jar 和 jdgui 最新版本下载,分别见google code: dex2jar (google code) jdgui (google code) ,最新版本请见 官方 具体步骤: 首先将apk文件后缀改为zip并解压,得到其中的classes.dex,它就是java文件编译再通过dx工具打包而成的,将classes.dex复制到dex2jar.bat所在目录dex2jar-0.0.9.9文件夹。 在命令行下定位到dex2jar.bat所在目录,运行 dex2jar.bat classes.dex 生成 classes_dex2jar.jar 然后,进入jdgui文件夹双击jd-gui.exe,打开上面生成的jar包classes_dex2jar.jar,即可看到源代码了,如下图: HelloAndroid源码在反编译前后的对照如下: 二、apk反编译生成程序的源代码和图片、XML配置、语言资源等文件 如果是汉化软件,这将特别有用 首先还是要下载上述反编译工具包,其中最新的apktool,请到google code下载 apktool (google code) 具体步骤: 下载上述反编译工具包,打开apk2java目录下的apktool1.4.1文件夹,内含三个文件: aapt.exe,apktool.bat,apktool.jar 注: 里面的apktool_bk.jar是备份的老版本,最好用最新的apktool.jar 在命令行下定位到apktool.bat文件夹,输入以下命令: apktool.bat d -f abc123.apk abc123,如下图: 上图中,apktool.bat 命令行解释: apktool.bat d -f [apk文件 ] [输出文件夹] 反编译的文件如下 (AndroidManifest.xml为例) : 将反编译完的文件重新打包成apk,很简单,输入apktool.bat b abc123 (你编译出来文件夹) 即可,命令如下: ...

Created 30306-12-30 · Updated 5056-06-05 · 1 min · 93 words · -

加壳与脱壳

加壳与脱壳 http://blog.csdn.net/lzyzuixin/article/details/4104334 加壳一般是指保护程序资源的方法. 脱壳一般是指除掉程序的保护,用来修改程序资源. 病毒加壳技术与脱壳杀毒方法 : 壳是什么?脱壳又是什么?这是很多经常感到迷惑和经常提出的问题,其实这个问题一点也不幼稚。当你想听说脱壳这个名词并试着去了解的时候,说明你已经在各个安全站点很有了一段日子了。下面,我们进入"壳"的世 界吧。 金蝉脱壳的故事 我先想讲个故事吧。那就是金蝉脱壳。金蝉脱壳属于三十六计中的混战计。金蝉脱壳的本意是: 寒蝉在蜕变时,本体脱离皮壳而走,只留下蝉蜕还挂在枝头。此计用于军事,是指通过伪装摆脱敌人,撤退或转移,以实现我方的战略目标的谋略。稳住对方,撤退或转移,决不是惊慌失措,消极逃跑,而是保留形式,抽走内容,稳住对方,使自己脱离险境达到己方战略目标,己方常常可用巧妙分兵转移的机会出击另一部分敌人。三国时期,诸葛亮六出祁山,北伐中原,但一直未能成功,终于在第六次北伐时,积劳成疾,在五丈原病死于军中。 维遵照诸葛亮的吩咐,在诸葛亮死后,秘不发丧,对外严密封锁消息。他带着灵柩,秘密率部撤退。司马懿派部队跟踪追击蜀军。姜维命工匠仿诸葛亮摸样,雕了一个木人,羽扇纶巾,稳坐车中。并派杨仪率领部分人马大张旗鼓,向魏军发动进攻。魏军远望蜀军,军容整齐,旗鼓大张,又见诸葛亮稳坐车中,指挥若定,不知蜀军又耍什么花招,不敢轻举妄动。司马懿一向知道诸葛亮"诡计多端",又怀疑此次退兵乃是诱敌之计,于是命令部队后撤,观察蜀军动向。姜维趁司马懿退兵的大好时机,马上指挥主力部队,迅速安全转移,撤回汉中。等司马懿得知诸葛亮已死,再进兵追击,为时已晚。相信这个故事,大家在大型连续剧《三国演义》里已经看过了。呵呵,只是没有理解得这么深入罢了!而在黑客入侵技术中,金蝉脱壳则是指: 删除系统运行日志 攻击者攻破系统后,常删除系统运行日志,隐藏自己的痕迹…呵呵 二、壳,脱壳,加壳 在自然界中,我想大家对壳这东西应该都不会陌生了,由上述故事,我们也可见一斑。自然界中植物用它来保护种子,动物用它来保护身体等等。同样,在一些计算机软件里也有一段专门负责保护软件不被非法修改或反编译的程序。它们一般都是先于程序运行,拿到控制权,然后完成它们保护软件的任务。就像动植物的壳一般都是在身体外面一样理所当然 (但后来也出现了所谓的"壳中带籽"的壳) 。由于这段程序和自然界的壳在功能上有很多相同的地方,基于命名的规则,大家就把这样的程序称为"壳"了。就像计算机病毒和自然界的病毒一样,其实都是命名上的方法罢了。 从功能上抽象,软件的壳和自然界中的壳相差无几。无非是保护、隐蔽壳内的东西。而从技术的角度出发,壳是一段执行于原始程序前的代码。原始程序的代码在加壳的过程中可能被压缩、加密……。当加壳后的文件执行时,壳-这段代码先于原始程序运行,他把压缩、加密后的代码还原成原始程序代码,然后再把执行权交还给原始代码。 软件的壳分为加密壳、压缩壳、伪装壳、多层壳等类,目的都是为了隐藏程序真正的OEP (入口点,防止被破解) 。关于"壳"以及相关软件的发展历史请参阅吴先生的《一切从"壳"开始》。 壳的概念 作者编好软件后,编译成exe可执行文件。 1.有一些版权信息需要保护起来,不想让别人随便改动,如作者的姓名,即为了保护软件不被破解,通常都是采用加壳来进行保护。 2.需要把程序搞的小一点,从而方便使用。于是,需要用到一些软件,它们能将exe可执行文件压缩, 3.在黑客界给木马等软件加壳脱壳以躲避杀毒软件。实现上述功能,这些软件称为加壳软件。 (二) 加壳软件最常见的加壳软件 ASPACK ,UPX,PEcompact 不常用的加壳软件WWPACK32;PE-PACK ;PETITE NEOLITE (三) 侦测壳和软件所用编写语言的软件 因为脱壳之前要查他的壳的类型。 1.侦测壳的软件fileinfo.exe 简称fi.exe (侦测壳的能力极强) 。 2.侦测壳和软件所用编写语言的软件language.exe (两个功能合为一体,很棒) ,推荐language2000中文版 (专门检测加壳类型) 。 3.软件常用编写语言Delphi,VisualBasic (VB) -最难破,VisualC (VC) 。 (四) 脱壳软件 软件加壳是作者写完软件后,为了保护自己的代码或维护软件产权等利益所常用到的手段。目前有很多加壳工具,当然有盾,自然就有矛,只要我们收集全常用脱壳工具,那就不怕他加壳了。软件脱壳有手动脱和自动脱壳之分,下面我们先介绍自动脱壳,因为手动脱壳需要运用汇编语言,要跟踪断点等,不适合初学者,但我们在后边将稍作介绍。 加壳一般属于软件加密,现在越来越多的软件经过压缩处理,给汉化带来许多不便,软件汉化爱好者也不得不学习掌握这种技能。现在脱壳一般分手动和自动两种,手动就是用TRW2000、TR、SOFTICE等调试工具对付,对脱壳者有一定水平要求,涉及到很多汇编语言和软件调试方面的知识。而自动就是用专门的脱壳工具来脱,最常用某种压缩软件都有他人写的反压缩工具对应,有些压缩工具自身能解压,如UPX;有些不提供这功能,如: ASPACK,就需要UNASPACK对付,好处是简单,缺点是版本更新了就没用了。另外脱壳就是用专门的脱壳工具来对付,最流行的是PROCDUMP v1.62 ,可对付目前各种压缩软件的压缩档。在这里介绍的是一些通用的方法和工具,希望对大家有帮助。我们知道文件的加密方式,就可以使用不同的工具、不同的方法进行脱壳。下面是我们常常会碰到的加壳方式及简单的脱壳措施,供大家参考: 脱壳的基本原则就是单步跟踪,只能往前,不能往后。脱壳的一般流程是: 查壳->寻找OEP->Dump->修复 找OEP的一般思路如下: 先看壳是加密壳还是压缩壳,压缩壳相对来说容易些,一般是没有异常,找到对应的popad后就能到入口,跳到入口的方式一般为。 我们知道文件被一些压缩加壳软件加密,下一步我们就要分析加密软件的名称、版本。因为不同软件甚至不同版本加的壳,脱壳处理的方法都不相同。 常用脱壳工具: 文件分析工具 (侦测壳的类型) : Fi,GetTyp,peid,pe-scan, OEP入口查找工具: SoftICE,TRW,ollydbg,loader,peid dump工具: IceDump,TRW,PEditor,ProcDump32,LordPE PE文件编辑工具PEditor,ProcDump32,LordPE ...

Created 20206-03-20 · Updated 5056-06-05 · 1 min · 154 words · -

PostgreSQL 锁机制

PostgreSQL 的锁机制分为多个层级,从应用层的 Advisory Lock 到行级、表级,再到内核内部的 LWLock,每一层都有其适用场景。 锁的层级总览 层级 类型 由谁控制 可见性 表级锁 8 种模式 SQL 语句或 LOCK TABLE pg_locks 行级锁 4 种模式 SELECT FOR ... pg_locks (元组锁) 页级锁 共享/排他 Buffer Manager 内部 不可见 Advisory Lock 会话级/事务级 应用程序 pg_locks Predicate Lock 谓词锁 串行化隔离级别 (SSI) pg_locks LWLock / Spinlock 内核共享内存保护 内核内部 不可见 表级锁 PostgreSQL 表级锁有 8 种模式,从弱到强排列。冲突意味着两个锁不能被同时持有。 8 种模式 模式 缩写 典型操作 说明 ACCESS SHARE AS SELECT 最弱,只与 ACCESS EXCLUSIVE 冲突 ROW SHARE RS SELECT FOR UPDATE/SHARE 与 EXCLUSIVE、ACCESS EXCLUSIVE 冲突 ROW EXCLUSIVE RE INSERT、UPDATE、DELETE 与 SHARE、SHARE ROW EXCLUSIVE、EXCLUSIVE、ACCESS EXCLUSIVE 冲突 SHARE UPDATE EXCLUSIVE SUE VACUUM、ANALYZE、CREATE INDEX CONCURRENTLY 与自身及更强模式冲突 SHARE S CREATE INDEX(非 CONCURRENTLY) 阻止并发写 SHARE ROW EXCLUSIVE SRE CREATE TRIGGER、部分 ALTER TABLE 比 SHARE 更强,与自身冲突 EXCLUSIVE E REFRESH MATERIALIZED VIEW CONCURRENTLY 只允许并发 ACCESS SHARE(即普通 SELECT) ACCESS EXCLUSIVE AE DROP TABLE、TRUNCATE、ALTER TABLE、LOCK TABLE 最强,与所有模式冲突,阻塞所有操作包括 SELECT 冲突矩阵 AS RS RE SUE S SRE E AE ACCESS SHARE - - - - - - - ✗ ROW SHARE - - - - - - ✗ ✗ ROW EXCLUSIVE - - - - ✗ ✗ ✗ ✗ SHARE UPD EXC - - - ✗ ✗ ✗ ✗ ✗ SHARE - - ✗ ✗ - ✗ ✗ ✗ SHARE ROW EXC - - ✗ ✗ ✗ ✗ ✗ ✗ EXCLUSIVE - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ACCESS EXCL ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ 显式表锁 -- 显式加表锁,默认 ACCESS EXCLUSIVE LOCK TABLE orders; -- 指定模式 LOCK TABLE orders IN SHARE MODE; LOCK TABLE orders IN ROW EXCLUSIVE MODE; -- 非阻塞,获取不到立即失败 LOCK TABLE orders IN ACCESS EXCLUSIVE MODE NOWAIT; 常见场景:批量数据迁移时先 LOCK TABLE ... IN EXCLUSIVE MODE,防止迁移过程中有新写入。 ...

Created 3036-06-03 · Updated 4046-06-04 · 8 min · 1554 words · -

Netty 堆外内存

为什么使用堆外内存 Java 堆内存(Heap)受 JVM GC 管理,分配和释放都有 GC 开销,且在 GC 发生时对象地址可能移动(Compacting GC)。进行 I/O 操作时,JVM 必须先把堆内数据拷贝到一块固定地址的堆外缓冲区,再交给内核。 堆外内存(Direct Memory / Off-Heap)直接由操作系统管理,有以下优势: 零拷贝:内核可以直接读写堆外内存,省掉堆内 → 堆外的一次拷贝 不受 GC 暂停影响:地址固定,内核持有指针不会因 GC 而失效 更可预测的延迟:不参与 Young/Old GC,减少 STW(Stop-The-World)概率 代价是分配/释放成本更高,且不会被 GC 自动回收,需要手动管理生命周期。 ByteBuf:Netty 的核心缓冲区抽象 Netty 用 ByteBuf 替代 JDK 的 ByteBuffer,消除了 flip()/rewind() 的使用负担,并同时支持堆内和堆外两种底层存储。 分类 ByteBuf ├── HeapByteBuf 堆内,byte[] 存储,GC 管理 ├── DirectByteBuf 堆外,java.nio.DirectByteBuffer 存储 └── CompositeByteBuf 零拷贝组合多个 ByteBuf(可混合堆内/堆外) 每种又分 Pooled(池化)和 Unpooled(非池化)两个版本: 类型 分配方式 适用场景 PooledDirectByteBuf 从内存池取 高频、短生命周期 I/O UnpooledDirectByteBuf 每次调用 malloc 低频、大块、长期持有 PooledHeapByteBuf 从内存池取 不需要 native I/O 的场景 UnpooledHeapByteBuf 每次 new byte[] 简单测试/工具代码 零拷贝(Zero-copy) OS 层面的 Zero-copy 指避免在用户态(User-space)与内核态(Kernel-space)之间拷贝数据,例如 Linux 的 mmap、sendfile。Netty 的 Zero-copy 完全在用户态(Java 层面),核心目标是减少 ByteBuf 之间不必要的内存拷贝。 ...

Created 23236-03-23 · Updated 3036-06-03 · 4 min · 678 words · -

网站访问统计:Umami + Cloudflare Web Analytics

背景 Hugo 博客(PaperMod 主题)默认没有访问统计。为了了解谁在访问、访问了哪些页面,选择同时接入两套统计: Umami:隐私友好,无 cookie,数据存储在 Umami 服务器 Cloudflare Web Analytics:与 Cloudflare 基础设施集成,数据存储在 Cloudflare 两者不冲突,可以同时运行,便于对比数据。 Umami 特点 无 cookie,无跨站追踪,不需要 GDPR 同意弹窗 免费 Hobby 计划:100K 事件/月,3 个站点,6 个月数据保留 地理位置精度:国家级别 统计维度 页面浏览量(PV)、独立访客数(UV) 每次会话浏览页数、跳出率、平均停留时间 引荐来源、UTM 参数 国家/地区、操作系统、浏览器、设备类型 各页面访问量排行 Browsers:Chrome、Chrome (iOS) 与 iOS Umami 在 Environment → Browsers 里根据访问请求的 User-Agent(UA) 解析浏览器名称,与 Environment → OS 里的操作系统是两套维度,不要混看。 显示名称 含义 Chrome 桌面端或 Android 等环境下的 Chrome;UA 不含 iOS 专用标记 Chrome (iOS) iPhone / iPad 上用 Chrome App 打开;UA 含 CriOS/版本号 iOS 能判断是 iOS 上的浏览器或 WebView,但 未识别 为 Safari、Chrome、Firefox、Edge 等时的兜底分类 列表里 Chrome (iOS) 与 iOS 各计 1 个访客,通常表示 两次不同访问(不同人或不同设备 / 浏览器),不是同一次访问被记了两遍。 ...

Created 10106-05-10 · Updated 30306-05-30 · 2 min · 341 words · W10N

蓝牙配对

Arch Linux 蓝牙连接键盘 环境 设备:SER8(AMD 小主机) 系统:Arch Linux + KDE 问题:KDE 系统设置蓝牙页面无法发现蓝牙键盘 排查过程 # 检查蓝牙服务状态 systemctl status bluetooth # → inactive (dead),且 disabled # 检查硬件是否被识别 ls /sys/class/bluetooth/ # → hci0(硬件正常识别) # 检查软件包 pacman -Q bluez bluedevil # → bluez 5.86-6 / bluedevil 1:6.6.5-1(已安装) 根本原因 蓝牙硬件正常、驱动正常、软件包齐全,但 bluetooth.service 从未被启用,导致 KDE 蓝牙面板无法扫描任何设备。 解决方法 # 启动蓝牙服务并设置开机自启 sudo systemctl enable --now bluetooth # 可选:安装命令行调试工具 sudo pacman -S bluez-utils 服务启动后,打开 KDE 系统设置 → 蓝牙,将键盘置于配对模式,即可正常发现并配对。 ...

Created 24246-12-24 · Updated 28286-05-28 · 1 min · 127 words · -

协程, Coroutine

协程, Coroutine 协程别名: 微线程,纤程。英文:Coroutine, Green threads, fibers 传统编程语言中子程序或者函数是层级调用的,函数可以调用其它函数, 调用者需要等待被调用者结束之后继续执行, 函数调用是通过栈实现的. 一个线程就是按顺序执行一个或几个子函数, 函数调用只有一个入口和一个出口. 协程看上去也是函数,但是执行过程中在子程序内部可以中断,然后执行别的函数, 然后再被调度回来执行. 协程比线程有更高的执行效率, 协程没有线程切换的开销 协程在用户空间调度, 不涉及系统调用或任何阻塞调用, 不需要用来守卫关键区块的同步性原语(primitive)比如互斥锁、信号量等,并且不需要来自操作系统的支持 协程不需要多线程的锁机制, 为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。 协程是协作式多任务的, 线程典型是抢占式多任务的 因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。 使用抢占式调度的线程实现协程,但是会失去某些利益(特别是对硬性实时操作的适合性和相对廉价的相互之间切换)。 协程是语言层级的构造,可看作一种形式的控制流,而线程是系统层级的构造。 名词对照 coroutine、goroutine、virtual thread、轻量级线程、协程、虚拟线程、用户态线程、绿色线程——这些名词基本上在说同一类东西,只是来自不同语言和时代: 术语 说明 coroutine(协程) 最广义的概念,包括协作式(asyncio)和抢占式(goroutine)两类 goroutine Go 的实现,抢占式,属于协程的子集 virtual thread(虚拟线程) Java 21 的叫法,强调"就是线程,只是轻量" green thread(绿色线程) 早期术语,泛指用户态管理的线程 用户态线程 / 轻量级线程 描述实现机制的技术术语 命名不同有历史原因: Go 作者刻意不叫"协程",因为传统协程是协作式的,而 goroutine 是运行时抢占式调度的,更像轻量级线程 Java 叫"虚拟线程"是为了向后兼容——复用 Thread API,让现有代码改动最小 严格说,asyncio 协程(协作式、无栈)和 goroutine / 虚拟线程(抢占式、有栈)不是一回事,但常被混称为"协程"。 为什么需要用户态线程 OS 线程太重了 一个 OS 线程的代价: 默认栈大小 1~8 MB(Linux 默认 8MB) 创建/销毁需要系统调用,耗时微秒级 上下文切换需要陷入内核,保存/恢复大量寄存器 线程数受 OS 限制,通常几千到几万个 典型场景:一个 HTTP 服务,每个请求一个线程,1 万并发连接 → 80GB 内存光用在栈上,还没开始干活。 ...

Created 4046-02-04 · Updated 11116-05-11 · 4 min · 769 words · -