电子杂志(试刊)
- 1. 听风独奏 www.gbcdbj.com
序
从开始建群.后来的网络课堂,到现在的电子杂志,从一个寥寥数人的群,到现在数十个群,我们一步步
的实现我们帮助他人想法,一步步想让更多的人加入我们.想让更多的初学者得到帮助.曾经身为一个初学
者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人。我
也希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,最应该鄙视的是不肯付出时
的吝啬.
在这里我要特别感谢下 ghost(35797274),小 c++(409143825),cicada(evc++)(286797633)入
土之人(89212740),这些在工作之余预备课程跟大家分享的人..还要感谢 Charm (649453195)和 Hey,
Ranon!(313626493) 两位伙伴.没有他们是不可能有网络课堂也不可能有有现在的电子杂志.更要感谢
各群的群主和管理以及群员.因为有他们的支持我们才有动力.
℡独奏(173925475)
2010 年 4 月写于北京
听风独奏 www.gbcdbj.com
- 2. 听风独奏 www.gbcdbj.com
ABOUT US
Team Leader:独奏 、Team Worker:Ranon 、Team Member:Charm ......
本着原创、分享、共赢的原则,我们吸引了无数有共同爱好的技术爱好者的目光,日益成为技术爱好
者聚集、学习、交流的重要阵地。我们专注于原创、经典、创新的理念,为每一个学习者贡献我们微薄的
力量。
联系方式:QQ 173925475 QQ 313626493
服务范围:
1、我们提供新鲜的技术课程和资料。
2、我们为大家提供最完善的服务,制作视频、文本、图片等相关文档。
3、相关教学内容的整理、相关产品的认证
合作方向:为了更好的与相关团队、相关机构合作,我们以开放、共享、共赢作为最核心的原则和方向
合作伙伴:C++大家庭,工大网安 ......
Ranon (Tel:13916291796)
2010 年 04 月 上海
听风独奏 www.gbcdbj.com
- 3. 听风独奏 www.gbcdbj.com
关于 WE ARE SO YOUNG !群
开技术类的 QQ 群为了什么?
一,交流技术 自己有问题可以问问别人
二,解答问题 解答别人的疑问 将心比心嘛
然而,Google,Baidu 的出现,似乎是的获取答案的路径更快
于是,每当别人在群问我问题时候,我知道可以在 Google 等上面获取答案时 ,我总是说,这类问
题,网上很多。
好了,我想说的也就是这里:
自己是菜鸟的时候,上网搜索问题,看不懂别人说什么,想在群里得到更进一步的解说,某某高人也
如此跟我说 这类问题,网上很多 先 google 吧。于是,只有去苦思网上的说法去了。
直到现在,这种想法,我也很赞同,毕竟这是自己锻炼的好方法。
但是,有时候,能在这说一下自己的看法,或者学习这问题时候的困难所在,对于初学者来说更好,
或者说,更符合技术群的宗旨:可以以对话的形式学习。我想 我以后也不会这么随便一句 这类问题,网
上很多搪塞过去的.
Charm (649453195)
2010 年 03 月 写于广东
听风独奏 www.gbcdbj.com
- 4. 听风独奏 www.gbcdbj.com
Xss 浅谈
作者: ℡独奏 173925475
跨站脚本 Cross-Site Scipting(Xss) 是最为流行的 Web 安全漏洞之一,我浅要的说明下这个漏洞形成
的原因及危害.
所谓跨站脚本就是攻击者可以将恶意的脚本代码注入到合法页面当中.当用户点击浏览这个页面时嵌在
页面中的恶意代码就会被执行.跨站脚本有好几种类型最为普遍的为反射类型的跨站脚本.
下面我以一个 jsp 页面为例说明 Xss 的机理.
操作系统:win xp sp2
编译环境:netbean6.1
服务器:tomcat 6
浏览器:遨游(IE 内核)
这个例子很简单.当用户输入内容.将这个内容输出到页面上显示,为了方便我将服务处理和显示放到同
一个页面,这个例子虽然简单但带有普遍性
index.jsp
1 <%@page contentType="text/html" pageEncoding="UTF-8"%>
2 <html>
3 <head>
4 <title>XSS</title>
5 </head>
6 <body>
7 <%
8 String Name=request.getParameter("textfield");
9 %>
10 name: <%=Name%>
11 <form id="form1" name="form1" method="get" action="index.jsp">
12 XssTest Input
13 <input type="text" name="textfield" />
14 <input type="submit" name="Submit" value="OK" />
15 </form>
16 </body>
17 </html>
当用户浏览这个页面时就会显示:
听风独奏 www.gbcdbj.com
- 5. 听风独奏 www.gbcdbj.com
当用户输入信息时例如 Xss 就会提交一些 Xss 请求
http://localhost:8084/WebApplication1/index.jsp?textfield=Xss&Submit=OK
将显示
这个例子很简单.看上去没什么功能但它却存在一个很典型的反射类跨站脚本漏洞.
如果我们在这个文本框内输入如下代码
<script>alert("Cookie=n"+document.cookie);</script>
则提交的请求为:
http://localhost:8084/WebApplication1/index.jsp?textfield=%3Cscript%3Ealert%
28%22Cookie%3D%5Cn%22%2Bdocument.cookie%29%3B%3C%2Fscript%3E&Submit=OK
那么这个这个页面动态生成就包含了其插入的脚本
<html>
<head>
<title>XSS</title>
</head>
<body>
name: <script>alert("Cookie=n"+document.cookie);</script>
<form id="form1" name="form1" method="get" action="index.jsp">
XssTest Input
<input type="text" name="textfield" />
<input type="submit" name="Submit" value="OK" />
</form>
</body>
</html>
脚本执行后就会弹出以下对话框,对画框内容是本地浏览器所在域的 Cookie 值
听风独奏 www.gbcdbj.com
- 7. 听风独奏 www.gbcdbj.com
编程方式读取 X.509 证书吊销列表(CRL)
(一)应用 Bouncy Castle Crypto
作者: Eros.煞帆 272990156
X.509 结构的证书被吊销后,序列号会出现在 Certificate Revocation List (CRL) 中,我们可以将它另存为一
个.crl 的文件,就能够查看被吊销的证书信息,但.NET Framework 并没有提供可对 Crl 进行属性访问的类
(Java 中提供了 X509Crl)
,要实现这样的功能,我们得借助.NET 框架之外的技术:Bouncy Castle Crypto
或者 Mono SDK。
先介绍如何使用 Bouncy Castle Crypto(Version 1.4)读取 X.509 证书及吊销列表。
Bouncy Castle Crypto 是一个开源的加/解密框架,下载地址:
http://www.bouncycastle.org/csha ... pto-net-1.4-bin.zip
首先加入 X.509 证书所在的命名空间:
using Org.BouncyCastle.X509;
其中的几个有关的类:
X509CrlParser 用于构建一个 crl 对象,支持从字节数组和内存流中获取数据。
X509Crl crl 对象,包含证书吊销组织、吊销证书列表、时间戳等信息。
X509CrlEntry crl 对象中被吊销的证书对象。
ISet 在 Org.BouncyCastle.Utilities.Collections 下,X509Crl 中被读取所有证书对象放在 HashSet 中,以 ISet
接口类型返回,HashSet 支持迭代器。
下面是读取 Crl 的示例:
Code
[copy to clipboard]
//获取obj
List<int> numbers = new List<int>();
X509CrlParser parser = new X509CrlParser();
X509Crl crl = parser.ReadCrl((byte[])obj);
//获取所有的吊销证书
ISet crlSet = crl.GetRevokedCertificates();
if (crlSet != null && crlSet.Count > 0)
{
foreach (object o in crlSet)
{
X509CrlEntry crlEntry = (X509CrlEntry)o;
int serialNumber = crlEntry.SerialNumber.IntValue;
if (!numbers.Contains(serialNumber))
听风独奏 www.gbcdbj.com
- 8. 听风独奏 www.gbcdbj.com
{
numbers.Add(serialNumber);
}
}
}
X509CrlEntry.SerialNumber.IntValue 将 16 进制的证书序列号以 10 进制的 Int32 类型输出。
另外再提一下 BC Crypto 的 X509Certificate 类和.NET Framework 下的 X509Certificate2 类的区别:
X509Certificate2 输出证书 DN 信息时,属性 SubjectName 是将个人信息按照从小到大(姓名-组织-市-省-
国家)排列,而 BC Crypto 的 X509Certificate 使用 SubjectDN 属性,将个人信息从大到小排列,市的标识
是 ST,.NET 是 S。如果需要根据证书生成组织结构,这个需要特别注意。
听风独奏 www.gbcdbj.com
- 9. 听风独奏 www.gbcdbj.com
C++对象数量跟踪限制
作者: Evil.Ghost 35797274
在实际的编程中,有很多时候需要限制对象的数量,比如代表设备资源的对象,代表上线客户的对象
等等。那么我们就需要对这些类型的对象进行数量跟踪限制,这样我们就必须在类定义中加入一些额外的
信息。
实践中不难发现,需要这让功能的类加入的额外信息似乎大同小异,按照避免重复编码的原则,我们
应该寻找另外一种解决方案使得不用或者少做这样的重复工作。
很显然,我们需要一个这样的类,它完成对象数量跟踪和限制的功能,并且能够很方便的被各种需要
此功能类型所使用。它还必须具有隐藏性,因为实际的客户代码是不需要知道其信息的,这个类只能算个
辅助类。那么它就不应该具有 public 访问权限的构造函数。
实现跟踪一类对象的数量并且进行限制,最简单的办法就是在这个类中定义两个静态成员:1、当前
对象数量;2、最大对象数量。既然我们已经打算将这些信息封装到一个辅助类中,那自然这两个静态成员
也应该成为辅助类的静态成员。不同的类去使用它的时候,其静态成员应该完全没有任何联系,那么就要
想办法为每个使用它的类生成一份专有的类,能够完成这样功能的方法自然就是——模板。
需要对象数量跟踪限制功能的类怎么样来使用这个辅助模板类呢?使用包含的话?那么每个使用它
的类都必须成为其友元,因为这个辅助模板类的构造函数不具有 public 访问权限,这很显然是不可能的。
有一种方法可以访问一个类的非 public 成员——继承。派生类可以访问基类的 protected 成员,我们将辅
助模板类的构造函数声明为 protected 访问权限,并让使用它的类继承于它,那么这个辅助类就可以发挥
其功效了。
这里有个值得注意的问题:vtbl。一个继承关系上出现一个 virtual 关键字,那么肯定会影响到对象
的大小和布局。然而从我们要完成的这个功能上看,虽然具有继承关系,但是根本没有必要使用到 virtua
l。但是客户如何使用我们的类我们是无法猜测的,如果有个好奇的客户使用基类指针去删除一个派生类对
象,而基类析构函数不带 virtual 关键字的话,那么带来的风险可能谁都不愿意承担。既然我们已经确定
了不需要 virtual,那么我们就要坚持,不要因为客户的这种操作来改变我们的行为。这种操作是我们不
听风独奏 www.gbcdbj.com
- 10. 听风独奏 www.gbcdbj.com
想看到的,那我们就去限制它!我们把删除基类的权限限制到派生类中,即基类析构函数声明为 protecte
d,那么客户就没有办法 delete 一个基类指针了,自然就不存在那种我们不想给予客户的操作了。
使用这个辅助的模板类来跟踪对象数量以及限制对象数量,除了我们编写派生类的人来说,其他人根
本就不需要知道,那么它的实现细节最好应该是 private 的。private 继承就能帮到你。
当对象的数量超过了最大值时,如何传递这个消息给客户呢,然而构造函数又没有返回值,这时 C++
异常机制可以帮助我们。辅助模板类应该在跟踪到对象数量达到上限时,客户再请求就传递一个通知给客
户——即抛出一种 TooManyObjects 的异常。有时,已经存在的对象数量也可能成为客户所想了解的信息,
那么辅助模板类还必须有一种能够让客户得到对象数量的方法,定义一个静态函数应该是最容易的方法。
这时我们应该回过头来看了,我们上面说到我们采用的是 private 继承,那么这个辅助模板基类的所
有信息都成为了 private,我们必须要将其 public 的成员恢复其访问权限。还好 C++提供了 using 来让我
们有机会恢复访问权限。在派生类的 public 中使用 using 来让基类 public 成员可见,这成员包括需要传
递给客户的异常类和获取对象数量的静态函数。
到此为止,我们已经可以实现这样的一个辅助模板基类了。其使用的规则我们可以很容易编写一个文
档来告诉给需要派生自它的客户了。(下面为实例代码)
听风独奏 www.gbcdbj.com
- 11. 听风独奏 www.gbcdbj.com
示例代码:
TakeCount.h 文件
#ifndef TAKE_COUNT_H
#define TAKE_COUNT_H
/*---------------------------------------------------------------------------------------->
* 对象数量跟踪限制的模板基类TakeCount。 作者:Evil.Ghost *
* 需要跟踪限制对象数量的类private继承于它,并负责初始化其静态const成员maxObjects。 *
* 如果对象超出上限,那么在构造函数中将抛出TooManyObjects异常。 *
* 可以通过ObjectCount函数获取当前对象数量。 *
<----------------------------------------------------------------------------------------*/
// 模板的类型参数应传递派生类
template<class NeedTakeCount>
class TakeCount{
static int numObjects;
static const size_t maxObjects;
public:
class TooManyObjects{};
static int ObjectCount()
{
return numObjects;
}
protected:
TakeCount();
TakeCount(const TakeCount& rhs);
~TakeCount()
{
--numObjects;
}
private:
// 避免重复写构造代码的帮助函数
void Init();
};
/*------------------实现代码----------------------*/
template<class NeedTakeCount>
TakeCount<NeedTakeCount>::TakeCount()
{
Init();
听风独奏 www.gbcdbj.com
- 13. 听风独奏 www.gbcdbj.com
EfficitivecC++ 总结
作者: 心石 313991728
本文都是自己看完 Efficitivec++ 的部分总结希望对大家有帮助.. 有些推论是方便我自己理解,不一定
准确。希望大家指正..
1. 尽量以 enum, inline, const 替换 define
排错时没有变量名,带参数宏的不可靠。
2. 将不改变类成员的函数声明和定义为 const,将变量声明为 const
Const char *p; char const *p; char * const p; const char * const p;
Const 成员函数可重载;
Const_coast:去除 const 属性 eg:const_coast<char&>
Static_coast: 加上属性 eg: static_coast<const char&>
普通对象可以调用 CONST 和非 CONST 方法,如果某方法被 CONST 重载,普通对象将优先调用非
CONST 方法,如果这个方法不存在,则会调用 CONST 方法。而常对象则只能调用 CONST 的方法。
3. 确定对象使用前已经被初始化
构造函数体内实现的只是赋值,初始化需要在初始化序列中进行。初始化顺序和声明的顺序最好一样,
尽管这不影响实际的调用顺序。
4. 对于跨编译单元的全局变量,为确保使用前就已经初始化,可以用全局函数返回该对象的引用,使之
成为本地静态引用变量。
5. 如果不想使用编译自动生成的函数,则可以将其声明为 private,并不实现它。可将相关错误转移至连
接期,方便追踪。
6. 为多态基类声明 virtual 析构函数,可确保资源的完整释放。
Virtual 实现机理:在带有 virtual 的类中,this 指针的前四个字节是该类 VTABLE 的入口地址,可据此计
算机出需要的正确的调用接口。
7. 如果析构函数有可能有异常,就把它吃掉,或终止运行。需要上层捕获这个异常,就单独提供接口来
操作这一部分,而不在析构中处理。
8. 不要在构造或析构中直接或间接调用 Virtual 函数,因为在构造中调用,此时的 VTABLE 入口地址还
没有设置好,对虚函数不支持;如果在析构中调用,原因不明,也许是因为在析构之前,VTABLE 的
入口地址就先于释放了。
9. 重载=运算符时,一定要判断是否自我赋值,确保安全性。并用要返回赋值后对象的引用,方便链式
表达。
10. 关于构造,拷贝构造,赋值的调用解释。
听风独奏 www.gbcdbj.com
- 14. 听风独奏 www.gbcdbj.com
class T
{
public:
T(int m){printf("构造函数n"); n = m;}
T(T& r){printf("拷贝构造函数n"); n = r.n;}
const T& operator=(T& r){printf("赋值函数n"); n = r.n; return *this;}
~T(){printf("析构函数n");}
private:
int n;
};
int main()
{
int n = 10;
T t0(n); //显式构造
T t = n; //构造,隐式调用构造函数
T t1 = t; //拷贝构造
T t2(t); //拷贝构造
t2 = t; //赋值
scanf("%d", &n);
}
11.对象赋值的时候,不要忘记对源对象的完整拷贝,注意派生类的赋值,需要调用基类方法,将基类成
员一起拷贝。拷贝构造函数不要调用赋值函数,这时它处于构造阶段;赋值函数也不要调用拷贝构造函数,
理清这些特殊函数的初衷。如果要使用他们共同的代码,可以将其放入第三个函数体中,以便调用。
11. 以对象管理资源.
Auto_ptr: 任意两个 Auto_ptr 不能指向同一个对象。不能自定义销毁方法。
Shared_ptr: 通过引用计数,实现 PTR 之间的赋值,在引用为 0 时,销毁对象,可自定义销毁方
法。以独立语句将指针转入智能指针!!!
以上两者对于数组的管理都是没有意义的。
RAII 对象之间的复制行为,如果不需要这种行为,可以禁止它。如果需要,可以采用底层资源的引
用计数机制,或者资源的一起复制,或者其它方法,可根据实际情况灵活选用。
资源管理类需要显式提供访问原始资源的方法,比如 get()。
New 和 delete 要采用相同的形式, 比如 new [],delete[]; 因为 delete [],有的编译器是
将该地址的前四个字节做为数组的长度,实现对每个对象的释放。同理可得 delete[]不要用于 new 出来
的内存。就算编译器不是采用这种方法管理数组内存,也会有其它类似的机制。
要采用单独的语句将指针放入智能指针,避免其它调用异常抛出,指针没有放入智能指针,出现不
可管理的内存的情况。
12.自定义结构参数的传递,尽量采用 const reference 的方式代替 value 方式,如果需要改变参数
听风独奏 www.gbcdbj.com
- 15. 听风独奏 www.gbcdbj.com
的值,就去掉 const.内置类型 value 方式比 reference 方式更高效。但同时,对于需要返回 value
的值不要试图返回 reference,例如+,-,*,/这些运算,在支持链式表达或后续赋值的时候,将可能
返回一个指向临时对象的 reference。总之,不能返回一个 pointer 或 reference 指向一个 local
stack 对象,或指向 heap-allocated 对象。。。
12. 将成员变量声明为 private,对于外界必须访问的变量,提供操作接口。并且避免返回指向内部成员
的 HANDLE,防止意外修改,保持封装的特性。
13. 尽量把变量定义时间推后,防止不必要的开销。
14.转型操作: const_cast<T>(expression) :常量性去除
Dynamic_cast<T>(expression): 进 行 基 类 与 子 类 的 类 型 安 全 转 换 , 失 败 返 回
NULL,兄弟之间的转换将会失败。不能用于没有继承关系的转换,也不能用于没有虚函数的转换。
Reinterpret_cast<T>(expression): 用于两种不相关类型的转换,使操作数的位
模式在较低层次重新解释。
Static_cast<T>(expression): 强迫隐式转换,代替 C 语言中的小括号。
听风独奏 www.gbcdbj.com
- 16. 听风独奏 www.gbcdbj.com
俄罗斯方块的一维数组存储
作者: ℳy Sonata luomuhanxue@126.com(409143825)
我写了一个俄罗斯方块,其和平时网上看到的有一点不一样,网上大多数是二维数组写成的,而我这
个是用一维数组写的。如果你有兴趣的话,可以先不看下文,自己尝试一下用一位数组写一个出来。
要想用一维数组表示二维数组的信息的话,么对以为数组里的每个元素就要特别对待,因为那每一个
元素要存储二维数组里的每一行的信息。究竟如何存储呢?请看下面的例图:
这个为内存的一个字节
0 0 1 0 0 0 0 1
这样的一个字节完全可以看成是一个一维数组,其存储的是{0,0,0,0,0,0,0,1}这些数字,
这样只要把这些数字按一定方法分离出来就可以完全当作二维数组用。这些方法自己定。那么如何分离这
些数字呢?看下面的例子:
0 0 1 0 0 0 0 1 = 33
7 6 5 4 3 2 1 0
做按位与操作(&)
0 0 0 0 0 0 0 1 = 1
这就得到低位的 1 了,再把整个字节逐个向低位移(>>)再和 1 按位与(&),例子:分离那个第五位上
的那个 1 可以这样做:(33>>5)&1,这样就把第五位的 1 分离出来了。
现在回到俄罗斯方块,用一个二维数组也就是标志一下哪些地方有方块,哪些地方没方块,既然只一
个标志有和无,就完全可以用 1 和 0 来存储,那么存储 0 和 1 的话,用二维数组实在是很浪费。而且数组
的维数越高越不容易操作
现在要做的设计好要表示的二维数组的长和宽了。我做的是 16*25 的,用的是一个 UInt16 类型的数组,
一看名字就知道是无符号 16 位的整型,刚好用来存储长度是 16 的二维数组。其示意图如下:
P[n]
P[...]
P[2]
P[1]
P[0]
这样就可以用来保存一个 16*n 的二维数组了,P[n]表示第 n 行,既然设计好数组,那么如何保存进
去呢?
a
听风独奏 www.gbcdbj.com
- 17. 听风独奏 www.gbcdbj.com
0 0 1 0 0 0 0 1
7 6 5 4 3 2 1 0
做按位或操作(|)
b
0 0 0 0 1 1 0 0
要把 b 中的内容添加到 a 中去可以这样做,a|b:
这样得到
0 0 1 0 1 1 0 1
这样就可以实现保存,只要小方块落下时,给对应的位置这样标志就可以了。
当行满的时候 P[n]的值是 65535,也就是 2 的 16 次方减 1,这个 65535 我就称为行满值。当然如果
是 int 型的,那么如果你写的是 32*n 的数组就要注意了,此时行满的条件是 P[n] = —1,因为 int 是有
符号的,不过在不同的环境中 int 占的长度不一定。在 TC 中是 2 个字节,所以编写的时候要注意。
一维数组保存二维信息的原理到此基本上讲完了,下面就自己要会灵活运用了,其比起来二维数组写
的俄罗斯方块有如下优点:
1、节省存储空间。
2、判断行满是效率高,只要判断 P[n]是否等于我们设定的满行值,省去二维数组的每一行遍历是否
都等于 1。
3、在消行的时候更加方便,效率高 P[n-1] = P[n]就能消除 P[n-1]行了,省去二维数组第 n 行向第
n-1 行的赋值操作。
但是一个俄罗斯方块没有一定特殊的游戏法则是多么的无聊哈,要想用一维数组存储更多的信息应该怎
么做呢?很简单,我们只要更改一下分离方法就可以进行跟多的信息保存了,比如一个方块是红色的,我
要把这红色也保存到一位数组中去,我先设定好几种颜色对应的数字,比如红色对应 2,黄色对应 3,我们
只要把这个 2 或 3 保存进去就行了,那个一个位是保存不了 2 的,我就必须加宽每个位。看这个例子:
1 0 0 1 0 0 1 1
红色 黑色 无 黄色
这样用两位来保存一个位置的信息,则一个位置有 4 种信息,0 时为空,1 时为黑色方块,2 时为红
色方块,3 时为黄色方块,此时的分离方法也要改,把要分离的两位移到低位,和 3 按位与。那么 16 位的
UInt16 就只能存储 8*n 的二维数组了。我可以加大其对应的类型,可以用 int32,或者更高位的类型达到
存储更多信息的目的。
当然,这个也是有个限度的,过多的信息存储时还是用二维好点。比如一个俄罗斯方块要存储 16 种颜
色,8 种音效,多种的积分法则,此时一位数组是远远办不到的。但是我们任然可以用按位操作达到节省
存储空间的压缩,和一些高效率的运行。
听风独奏 www.gbcdbj.com
- 18. 听风独奏 www.gbcdbj.com
声明一下:这里不是叫大家以后不用二维数组,用一维数组,而是一种按位操作的用法。
也许你会笑话我,现在空间那么大,机器的运算速度那么快,何必再整这些呢?我会笑笑说:这就是
一个程序员的快乐。
听风独奏 www.gbcdbj.com