<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://shell909090.spaces.live.com/mmm2008-05-17_13.22/rsspretty.aspx?rssquery=en-US;http%3a%2f%2fshell909090.spaces.live.com%2fcategory%2f%e8%ae%a1%e7%ae%97%e6%9c%ba%e4%b8%8e%2bInternet%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Shell's Room: 计算机与 Internet</title><description /><link>http://shell909090.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%25E8%25AE%25A1%25E7%25AE%2597%25E6%259C%25BA%25E4%25B8%258E%2bInternet</link><language>en-US</language><pubDate>Fri, 04 Jul 2008 01:10:22 GMT</pubDate><lastBuildDate>Fri, 04 Jul 2008 01:10:22 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><cf:parentRSS>http://shell909090.spaces.live.com/blog/feed.rss</cf:parentRSS><live:type>blogcategory</live:type><live:identity><live:id>8850414288015442459</live:id><live:alias>shell909090</live:alias></live:identity><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>python的几个改进</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1790.entry</link><description>     首先需要增加的就是kill掉线程的方法，目前我们统统是调用系统函数。有没有搞错阿，需要针对系统写代码不说，还不安全。在线程关闭的过程中没有辗转开解和安全捕获。从最安全的角度上说，要关闭线程最方便的就是给其他线程抛异常。python并非不可以给其他线程抛异常，可非常麻烦不说，具体执行的时候发现，其实根本不是抛异常，而是在执行过程中检查异常。这样当程序在调用外部代码的时候死循环，想kill线程的时候根本不可行。所以安全的关闭线程的异常和直接kill掉线程的方法都要有。&lt;br&gt;    其次，这东西没有什么可以快速辅助处理集合的工具类，例如STL中的set_union等等。虽说每个都不难，可是统一的实现和各自的实现毕竟是有差别的。很多时候，我们只需要抽象的计算两个集合，一个和一个的交集，就OK了。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+python%e7%9a%84%e5%87%a0%e4%b8%aa%e6%94%b9%e8%bf%9b&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1790.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1790.entry</guid><pubDate>Sun, 11 May 2008 11:37:52 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1790/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1790.entry#comment</wfw:comment><dcterms:modified>2008-05-11T11:37:52Z</dcterms:modified></item><item><title>反射的几个类型</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1788.entry</link><description>     所谓反射，其实就是在运行时可以获得代码数据的技术，算是面对对象编程语言的专利。从这个意义上说，反射可以分为三个类型。&lt;br&gt;    头一类是RTTI，其实这根本不算反射，本质上只能说多态。RTTI是一种鉴别某个对象是否为某个类的派生实例的技术，在C++中就有实现。简单的方法就是实现一个特定的虚函数，将当前对象所属的类虚函数表和所属父类的虚函数表一一返回。这样对比某个类的虚函数表，就可以知道是否为派生实例了。支持RTTI，程序才算真正支持了面对对象，而反射则是更高一层的技术。&lt;br&gt;    第二类就是在C#和Java中盛行的反射技术，这种技术的核心在于可以通过名称寻找到对象。例如，我们可以寻找到一个叫做abc的对象，枚举其中的成员和方法，并且执行调用，这才是反射最大的意义。当我们遇到不同的数据输入时，我们可以调用不同的方法来处理这个数据，并且这个过程是动态配置的。而在C++中，我们无法通过编译器支持这个能力，必须手工的建立一个名称和一个对象的关联关系表，在合适的时候通过这个表，获得某个名称的函数入口指针。其实C#和Java中实现的方法和VM息息相关，他们的代码在目标文件中还保持着命名空间-类-对象的结构，Java还进一步的保留了源码(只是被翻译为了更快的P代码)，而C#只保留了IL代码。这样VM在执行的时候自然可以很轻松的找到对应的函数，并且获得函数签名。而C类语言的特征是汇编时代的&amp;quot;符号链接&amp;quot;方式，编译的时候保有符号，完成链接就没了。&lt;br&gt;    中间插一句，其实我们完全可以写一个只支持高阶语言的系统。这样的系统未必高效，可一定方便阿。&lt;br&gt;    最后一种则是python中的系统，当用户调用一个类中的函数的时候，使用一个专门的函数来决定调用哪个。因此当对付SOAP这种东西的时候，python可以直接上。而C#，Java，C++都要通过工具生成代理方法。再用代理方法去调用公共函数库，实现调用。因为python直接将调用定向到了一个统一的函数上，所以压根不需要这步。不过这步的代价是严重的性能问题，因为每次函数调用都要去检查调用目标。python是纯脚本语言，占了这点便宜，所以才能这么干。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e5%8f%8d%e5%b0%84%e7%9a%84%e5%87%a0%e4%b8%aa%e7%b1%bb%e5%9e%8b&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1788.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1788.entry</guid><pubDate>Tue, 06 May 2008 08:58:17 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1788/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1788.entry#comment</wfw:comment><dcterms:modified>2008-05-06T08:58:17Z</dcterms:modified></item><item><title>C++继承,虚,转换规则探究</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1787.entry</link><description>     以下讨论的东西都是在VS2005下跑出来的，如果想知道别的编译器规则，请照跑一遍。以下是类定义，函数内容为打印出当前函数名称，所以就不再贴了。&lt;br&gt;class Base&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;    Base();&lt;br&gt;    Base(const Base &amp;amp; o);&lt;br&gt;    virtual ~Base();&lt;br&gt;    virtual Base &amp;amp; operator = (const Base &amp;amp; o);&lt;br&gt;&lt;br&gt;    void function1();&lt;br&gt;    virtual void function2();&lt;br&gt;    void function3();&lt;br&gt;    virtual void function4();&lt;br&gt;    //virtual void function5();&lt;br&gt;    virtual void function6();&lt;br&gt;};&lt;br&gt;class Derive : public Base&lt;br&gt;{&lt;br&gt;public:&lt;br&gt;    Derive();&lt;br&gt;    Derive(const Derive &amp;amp; o);&lt;br&gt;    virtual ~Derive();&lt;br&gt;    virtual Derive &amp;amp; operator = (const Derive &amp;amp; o);&lt;br&gt;&lt;br&gt;    void function1();&lt;br&gt;    virtual void function2();&lt;br&gt;    virtual void function3();&lt;br&gt;    void function4();&lt;br&gt;    //compiler error&lt;br&gt;    //int function5();&lt;br&gt;protected:&lt;br&gt;    virtual void function6();&lt;br&gt;public:&lt;br&gt;};&lt;br&gt;    首先我们讨论继承下的构造/析构顺序。&lt;br&gt;pa = dynamic_cast&amp;lt;Base*&amp;gt;(new Derive ());&lt;br&gt;delete pa;&lt;br&gt;Base::Base&lt;br&gt;Derive::Derive&lt;br&gt;Derive::~Derive&lt;br&gt;Base::~Base&lt;br&gt;    关于这段代码多说两句，如果我们把class Derive : public Base中的public删除，就会出现C2243错误，看来默认是私有继承。&lt;br&gt;    先是基类构造，然后是继承类构造。先是继承类析够，然后是基类析够。然后我们将virtual ~Base();的virtual删除，结果就变成了。&lt;br&gt;Base::Base&lt;br&gt;Derive::Derive&lt;br&gt;Base::~Base&lt;br&gt;    注意继承类的析构没了。所以如果你打算让人继承你的类，记得将类的析构改成virtual，否则他怎么写析构都不会被调用的。&lt;br&gt;    然后是虚函数继承。&lt;br&gt;pa-&amp;gt;function1 ();&lt;br&gt;pa-&amp;gt;function2 ();&lt;br&gt;pa-&amp;gt;function3 ();&lt;br&gt;pa-&amp;gt;function4 ();&lt;br&gt;    结果是这样。&lt;br&gt;Base::function1&lt;br&gt;Derive::function2&lt;br&gt;Base::function3&lt;br&gt;Derive::function4&lt;br&gt;Derive::function6&lt;br&gt;    看来，虚特性出来不出来完全看基类。注意到上面的function5么？假设你继承了一个类，打算写一个函数，和基类里面的某个虚函数具有一样的名称和参数，但是返回不一样。嘟嘟～～抱歉，编译器错误。而且注意function6，即使在继承类中声明说这是保护函数，也可以通过公开的基类函数的虚特性进行调用。&lt;br&gt;    下面我们要说一下拷贝构造函数，这不可避免的要说到定义。&lt;br&gt;Derive::Derive(const Derive &amp;amp; o)&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;Derive::Derive copy constructer\n&amp;quot;);&lt;br&gt;}&lt;br&gt;    猜猜这个会出什么结果？&lt;br&gt;Base::Base&lt;br&gt;Derive::Derive copy constructer&lt;br&gt;    要是经常看我blog的人就不会意外，继承类的拷贝构造函数调用的是基类的普通构造函数。如果你打算让基类也拷贝构造，那这么做。&lt;br&gt;Derive::Derive(const Derive &amp;amp; o):Base (o)&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;Derive::Derive copy constructer\n&amp;quot;);&lt;br&gt;}&lt;br&gt;    然后是拷贝构造函数的使用时机。运行代码如下，我们逐步分析。&lt;br&gt;Base ta = *pa;&lt;br&gt;Base::Base copy constructer&lt;br&gt;Base::~Base&lt;br&gt;    当对象声明时，如果加一个=，则以=后的对象来构造当前对象，这是拷贝构造的第一个用法。&lt;br&gt;Derive tb = *static_cast&amp;lt;Derive*&amp;gt;(pa);&lt;br&gt;Base::Base copy constructer&lt;br&gt;Derive::Derive copy constructer&lt;br&gt;Derive::~Derive&lt;br&gt;Base::~Base&lt;br&gt;    当然，如果我们声明继承类的时候，一样拷贝构造。&lt;br&gt;//compiler error&lt;br&gt;//Derive tc = ta;&lt;br&gt;    当我们试图用基类构造继承类的时候，理所当然的，出错了。&lt;br&gt;void test1 (Base &amp;amp;)&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test1\n&amp;quot;);&lt;br&gt;}&lt;br&gt;test1(*pa);&lt;br&gt;输出：test1&lt;br&gt;    如果我们以一个对象调用的时候，如果是引用，当然是不拷贝的。&lt;br&gt;void test2 (Base)&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test2\n&amp;quot;);&lt;br&gt;}&lt;br&gt;test2(*pa);&lt;br&gt;Base::Base copy constructer&lt;br&gt;test2&lt;br&gt;Base::~Base&lt;br&gt;    如果是直接调用，首先是拷贝构造，然后调用，最后析构。&lt;br&gt;Base&amp;amp; test3 ()&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test3\n&amp;quot;);&lt;br&gt;    return Base ();&lt;br&gt;}&lt;br&gt;pb = &amp;amp;test3();&lt;br&gt;test3&lt;br&gt;Base::Base&lt;br&gt;Base::~Base&lt;br&gt;    当返回对象引用的时候，只有很正常的构造和析构。&lt;br&gt;Base test4 ()&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test4\n&amp;quot;);&lt;br&gt;    return Base ();&lt;br&gt;}&lt;br&gt;pb = &amp;amp;test4();&lt;br&gt;test4&lt;br&gt;Base::Base&lt;br&gt;Base::~Base&lt;br&gt;    返回对象本身的话，哎，怎么会这样？&lt;br&gt;    熟悉语言的应该看出来了，return Base ();的时候，先跑了一次构造，建立在栈里面，返回的时候要copy到堆中。拷贝构造呢？&lt;br&gt;    这就是传说中的返回构造优化拉，直接构造在堆上面，省掉一次copy，下面我们看看原始的状态。&lt;br&gt;Base&amp;amp; test5 ()&lt;br&gt;{&lt;br&gt;    Base b;&lt;br&gt;    printf (&amp;quot;test5\n&amp;quot;);&lt;br&gt;    return b;&lt;br&gt;}&lt;br&gt;pb = &amp;amp;test5();&lt;br&gt;Base test6 ()&lt;br&gt;{&lt;br&gt;    Base b;&lt;br&gt;    printf (&amp;quot;test6\n&amp;quot;);&lt;br&gt;    return b;&lt;br&gt;}&lt;br&gt;pb = &amp;amp;test6();&lt;br&gt;Base::Base&lt;br&gt;test5&lt;br&gt;Base::~Base&lt;br&gt;Base::Base&lt;br&gt;test6&lt;br&gt;Base::Base copy constructer&lt;br&gt;Base::~Base&lt;br&gt;Base::~Base&lt;br&gt;    大家看到了？5的时候先构造，再传回，和返回对象引用的时候行为一致。6的时候可没有返回构造优化，于是先构造，然后拷贝。删除的时候先删除原始对象，再删除拷贝对象，大家可以自行证实这点。&lt;br&gt;    我们再修改上面的调用为下面的。&lt;br&gt;Base td = test5();&lt;br&gt;Base::Base&lt;br&gt;test5&lt;br&gt;Base::~Base&lt;br&gt;Base::Base copy constructer&lt;br&gt;Base::~Base&lt;br&gt;    首先是5的构造，析构，然后才是td的拷贝构造，析构。这个顺序，熟悉语言的人应该感觉到奇怪了吧。按照推论，应当是先拷贝再析构的。如果你这么觉得，还是先看完下面的东西吧。&lt;br&gt;Base te = test6();&lt;br&gt;Base::Base&lt;br&gt;test6&lt;br&gt;Base::Base copy constructer&lt;br&gt;Base::~Base&lt;br&gt;Base::~Base&lt;br&gt;    这才是预计的顺序。注意，这里并没有调用两次拷贝构造。虽然贝壳并不了解机制，不过估计又是一种返回构造优化。&lt;br&gt;    5中例子觉得迷惑的人，不妨在拷贝构造里面打个断点，看看你copy的对象是什么，无效对象！！！！&lt;br&gt;    返回引用的情况下，一旦返回对象的生命周期结束了，返回的数据就无法保证有效。因此返回局部对象是非常危险的，唯一的里外就是3例子中在返回的时候构造一个新的对象而引发的返回构造优化。&lt;br&gt;    下面是拷贝构造和operator =的区别和调用时间。&lt;br&gt;Base ya = *pa;&lt;br&gt;Base yb;&lt;br&gt;yb = *pa;&lt;br&gt;Base::Base copy constructer&lt;br&gt;Base::Base&lt;br&gt;Base::operator =&lt;br&gt;Base::~Base&lt;br&gt;Base::~Base&lt;br&gt;    上面一个是拷贝构造，下面一个是普通构造加operator =。&lt;br&gt;    最后是全部的定义和源码，类的定义参考最上面的。&lt;br&gt;void test1 (Base &amp;amp;)&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test1\n&amp;quot;);&lt;br&gt;}&lt;br&gt;void test2 (Base)&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test2\n&amp;quot;);&lt;br&gt;}&lt;br&gt;Base&amp;amp; test3 ()&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test3\n&amp;quot;);&lt;br&gt;    return Base ();&lt;br&gt;}&lt;br&gt;Base test4 ()&lt;br&gt;{&lt;br&gt;    printf (&amp;quot;test4\n&amp;quot;);&lt;br&gt;    return Base ();&lt;br&gt;}&lt;br&gt;Base&amp;amp; test5 ()&lt;br&gt;{&lt;br&gt;    Base b;&lt;br&gt;    printf (&amp;quot;test5\n&amp;quot;);&lt;br&gt;    return b;&lt;br&gt;}&lt;br&gt;Base test6 ()&lt;br&gt;{&lt;br&gt;    Base b;&lt;br&gt;    printf (&amp;quot;test6\n&amp;quot;);&lt;br&gt;    return b;&lt;br&gt;}&lt;br&gt;int _tmain(int argc, _TCHAR* argv[])&lt;br&gt;{&lt;br&gt;    Base *pa, *pb;&lt;br&gt;    &lt;br&gt;    pa = dynamic_cast&amp;lt;Base*&amp;gt;(new Derive ());&lt;br&gt;&lt;br&gt;    // test inherit function rule&lt;br&gt;    //pa-&amp;gt;function1 ();&lt;br&gt;    //pa-&amp;gt;function2 ();&lt;br&gt;    //pa-&amp;gt;function3 ();&lt;br&gt;    //pa-&amp;gt;function4 ();&lt;br&gt;    //pa-&amp;gt;function6 ();&lt;br&gt;&lt;br&gt;    //test copy constructer&lt;br&gt;    //pb = dynamic_cast&amp;lt;Base*&amp;gt;(new Derive (*static_cast&amp;lt;Derive*&amp;gt;(pa)));&lt;br&gt;    //delete pb;&lt;br&gt;    //Base ta = *pa;&lt;br&gt;    //Derive tb = *static_cast&amp;lt;Derive*&amp;gt;(pa);&lt;br&gt;    //compiler error&lt;br&gt;    //Derive tc = ta;&lt;br&gt;    //test1(*pa);&lt;br&gt;    //test2(*pa);&lt;br&gt;    //pb = &amp;amp;test3();&lt;br&gt;    //pb = &amp;amp;test4();&lt;br&gt;    //pb = &amp;amp;test5();&lt;br&gt;    //pb = &amp;amp;test6();&lt;br&gt;    //Base td = test5();&lt;br&gt;    //Base te = test6();&lt;br&gt;&lt;br&gt;    //diffrence between copy cotr and operator =&lt;br&gt;    //Base ya = *pa;&lt;br&gt;    //Base yb;&lt;br&gt;    //yb = *pa;&lt;br&gt;&lt;br&gt;    delete pa;&lt;br&gt;    return 0;&lt;br&gt;}&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+C%2b%2b%e7%bb%a7%e6%89%bf%2c%e8%99%9a%2c%e8%bd%ac%e6%8d%a2%e8%a7%84%e5%88%99%e6%8e%a2%e7%a9%b6&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1787.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1787.entry</guid><pubDate>Fri, 02 May 2008 11:05:30 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1787/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1787.entry#comment</wfw:comment><dcterms:modified>2008-05-02T11:05:30Z</dcterms:modified></item><item><title>python的非经典错误</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1774.entry</link><description> def comp_tuple_file (tuple_file1, tuple_file2):&lt;br&gt;    for i in tuple_file1:&lt;br&gt;        if i in tuple_file2:&lt;br&gt;            tuple_file1.remove(i);&lt;br&gt;            tuple_file2.remove(i);&lt;br&gt;if __name__==&amp;quot;__main__&amp;quot;:&lt;br&gt;    t1=[(1,&amp;quot;1&amp;quot;),(2,&amp;quot;2&amp;quot;),(3,&amp;quot;3&amp;quot;)];&lt;br&gt;    t2=[(1,&amp;quot;1&amp;quot;),(3,&amp;quot;3&amp;quot;),(2,&amp;quot;2&amp;quot;),(4,&amp;quot;2&amp;quot;)];&lt;br&gt;    comp_tuple_file (t1, t2);&lt;br&gt;    print t1;&lt;br&gt;    print t2;&lt;br&gt;    错在哪里？&lt;br&gt;    头一次循环，i=(1,&amp;quot;1&amp;quot;)被正确移除了。但是接下来，i=(3,&amp;quot;3&amp;quot;)？&lt;br&gt;    这个叠代器的行为很有意思哦，貌似叠代器内存储的是集合的索引。&lt;br&gt;def comp_tuple_file (tuple_file1, tuple_file2):&lt;br&gt;    collection=tuple_file1[:];&lt;br&gt;    for i in collection:&lt;br&gt;        if i in tuple_file2:&lt;br&gt;            tuple_file1.remove(i);&lt;br&gt;            tuple_file2.remove(i);&lt;br&gt;if __name__==&amp;quot;__main__&amp;quot;:&lt;br&gt;    t1=[(1,&amp;quot;1&amp;quot;),(2,&amp;quot;2&amp;quot;),(3,&amp;quot;3&amp;quot;)];&lt;br&gt;    t2=[(1,&amp;quot;1&amp;quot;),(3,&amp;quot;3&amp;quot;),(2,&amp;quot;2&amp;quot;),(4,&amp;quot;2&amp;quot;)];&lt;br&gt;    comp_tuple_file (t1, t2);&lt;br&gt;    print t1;&lt;br&gt;    print t2;&lt;br&gt;    这才是正确的代码。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+python%e7%9a%84%e9%9d%9e%e7%bb%8f%e5%85%b8%e9%94%99%e8%af%af&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1774.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1774.entry</guid><pubDate>Tue, 08 Apr 2008 06:07:47 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1774/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1774.entry#comment</wfw:comment><dcterms:modified>2008-04-08T06:07:47Z</dcterms:modified></item><item><title>链接上的问题</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1773.entry</link><description>     贝壳最近在用库上吃了不少苦头，先是crypto++5.52。编译后怎么也链接不上。后来发现需要用/MT参数编译为多线程。后来又在STLport上又吃一次苦头，可见VC2003的默认单线程模式确实不得人心。&lt;br&gt;    下面说一下STL的编译手记。下载STLport，解压。运行vcvars32.bat设置环境变量,去build/lib下面，运行configuare -c msvc71(如果你是2003，否则按configuare --help察看你的编译器类型)。然后运行nmake -f msvc.mak install。可以看到有两个目录被建立了，bin和lib。把bin的复制到windows/system32下面，把lib的复制到系统目录下面。安装就OK了。&lt;br&gt;    上述和boost都差不多，然而和boost不一样的是，编写程序的时候，需要手工指定stlport的头文件路径。boost的可以以&amp;lt;boost/xxx.h&amp;gt;来引入，因此boost的头可以复制到系统里面去。然而stlport的必须以手工方式指定，否则就要覆盖默认的stl了。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e9%93%be%e6%8e%a5%e4%b8%8a%e7%9a%84%e9%97%ae%e9%a2%98&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1773.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1773.entry</guid><pubDate>Sat, 05 Apr 2008 08:47:56 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1773/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1773.entry#comment</wfw:comment><dcterms:modified>2008-04-05T08:47:56Z</dcterms:modified></item><item><title>显示自身的代码</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1770.entry</link><description>     void main(){char* a=&amp;quot;void main(){char* a=%c%s%c;printf (a,34,a,34);}&amp;quot;;printf(a,34,a,34);}&lt;br&gt;    核心是使用printf(a,a)来代换显示，并且用34来规避\转换。当然，完整的要带include，稍微有点区别。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e6%98%be%e7%a4%ba%e8%87%aa%e8%ba%ab%e7%9a%84%e4%bb%a3%e7%a0%81&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1770.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1770.entry</guid><pubDate>Tue, 01 Apr 2008 02:48:33 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1770/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1770.entry#comment</wfw:comment><dcterms:modified>2008-04-01T02:48:33Z</dcterms:modified></item><item><title>一些使用firefox的技巧</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1769.entry</link><description>     在linux下和windows下共享同样配置/插件。这个很简单，上面的blog中有篇文章说到thnunderbird在双系统下共享同样邮件的问题，firefox也一样解决。能用linux的人不会查不出配置目录位置吧。&lt;br&gt;    节约内存技巧。&lt;br&gt;    firefox虽然号称小巧，然而很多时候我们发现他的内存消耗也非常惊人。在贝壳的机器上，有的时候会高达150M，基本等于普通编辑器/播放器的10倍。事实上，不是firefox浪费内存，而是默认的内存配置是针对&amp;quot;机器上只开firefox&amp;quot;设计的。如果你机器内存小，或者需要同时开其他程序，最好自己配置一下firefox。&lt;br&gt;    首先就是fasterfox，关闭其中的&amp;quot;增强预读&amp;quot;，这东西很消耗内存。然后是内存缓存，调整到32M吧。一般一个网页上所有文件差不多1M-2M，32M够把20个网页的所有内容缓存起来，再多就不大正常了。根据贝壳自己的猜测，渲染动作应当是动态进行的，否则内存根本顶不住长文本的渲染。这样在浏览的时候，从后台抓取内容，动态渲染的速度就非常重要，因此强烈推荐不要小于8M。否则连5个页面的内容都不在内存中命中，还玩个P阿～&lt;br&gt;    还有渲染中的&amp;quot;启用快速返回&amp;quot;，将内存中的保留页面数调整小，贝壳用的是3。当然，这个只适用于firefox1.5。&lt;br&gt;    其次是session manager，将&amp;quot;撤销关闭&amp;quot;尽量减小。反正贝壳减小到了1个窗口3个页面。这些页面在关闭后还是继续消耗系统的内存，因此越小越好。当然，小到多少是要看你的具体需要了。&lt;br&gt;    最后，少用插件，少启用插件，除非你真的需要。长期不需要的就禁用，或者干脆卸载。&lt;br&gt;    内存回收技巧。&lt;br&gt;    很简单，觉得不够了，关了再开。反正有session manager，正在浏览的网页根本不会有影响。&lt;br&gt;    同时打开大批网页技巧。&lt;br&gt;    最好使用Tree Style Tab，这样方便。另外，如果需要打开一个页面的所有连接，可以这样做。先察看页面信息，选择&amp;quot;链接&amp;quot;-&amp;gt;&amp;quot;全部选择&amp;quot;-&amp;gt;&amp;quot;复制&amp;quot;，然后开一个文本文件，把内容粘贴进去。可以看到内容其实是一堆的页面链接。当然，如果页面内有js做的链接指向，可以试试用Convert javascript or onclick to normal links这个greasemonkey脚本转换成目标链接。然后，把这个文本文件改名成htm，打开。通常情况下应该是一堆无法点击的文字，不过你可以用Linkify ting来把文字转换成一堆链接。然后……一个个点过去吧。&lt;br&gt;    上面是使用greasemonkey解决的方法，当然，也有更简单的方法。你可以安装flashgot，然后新增一个下载管理器，名字叫做firefox。路径就指向firefox的执行文件路径，参数不用动。平时用你喜欢的管理器，需要打开全部链接的时候，更改为firefox，然后&amp;quot;使用flashgot下载全部链接&amp;quot;。当然，缺点是对付不了js脚本，除非你加载Convert javascript or onclick to normal。&lt;br&gt;    不过鉴于内存状态考虑，建议不要同时打开大量页面。维持在10-20个上下最好。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e4%b8%80%e4%ba%9b%e4%bd%bf%e7%94%a8firefox%e7%9a%84%e6%8a%80%e5%b7%a7&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1769.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1769.entry</guid><pubDate>Mon, 10 Mar 2008 05:33:31 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1769/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1769.entry#comment</wfw:comment><dcterms:modified>2008-03-10T05:33:31Z</dcterms:modified></item><item><title>晒一晒我的firefox</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1765.entry</link><description>     firefox是很有名的浏览器，以其短小和安全而著称。相信很多朋友喜欢使用firefox，然而你真的会用么？&lt;br&gt;    首先纠正一点，最标准的浏览器虽然不是IE，但是也不是firefox。而是以下三个，Safari(WebKit) / Opera(Presto) / Konqueror(KHTML)。Safari是Mac上的浏览器，Konqueror是Linux上的，Opera则多数用于手机上。Firefox 2.0.0.3 (Gecko 1.8.1.3)稍微差点，Internet Explorer 7.0 (Trident)和Internet Explorer 6.0 (Trident)是最不标准的。具体请看Acid2测试(http://www.osxcn.com/css/the-second-acid-test.html)。当然，也有消息称Firefox和IE已经都通过了测试(http://www.appbeta.com/50226711/ie8afirefoxasafariaoperaecaeacid2ce_133101.php)。&lt;br&gt;    其次，当你用着号称国人精华的XX浏览器的时候。首先请注意一下他是否使用了ie内核。IE有一个非常大的框架，其内核是Trident。所谓的浏览器内核，就是负责将html转换为DOM，然后渲染的组件集。当然，还有一些执行js等等的组件。微软的IE内核一般在mshtml.dll上，如果你有procexp，可以看看所谓的XX浏览器是否用了这个dll。如果用了，没的说，肯定是Trident内核。如果没有么……将mshtml改名转移，直到IE无法正常浏览。然后看看您的XX浏览器怎么样。&lt;br&gt;    Firefox的内核是Gecko，据说将来要使用Cairo。这两种组件……嘿嘿，贝壳都用过。但是firefox最强大的是他的插件组，效果终身难忘，让人不忍舍弃。下面贝壳介绍一下firefox的部分插件，脚本。&lt;br&gt;    /find/，这是个很小巧的插件，可以使得firefox能够以正则表达式在全文进行搜索。普通用户就表想了，这东西可是专业人士的杀手工具。可以做出&amp;quot;搜索全文中的所有电话号码&amp;quot;或者&amp;quot;搜索全文中的所有email&amp;quot;等等强大功能。当然，如果你需要的话。&lt;br&gt;    CustomizeGoogle，GFan一定要用。这个插件可以定制Google，例如可以在其他搜索引擎搜索，剔除赞助商广告，修改搜索的语言(贝壳的firefox就老阿达到英文上去，用这个插件就一切OK)。适用于Google的多个产品，包括gmail，google reader等等。&lt;br&gt;    fasterfox，强力推荐，加速插件。不过通常我都是用来调整性能参数的。自定义设置，不启用增强预读，缓存32M。这个配置对于0.5-1G的本本很有用。&lt;br&gt;    firebug，这东西也就网站开发人员用。不过绝对是杀手阿，可以看到网页的css，javascript，在线调试，察看ajax的网络通讯。通过这个东西，很容易调试多数的网页。&lt;br&gt;    fireshot，推荐看小说的的人用。可以将当前的网页整个导出成png(贝壳注：这不就是Cairo的基础功能么？导出到虚拟interface)。想想你看小说，将当前页面打印到png。不用截屏拼接，嘿嘿。当然，更好的方法是用firebug，直接可以提取内容。不过……看你水准了。&lt;br&gt;    flashgot，强力推荐，用这个东西可以将firefox的下载转到flashget上。当然，也支持迅雷，netant和bitcomet。这个东西弥补了firefox不支持专用下载软件的尴尬。当然，也有人喜欢都在firefox里面做。这个就如人饮水拉。&lt;br&gt;    gladder，用于爬GFW看Wikipedia的东西。如果听不懂，我不再解释。&lt;br&gt;    gmark，推荐多个电脑的人用，可以在各个地方用google bookmark，就好像用自己的bookmark一样，方便统一bookmark。如果你不喜欢在线bookmark(我觉得没有必要，用浏览器必定在线，除非google故障离线bookmark才有用)，那么可以用gmark的导出功能，导出到html。然后用firefox的导入，同步两个bookmark。其他插件要么是使用不习惯，要么就是不能和firefox自身的bookmark同步(都是单向的从firefox bookmark导出)。&lt;br&gt;    google reader notifier，推荐用google reader的挂线族。这个插件会提示你有多少东西你没有读，定时刷新。&lt;br&gt;    google笔记本，这个需要到google去下载，和gmark一样是让多个电脑同步的好东西。可以直接弹出一个google note让你记东西，并且在任何地方访问。同时也可以选中网页中的部分内容，点击加笔记，自动添加到笔记本中。&lt;br&gt;    greasemonkey，强力推荐，将用户脚本插入到页面中的组件，可以动态修改页面行为。下面会专门讲用这个组件挂脚本的技巧。&lt;br&gt;    IE tab，强力推荐，有的时候突然需要看IE，但是单独开一个IE非常麻烦。直接点右下的这个图标，当前页面就会自动切换成IE浏览。只是如果处于登陆中，恐怕会退出。&lt;br&gt;    keyconfig，可以自己配置firefox的快捷键。&lt;br&gt;    MinimizeToTray，最小化到托盘区的组件。配合上面一个，对付老板的利器阿。&lt;br&gt;    NoScript，强力推荐，拒绝恶意脚本，增加安全性。当然，弄不好就是拒绝正常脚本，增加麻烦。&lt;br&gt;    Session Manager，强力推荐，可以保存你当前在看的所有列表，下次恢复。也可以同时恢复登陆状态(例如你登陆了网站，下次上线就如同中间没有做任何动作一样，当然如果超时被踢就没办法了)，恢复关闭窗口。对付firefox的重起，减少内存消耗(手动重起)，看一堆页面看到一半有事……等等。非常有效。&lt;br&gt;    Tree Style Tab，另类的tab样式，把tab在左边做成树，可以折叠展开。如果你和我一样，经常喜欢大量的打开页面。此时，上面的tab往往缩的很小，看都看不到，但是还是长的要左右乱翻。这个时候这个插件非常有效。而且可以看到浏览的派生关系。如果平时觉得浪费空间，可以改回去。等需要的时候改过来。&lt;br&gt;    Update Scanner，扫描页面变化，如果有变化提示。对于看小说/泡论坛……等等。不用你们一天老去刷帖子了，这个插件可以提示你页面是否更新。当然不是没有更好的，不过那些东西都要写变化脚本，天哪～～&lt;br&gt;    上述的插件大都能在addons.mozilla.org或者addons.mozine.cn找到，如果不行就去google搜索。注意使用插件会消耗一定内存，尽管上面的大多插件都不怎么消耗内存，可都放上也比较让人受不了。一般贝壳都是将不用的转到禁用的。&lt;br&gt;    下面讲解greasemonkey的用户脚本技巧，多数脚本可以到userscript.org找到。&lt;br&gt;    GoogleTagCloudMaker，最好用的greasemonkey脚本。可以将google搜索的广告移除，变成关键字云。点击关键字云往往能追踪搜索，直到找到需要的东西。&lt;br&gt;    Show Btchina，让你可以浏览bt.btchina.net。这是个bittorrent种子搜集站，但是firefox无法浏览。使用这个脚本使得firefox可以正常浏览。&lt;br&gt;    Download Youtube Video III，在youtube的播放文件下面显示一个download，链接到播放的flv文件。可以很轻松的进行下载。以前贝壳都是用youplayer，老开着占内存，不老开就要重起firefox。虽然有session manager，不过也很讨厌。使用脚本就可以针对页面工作，减少内存消耗。&lt;br&gt;    以上的脚本在安装greasemonkey后可以直接点击安装。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e6%99%92%e4%b8%80%e6%99%92%e6%88%91%e7%9a%84firefox&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1765.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1765.entry</guid><pubDate>Wed, 05 Mar 2008 06:43:32 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1765/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1765.entry#comment</wfw:comment><dcterms:modified>2008-03-05T06:43:32Z</dcterms:modified></item><item><title>用firefox看facebook的问题</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1763.entry</link><description>     用firefox看facebook的时候老出问题，主要是验证码无法通过。会么？这年头连live spaces都可以用firefox了。(当然图片上传例外，除非你用IE Tab)而且facebook还有firefox的toolbar，要是再无法使用firefox就太奇怪了。&lt;br&gt;    今天总算发现了问题的所在，facebook使用了ajax技术，这种技术会动态的载入和卸载一些页面内容。而我使用了NoScript脚本，并且将facebook加入了白名单。这下可中计了。facebook常规浏览的时候，脚本都来自facebook本身。而当验证的时候，使用的另外一个公司的服务。在验证前，页面的脚本都是不被阻止的，因此我也没有发现异常。在点击验证后，由于页面没有刷，所以我压根没有注意到，下面的阻止从完全通过变成了部分阻止。当然，被阻止的就是另外一家公司的验证脚本。&lt;br&gt;    因此，我将这家公司也加入了NoScript的白名单。OK，世界从此清静了。&lt;br&gt; &lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e7%94%a8firefox%e7%9c%8bfacebook%e7%9a%84%e9%97%ae%e9%a2%98&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1763.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1763.entry</guid><pubDate>Mon, 03 Mar 2008 06:37:26 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1763/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1763.entry#comment</wfw:comment><dcterms:modified>2008-03-03T06:37:53Z</dcterms:modified></item><item><title>通知时代</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1756.entry</link><description>     以下内容可以说是作为一个时代的预告，请大家见证将来是否按照我的预想进行。&lt;br&gt;    首先请大家想想，当大家上网的时候，都做什么？也许是打游戏，也许是看电影，也许是泡论坛，也许是看好友的blog。随着web2.0时代的到来，我们每个人都有发布自己话语的能力。看上去和上世纪末的主页时代类似，然而不同的是，发布的频率增高了。假定你和我一样，有大约20-50个好友在网络上进场写blog。每个人每月写一篇，那么你每天就有1-2篇blog要看。你喜欢的电视剧有10个，它们每周更新一次，那么你每天就有1-2集电视剧要看。依此类推，你所关心的东西在网络上绝对不缺。每天平均下来都要看3-5篇东西，和几个朋友聊聊最新的生活，看几集电视剧，多好的生活。然而，当前却有个不和谐的问题，你需要持续的检查更新！&lt;br&gt;    按照我们上文举出的数据来推算，如果这个人每天需要看这些东西作为日常的网络活动。那么他就需要检查30-100个页面来确定哪些内容更新了，需要跟踪10-20个页面来确定需要下载的东西。在网络小众的时代，也许这不是个问题。我们的习惯是每天上网，然后收一次邮件，检查书签里面所有的页面，看看是否有更新了。下载最新的东西，把写好的信件发出去。以天为单位来说，这不是一个问题。然而正如在线时间的增长催生了IM来替代Mail一样，长时间的在线使得我们希望简单的获得&amp;quot;第一时间&amp;quot;的东西。邮件到达的时候，我希望&amp;quot;第一时间&amp;quot;的获得。有新闻的时候，我希望&amp;quot;第一时间&amp;quot;的关注。朋友写了blog的时候，我希望&amp;quot;第一时间&amp;quot;的回复。OK，假定5分钟是你可以认可的&amp;quot;第一时间&amp;quot;。那么你需要每5分钟&amp;quot;检查30-100个页面来确定哪些内容更新了，需要跟踪10-20个页面来确定需要下载的东西&amp;quot;。&lt;br&gt;    幸运的是，我们可以使用程序来自动做这些事情，并且现在已经有了部分解决方案。有一种邮件跟踪程序，可以跟踪pop3，hotmail，yahoo等常见的邮箱，检查是否有新的邮件。好友的blog和新闻都可以用rss软件来跟踪是否有新的内容。然而不幸的是，每种解决方案都是单独的。如果你需要持续的跟踪，就必须挂上邮箱的检查程序，rss的检查程序，网页的检查程序(用于部分不支持rss的网页)。不但复杂难以管理而且资源消耗也相当惊人。&lt;br&gt;    我预期将来大家都会持续的挂线，因此预计将来的模型是&amp;quot;通知&amp;quot;而非&amp;quot;检查&amp;quot;。当你有邮件时，会收到邮件到达通知，当你关注的新闻更新时，会收到新闻更新通知。而具体怎么实现呢？我估计是IM系统整合。当今IM界发展的趋势是互通，IM的特点又是即时，因此有很大可能性会是使用IM来通告新的内容到达。你可以向一些支持的网站注册你的IM，而后他们会视图加你为好友，并且向你提供验证号。当你将验证号回复给网站后，你的网站账户(如果需要的话)就和IM绑定在一起。而后你可以主动订阅一些内容主体的更新通知，当网站程序更新这些内容的时候，会读取到你的订阅。而后将内容更新和你的IM发送到一个队列中，这个队列再将这些消息发送到你的IM中。&lt;br&gt;    当然，IM接受这些消息的显示方式很可能不会用通常的消息界面，更可行的界面是类似google reader的聚合通告界面。当你完成订阅后，你的IM就会将源放到一个通知树中。每个源是一个列表，代表了这个源的内容。例如邮箱源的列表就是邮箱内的邮件，rss源的列表就是rss的新闻，&amp;quot;越狱&amp;quot;这种源的列表就是一堆的&amp;quot;越狱&amp;quot;影片下载地址(当然，如果合法的话)。甚至论坛的某个帖子都可以做源。源代表了内容，并且通告变化，而IM则记录了客户是否看过每个源的具体内容。有可能还会出现一些服务网站，负责每一定时间去检测不支持源的页面，如果满足一定的更新条件，那么就通知页面更新了。&lt;br&gt;    通过这种模式，你每天上线后就可以看到没上线时更新的内容，直接点击过去看。并且在线的时候各种需要的消息还会持续的通告过来。当然，你也应该可以(只要客户端支持)设定某种消息会强制的弹出(例如公司的邮箱里面有新邮件)，而某些只是更改托盘区的图标(例如某些有点关心的新闻更新了，你不会希望这个原因把你从游戏里面拉出来吧)。理论上说，当IM的客户端范畴拓展到手机后，我们甚至可以如同宣传中说的一样&amp;quot;随时随地，掌握信息&amp;quot;了。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e9%80%9a%e7%9f%a5%e6%97%b6%e4%bb%a3&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1756.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1756.entry</guid><pubDate>Thu, 21 Feb 2008 06:54:36 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1756/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1756.entry#comment</wfw:comment><dcterms:modified>2008-02-21T06:54:36Z</dcterms:modified></item><item><title>Process Explorer的潜在内存泄漏</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1738.entry</link><description>&lt;p&gt;    贝壳最近碰到一个郁闷到死的问题。机器经常出现硬盘狂转，系统响应延迟。系统弹出一个错误，然后死机。贝壳开始猜测是硬盘驱动问题，升级驱动N次，无效。然后再猜测是ext2fs的问题(贝壳用这个驱动挂载linux下面的盘的)，看来看去，不是。最后，贝壳确定了，这是内存泄漏了～～～&lt;br&gt;    问题是，这时候可没人跳出来推荐喝什么口服液的。贝壳系统中永远挂着一个procexp，看内存状态的。这东西是sysinternals的产品，后来被微软收购了。功能强大，很多系统调试，杀马都需要用到。于是贝壳就用这个工具看哪个程序的内存泄漏，可是看来看去看不到。准确说，是没等贝壳看到，系统就先死透了。最后贝壳多次尝试，发现了一个死机的规律。当mysql开启的时候，procexp就会随时发生异常死机。这是一个重要的提示，要么mysql内存泄漏了，要么procexp内存泄漏了。究竟是哪个呢？贝壳用了同属于sysinternals开发的pstools系列工具，仔细检查了异常发生时候的内存状态，确定，Process Explorer存在内存泄漏的风险！&lt;br&gt;    看来sysinternals被微软收购后，旗下的工具也出现了微软的一贯特色。以下是一次内存泄漏后，终止mysql服务后抓下来的内存状态输出。如果不终止mysql，不等我抓系统就挂了。&lt;br&gt;Process memory detail for HOME-B2326348D0: 
&lt;p&gt;Name                Pid      VM      WS    Priv Priv Pk   Faults   NonP Page&lt;br&gt;Idle                  0       0      28       0       0        0      0    0&lt;br&gt;System                4     800      52       0       0    10120      0    0&lt;br&gt;smss                772    3748      48     172    1648      223      0    5&lt;br&gt;csrss               828   68132    1464    2304    3768    13748      6  144&lt;br&gt;winlogon            856   61528     580    8536    8684     5143     39   96&lt;br&gt;services            900   37724     804    2256    2404     2740      7   65&lt;br&gt;lsass               912   44848     352    2684    2860     7332      7   80&lt;br&gt;svchost            1060   36904     200    1500    1544     1028      3   68&lt;br&gt;svchost            1136   39256     456    1984    2004     1437     13   72&lt;br&gt;svchost            1216  118756    2564   19236   28112    24221     93  197&lt;br&gt;svchost            1292   31728     192    1472    1512     1123      4   55&lt;br&gt;aswUpdSv           1536   18748      52     652     652      557      2   31&lt;br&gt;ashServ            1592  120428    6704   16628   41168  1076043      8  128&lt;br&gt;explorer           1884  119644    1908   19128   20552  4364782     16  177&lt;br&gt;spoolsv             288   50072     224    3564    3828     1502      5   85&lt;br&gt;TSVNCache           544   48008     700    6968    7068    21580      4   67&lt;br&gt;mobmeter            620   41116     588    4940    5044    14266      3   63&lt;br&gt;procexp             628  605756   15532  549068  549068  4776417      8  109&lt;br&gt;ashDisp             636   54468     928    6992    7016    28399      5   80&lt;br&gt;ctfmon              664   39064     380    4816    4840    15588      4   66&lt;br&gt;googletalk          720   76420    2852    8540    9036   428030     13  108&lt;br&gt;mdm                 832   30008     440    1088    1100      860      3   49&lt;br&gt;svchost            1244   40704     208    2640    2708     1896      3   73&lt;br&gt;svnserve           1264   16612     124     904     920      652      3   29&lt;br&gt;svchost             232   37936     536    1592    1636     1330      4   70&lt;br&gt;alg                 600   35664     200    1312    1352     1018      5   69&lt;br&gt;TTPlayer           3208   65672    3688   10920   13924   169533      8   86&lt;br&gt;thunderbird        3240  109016    2272   28832   31344    64167     14  112&lt;br&gt;conime             3284   42564     404    5184    5184    17612      3   68&lt;br&gt;firefox            1944  270920   11108  118720  132648  1233696     14  135&lt;br&gt;flashget           2836  108756   11248   19472   29636   117115     30  146&lt;br&gt;pyintau            2080   45004     172    4720    4788     1848      3   62&lt;br&gt;wuauclt            1068   67012     396    6580    6600     2167      7  115&lt;br&gt;cmd                3540   32764     920    3308    3372    15075      2   60&lt;br&gt;pslist             3048   32124    3108    2440    2956    10890      2   49&lt;br&gt;    我们可以看到，procexp这个进程的虚拟内存空间只有60M，工作集更只有15M，可私有内存高达549M！贝壳的机器只有768M内存，不死机还等啥？&lt;br&gt;    贝壳试验了mysql5.0.45，mysql5.0.51a，mysql5.1.22，procexp11.01，procexp11.04。确定在贝壳的本本上全都会造成上述问题。但是同样的环境在家里的2G内存机器上模拟的时候，全都不出现上述问题。从测试角度讲，这个属于和环境相关的隐性危险，严重级别是重。 
&lt;div&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+Process+Explorer%e7%9a%84%e6%bd%9c%e5%9c%a8%e5%86%85%e5%ad%98%e6%b3%84%e6%bc%8f&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1738.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1738.entry</guid><pubDate>Thu, 31 Jan 2008 03:21:06 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1738/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1738.entry#comment</wfw:comment><dcterms:modified>2008-01-31T03:22:17Z</dcterms:modified></item><item><title>弄死MSN的共享文件夹</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1717.entry</link><description>    MSN8的共享文件夹功能根本就是一个废物功能，速度慢，不习惯，而且用处不大。最恶心的是，没有卸载选项不说，手工卸载后一开MSN一重起还会回来。NND，看我怎么弄死他。MSN虽然是微软自己的产品，但是也需要遵守微软的API行为。改变资源管理器的行为是用COM组件注入到exlporer中实现的，没有使用驱动层的东西。那么我们就设法阻断DLL文件的注入加载。&lt;br&gt;    首先，regsvr32 /u是不行的。因为MSN一启动又会注册上，除非你不用MSN。删除文件也不行，因为会再生成一个。那么，我放着文件不动，把内容清空，然后再删除NTFS权限怎么样呢？即使是微软的产品，也不会强制说我的更改无效，然后自己胡来一套吧。&lt;br&gt;    首先，关闭所有MSN有关软件，在运行中输入cmd开一个命令行窗口。然后，用process explorer(现在这东西也是微软的产品)终止explorer进程(系统自带那个应该也行，不过我没有测试过)。这步顺序非常重要，因为我们要先阻断COM组件的加载，否则无法对文件实行更改。所以我们要先打开一个CMD，然后再关闭explorer。否则一旦关闭explorer，开CMD就难了。而没有CMD，要去删除文件就要多费一些手续了。&lt;br&gt;    我们现在在CMD中切换到MSN所在目录，删除fsshext.8.1.0178.00.dll啥的文件。这个文件名会根据你安装的版本而变化。而后启动explorer(在CMD里面敲explorer就好)，这个时候COM组件已经没有加载了。于是我们建立一个文本文件，改名叫fsshext.8.1.0178.00.dll，放到MSN的目录里面，再删除所有人的访问权限。删除的方法是文件上右击，点属性，安全，高级，取消&amp;quot;从父目录继承权限&amp;quot;的勾选，然后点删除。如果看不到安全选项卡，检查以下项目。工具，文件夹选项，察看，使用简单文件共享(推荐)，取消他的勾选。微软的东西，最好表随便勾。&lt;br&gt;    根据我的测试，这时候你随便重起电脑，MSN的组件说加载不上就加载不上。同理也可以应用到3721之类的流氓组件上，只要抢先建立了同名的文件，并且阻断了权限，这些组件就会无法使用。如果你进一步做了分离权限(日常不使用管理员账户)，即使安装程序作者知道这种方法都无法应对。如果可以的话，就说明微软存在漏洞了。 
&lt;div&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e5%bc%84%e6%ad%bbMSN%e7%9a%84%e5%85%b1%e4%ba%ab%e6%96%87%e4%bb%b6%e5%a4%b9&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1717.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1717.entry</guid><pubDate>Sat, 26 Jan 2008 06:43:47 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1717/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1717.entry#comment</wfw:comment><dcterms:modified>2008-01-26T06:45:33Z</dcterms:modified></item><item><title>财务数据库</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1695.entry</link><description>     贝壳最近工作繁忙，一般都是晚上十一点到家睡觉，第二天早上继续上班的那种，所以blog基本没怎么动。现在放篇财务数据库的原型，大家参考一下吧。当然，是对程序员而言。像六牙四皂小姐这种下面估计是压根看不懂的，而且也不会有那种变态的资金准度要求。&lt;br&gt;    首先建立一个账户表。&lt;br&gt;DROP TABLE IF EXISTS `accont_info`;&lt;br&gt;CREATE TABLE `accont_info` (&lt;br&gt;  `id` int(11) NOT NULL auto_increment,&lt;br&gt;  `username` varchar(40) NOT NULL,&lt;br&gt;  `accont` varchar(40) NOT NULL,&lt;br&gt;  `accont_type` int(11) NOT NULL default '0',&lt;br&gt;  PRIMARY KEY  (`id`),&lt;br&gt;  UNIQUE KEY `username` (`username`,`accont`)&lt;br&gt;) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=gbk;&lt;br&gt;    输入用户名，账户名和账户类型，例如&amp;quot;许智翔&amp;quot;,&amp;quot;招行账户&amp;quot;,2。账户类型中规定1是现金，2是存款，3是信用卡，4以上不计算。这样可以使用多个现金账户，存款账户和信用卡账户。然后利用子查询把所有类型间的相互行为统计出来。&lt;br&gt;    然后是类型表。&lt;br&gt;DROP TABLE IF EXISTS `type_info`;&lt;br&gt;CREATE TABLE `type_info` (&lt;br&gt;  `id` int(11) NOT NULL auto_increment,&lt;br&gt;  `type` varchar(40) NOT NULL,&lt;br&gt;  `subtype` varchar(40) default NULL,&lt;br&gt;  PRIMARY KEY  (`id`),&lt;br&gt;  UNIQUE KEY `type` (`type`,`subtype`)&lt;br&gt;) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=gbk;&lt;br&gt;    最后是资金流动数据表，accont_id中填写出户账户名，to_accont中填写入户账户名。如果是外部(例如从别人那里拿钱或者给别人钱)，则写0。happen_time上填写发生时间，money上写金额，message上写备忘。&lt;br&gt;DROP TABLE IF EXISTS `money_info`;&lt;br&gt;CREATE TABLE `money_info` (&lt;br&gt;  `id` int(11) NOT NULL auto_increment,&lt;br&gt;  `accont_id` int(11) NOT NULL,&lt;br&gt;  `to_accont` int(11) default NULL,&lt;br&gt;  `happen_time` datetime NOT NULL,&lt;br&gt;  `type` int(11) NOT NULL,&lt;br&gt;  `record_modify` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,&lt;br&gt;  `money` decimal(9,2) NOT NULL,&lt;br&gt;  `message` varchar(400) default NULL,&lt;br&gt;  PRIMARY KEY  (`id`),&lt;br&gt;  KEY `happen_time` (`happen_time`,`type`,`accont_id`)&lt;br&gt;) ENGINE=InnoDB AUTO_INCREMENT=914 DEFAULT CHARSET=gbk;&lt;br&gt;    下面就是核心代码了。这个存储过程需要两个时间，统计的开始和结束时间。可以得出两个表，这段时间的收支和余额表，分类支出表。&lt;br&gt;DELIMITER $$&lt;br&gt;&lt;br&gt;DROP PROCEDURE IF EXISTS `money`.`count_all` $$&lt;br&gt;CREATE DEFINER=`shell`@`%` PROCEDURE `count_all`(IN start_date DATETIME, IN end_date DATETIME)&lt;br&gt;BEGIN&lt;br&gt;declare cash_get DECIMAL(9,2);&lt;br&gt;declare bank_get DECIMAL(9,2);&lt;br&gt;declare card_get DECIMAL(9,2);&lt;br&gt;declare cash_used DECIMAL(9,2);&lt;br&gt;declare cash_bank DECIMAL(9,2);&lt;br&gt;declare bank_used DECIMAL(9,2);&lt;br&gt;declare bank_cash DECIMAL(9,2);&lt;br&gt;declare card_used DECIMAL(9,2);&lt;br&gt;select sum(money) into cash_get from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;to_accont in (SELECT id FROM accont_info where accont_type=1);&lt;br&gt;select sum(money) into bank_get from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;to_accont in (SELECT id FROM accont_info where accont_type=2);&lt;br&gt;select sum(money) into card_get from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;to_accont in (SELECT id FROM accont_info where accont_type=3);&lt;br&gt;select sum(money) into cash_used from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;accont_id in (SELECT id FROM accont_info where accont_type=1);&lt;br&gt;select sum(money) into cash_bank from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;accont_id in (SELECT id FROM accont_info where accont_type=1) and&lt;br&gt;to_accont in (SELECT id FROM accont_info where accont_type=2);&lt;br&gt;select sum(money) into bank_used from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;accont_id in (SELECT id FROM accont_info where accont_type=2);&lt;br&gt;select sum(money) into bank_cash from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;accont_id in (SELECT id FROM accont_info where accont_type=2) and&lt;br&gt;to_accont in (SELECT id FROM accont_info where accont_type=1);&lt;br&gt;select sum(money) into card_used from money_info where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and&lt;br&gt;accont_id in (SELECT id FROM accont_info where accont_type=3);&lt;br&gt;select &amp;quot;开始日期&amp;quot;,start_date&lt;br&gt;union&lt;br&gt;select &amp;quot;结束日期&amp;quot;,end_date&lt;br&gt;union&lt;br&gt;select &amp;quot;现金总收入&amp;quot;,cash_get&lt;br&gt;union&lt;br&gt;select &amp;quot;现金总支出&amp;quot;,cash_used&lt;br&gt;union&lt;br&gt;select &amp;quot;  现金存款&amp;quot;,cash_bank&lt;br&gt;union&lt;br&gt;select &amp;quot;  现金使用&amp;quot;,cash_used-cash_bank&lt;br&gt;union&lt;br&gt;select &amp;quot;现金总余额&amp;quot;,cash_get-cash_used&lt;br&gt;union&lt;br&gt;select &amp;quot;总存款&amp;quot;,bank_get&lt;br&gt;union&lt;br&gt;select &amp;quot;存款使用&amp;quot;,bank_used&lt;br&gt;union&lt;br&gt;select &amp;quot;  银行提款&amp;quot;,bank_cash&lt;br&gt;union&lt;br&gt;select &amp;quot;  信用卡使用&amp;quot;,card_used&lt;br&gt;union&lt;br&gt;select &amp;quot;  其他使用&amp;quot;,bank_used-bank_cash-card_used&lt;br&gt;union&lt;br&gt;select &amp;quot;存款余额&amp;quot;,bank_get-bank_used&lt;br&gt;union&lt;br&gt;select &amp;quot;信用卡平衡&amp;quot;,card_get-card_used&lt;br&gt;;&lt;br&gt;select m.type as typeid,t.type as typename,sum(m.money)as money from money_info m left join type_info t on m.type=t.id&lt;br&gt;where happen_time&amp;gt;=start_date and happen_time&amp;lt;end_date and to_accont=0 group by m.type;&lt;br&gt;END $$&lt;br&gt;&lt;br&gt;DELIMITER ;&lt;br&gt;    下面这个是上面的辅助代码，统计这个月的数据。&lt;br&gt;DELIMITER $$&lt;br&gt;&lt;br&gt;DROP PROCEDURE IF EXISTS `money`.`count_this_month` $$&lt;br&gt;CREATE DEFINER=`shell`@`%` PROCEDURE `count_this_month`()&lt;br&gt;BEGIN&lt;br&gt;&lt;br&gt;set @now_start=if(day(current_date())&amp;lt;25,&lt;br&gt;date_format(date_sub(current_date(),interval 1 month),'%Y-%m-25'),&lt;br&gt;date_format(current_date(),'%Y-%m-25'));&lt;br&gt;set @now_end=date_add(@now_start,interval 1 month);&lt;br&gt;CALL count_all(@now_start,@now_end);&lt;br&gt;&lt;br&gt;END $$&lt;br&gt;&lt;br&gt;DELIMITER ;&lt;br&gt;    最后这个是统计历史的收入，支出，现金支出，银行支出，信用卡支出和其他支出。&lt;br&gt;DELIMITER $$&lt;br&gt;&lt;br&gt;DROP PROCEDURE IF EXISTS `money`.`count_month` $$&lt;br&gt;CREATE DEFINER=`shell`@`%` PROCEDURE `count_month`()&lt;br&gt;BEGIN&lt;br&gt;&lt;br&gt;create temporary table temp_in(&lt;br&gt;yearmonth datetime,&lt;br&gt;money DECIMAL(9,2)&lt;br&gt;);&lt;br&gt;create temporary table temp_out(&lt;br&gt;yearmonth datetime,&lt;br&gt;money DECIMAL(9,2)&lt;br&gt;);&lt;br&gt;create temporary table temp_cash(&lt;br&gt;yearmonth datetime,&lt;br&gt;money DECIMAL(9,2)&lt;br&gt;);&lt;br&gt;create temporary table temp_bank(&lt;br&gt;yearmonth datetime,&lt;br&gt;money DECIMAL(9,2)&lt;br&gt;);&lt;br&gt;create temporary table temp_card(&lt;br&gt;yearmonth datetime,&lt;br&gt;money DECIMAL(9,2)&lt;br&gt;);&lt;br&gt;&lt;br&gt;insert into temp_in&lt;br&gt;select date_format(date_sub(happen_time, interval 24 day),&amp;quot;%Y-%m-25&amp;quot;) as yearmonth,sum(money)&lt;br&gt;from money_info where accont_id=0 group by yearmonth;&lt;br&gt;insert into temp_out&lt;br&gt;select date_format(date_sub(happen_time, interval 24 day),&amp;quot;%Y-%m-25&amp;quot;) as yearmonth,sum(money)&lt;br&gt;from money_info where to_accont=0 group by yearmonth;&lt;br&gt;insert into temp_cash&lt;br&gt;select date_format(date_sub(happen_time, interval 24 day),&amp;quot;%Y-%m-25&amp;quot;) as yearmonth,sum(money)&lt;br&gt;from money_info where to_accont=0 and accont_id in (select id from accont_info where accont_type=1) group by yearmonth;&lt;br&gt;insert into temp_bank&lt;br&gt;select date_format(date_sub(happen_time, interval 24 day),&amp;quot;%Y-%m-25&amp;quot;) as yearmonth,sum(money)&lt;br&gt;from money_info where to_accont=0 and accont_id in (select id from accont_info where accont_type=2) group by yearmonth;&lt;br&gt;insert into temp_card&lt;br&gt;select date_format(date_sub(happen_time, interval 24 day),&amp;quot;%Y-%m-25&amp;quot;) as yearmonth,sum(money)&lt;br&gt;from money_info where to_accont=0 and accont_id in (select id from accont_info where accont_type=3) group by yearmonth;&lt;br&gt;&lt;br&gt;select o.yearmonth as startday,date_add(o.yearmonth,interval 1 month) as endday,&lt;br&gt;ifnull(i.money,0) as money_in,ifnull(o.money,0) as money_out,ifnull(c.money,0) as money_cash,&lt;br&gt;ifnull(b.money,0) as money_bank,ifnull(d.money,0) as money_card,&lt;br&gt;ifnull(o.money,0)-ifnull(c.money,0)-ifnull(b.money,0)-ifnull(d.money,0) as money_other&lt;br&gt;from temp_out o&lt;br&gt;left join temp_in i on o.yearmonth=i.yearmonth&lt;br&gt;left join temp_cash c on o.yearmonth=c.yearmonth&lt;br&gt;left join temp_bank b on o.yearmonth=b.yearmonth&lt;br&gt;left join temp_card d on o.yearmonth=d.yearmonth;&lt;br&gt;&lt;br&gt;drop temporary table if exists temp_in,temp_out,temp_cash,temp_bank,temp_card;&lt;br&gt;&lt;br&gt;END $$&lt;br&gt;&lt;br&gt;DELIMITER ;&lt;br&gt;    怎么样，很简单实用吧。建议实用mysql+mysqlgui。图形的录入和统计，方便的备份。比以前写的方便多了。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e8%b4%a2%e5%8a%a1%e6%95%b0%e6%8d%ae%e5%ba%93&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1695.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1695.entry</guid><pubDate>Fri, 25 Jan 2008 05:15:26 GMT</pubDate><slash:comments>4</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1695/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1695.entry#comment</wfw:comment><dcterms:modified>2008-01-26T06:44:48Z</dcterms:modified></item><item><title>libxml使用中的编码问题</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1693.entry</link><description>&lt;p&gt;    libxml是gnome的XML解析库，具有强大的解析能力，支持DOM和SAX解析模型，属于验证型解析器。其内部是使用utf-8编码工作的，因此gbk之类编码的XML无法解析。为了解决这个问题，我们可以使用一个很简单的小窍门。&lt;br&gt;    libxml是要和iconv一并使用的，头文件引用一般类似以下形式。&lt;br&gt;#include &amp;lt;iconv.h&amp;gt;&lt;br&gt;#pragma comment(lib, &amp;quot;iconv&amp;quot;)&lt;br&gt;#include &amp;lt;libxml/tree.h&amp;gt;&lt;br&gt;#include &amp;lt;libxml/parser.h&amp;gt;&lt;br&gt;#pragma comment(lib, &amp;quot;libxml2&amp;quot;)&lt;br&gt;    这样的话，我们向libxml注册一个处理句柄，对其他编码的xml先执行一次转换，再进行解析。&lt;br&gt;iconv_t         iconv_utf8_gbk = NULL;&lt;br&gt;iconv_t         iconv_gbk_utf8 = NULL;&lt;br&gt;int gbk_input (unsigned char *out, int *outlen, const unsigned char *in,&lt;br&gt;      int *inlen)&lt;br&gt;{&lt;br&gt; char           *outbuf = (char *) out;&lt;br&gt; char           *inbuf = (char *) in;&lt;br&gt; size_t          rslt;&lt;br&gt; rslt =&lt;br&gt;  iconv (iconv_utf8_gbk, (const char **) &amp;amp;inbuf, (size_t *) inlen,&lt;br&gt;      &amp;amp;outbuf, (size_t *) outlen);&lt;br&gt; if (rslt &amp;lt; 0)&lt;br&gt;  return rslt;&lt;br&gt; *outlen = ((unsigned char *) outbuf - out);&lt;br&gt; *inlen = ((unsigned char *) inbuf - in);&lt;br&gt; return *outlen;&lt;br&gt;}
&lt;p&gt;int gbk_output (unsigned char *out,&lt;br&gt;    int *outlen, const unsigned char *in, int *inlen)&lt;br&gt;{&lt;br&gt; char           *outbuf = (char *) out;&lt;br&gt; char           *inbuf = (char *) in;&lt;br&gt; size_t          rslt;&lt;br&gt; rslt =&lt;br&gt;  iconv (iconv_gbk_utf8, (const char **) &amp;amp;inbuf, (size_t *) inlen,&lt;br&gt;      &amp;amp;outbuf, (size_t *) outlen);&lt;br&gt; if (rslt &amp;lt; 0)&lt;br&gt;  return rslt;&lt;br&gt; *outlen = ((unsigned char *) outbuf - out);&lt;br&gt; *inlen = ((unsigned char *) inbuf - in);&lt;br&gt; return *outlen;&lt;br&gt;}&lt;br&gt;    初始化的时候运行以下代码进行句柄注册。&lt;br&gt;{&lt;br&gt; if (iconv_utf8_gbk == NULL)&lt;br&gt;  iconv_utf8_gbk = iconv_open (&amp;quot;utf-8&amp;quot;, &amp;quot;gbk&amp;quot;);&lt;br&gt; if (iconv_gbk_utf8 == NULL)&lt;br&gt;  iconv_gbk_utf8 = iconv_open (&amp;quot;gbk&amp;quot;, &amp;quot;utf-8&amp;quot;);&lt;br&gt; LIBXML_TEST_VERSION;&lt;br&gt; xmlNewCharEncodingHandler (&amp;quot;gb2312&amp;quot;, gbk_input, gbk_output);&lt;br&gt; xmlNewCharEncodingHandler (&amp;quot;gbk&amp;quot;, gbk_input, gbk_output);&lt;br&gt;}&lt;br&gt;    经过试验，这样我们就可以解析编码类型为gbk和gb2312的xml文件了。可以进行输入和输出，不过输出的utf-8形式让人觉得有点难过……&lt;br&gt;
&lt;div&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+libxml%e4%bd%bf%e7%94%a8%e4%b8%ad%e7%9a%84%e7%bc%96%e7%a0%81%e9%97%ae%e9%a2%98&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1693.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1693.entry</guid><pubDate>Thu, 27 Dec 2007 06:04:59 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1693/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1693.entry#comment</wfw:comment><dcterms:modified>2007-12-27T06:04:59Z</dcterms:modified></item><item><title>继承函数的拷贝构造</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1692.entry</link><description>&lt;div dir=ltr style="margin-right:0px"&gt;    从基类继承一个子类，基类有一个拷贝构造函数，子类重载了一个。那么在子类拷贝构造的时候会自动调用基类的拷贝构造函数吗？&lt;/div&gt;
&lt;div dir=ltr style="margin-right:0px"&gt;    答案是不会，自动调用的是基类的构造函数。&lt;/div&gt;
&lt;div dir=ltr style="margin-right:0px"&gt;    子类中如果需要调用基类的拷贝构造函数，需要这样用。&lt;/div&gt;
&lt;div dir=ltr style="margin-right:0px"&gt;    D (const D &amp;amp; o): B (o){...}&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e7%bb%a7%e6%89%bf%e5%87%bd%e6%95%b0%e7%9a%84%e6%8b%b7%e8%b4%9d%e6%9e%84%e9%80%a0&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1692.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1692.entry</guid><pubDate>Tue, 25 Dec 2007 07:49:53 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1692/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1692.entry#comment</wfw:comment><dcterms:modified>2007-12-27T06:05:20Z</dcterms:modified></item><item><title>wc、sort介绍</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1690.entry</link><description>&lt;div&gt;    首先声明一点，我介绍的小软件系列都是Linux下的，在Windows下可以找Gnuwin32里面提供的移植包。因此多数人都是可以使用的，只是高兴不高兴用的问题而已。&lt;/div&gt;
&lt;div&gt;    其次我得道歉。本来说好了每周介绍一些小软件的，结果MSN空间不稳定，加上贝壳又忙。所以现在才介绍第二个，大家理解理解吧。&lt;/div&gt;
&lt;div&gt;    这次介绍的对象是wc，不是厕所，也不是世界杯，而是一个字符统计软件。这个软件的目的是统计出一个文件内的行数，单词数，字符数。行数是按照硬回车来统计的，单词是按照分割符号来统计的，字符么就不说了。这个和Word的字符统计很像，不过用起来并不那么方便。也许有人奇怪，这种软件有什么用呢？主要是在脚本程序内使用来统计一些数据，也有用来统计程序的代码行数的。平时大家一般都是分开统计行数，这次可以wc -l *.cpp *.h。就可以得到所有文件的行数和总行数。&lt;/div&gt;
&lt;div&gt;    而后我补充介绍一个东西，sort。这东西也很简单，就是把输入的内容按照一定的法则排序输出。一般来说，排序法则是alpha法则，当然也有数字法则等等。这个软件主要是从输出中排除一些重复数据，或者把输出过滤。例如我们可以和上面的联合使用，wc -l *.c *.h | sort。就可以得到当前所有的文件的行数，并且排序。&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+wc%e3%80%81sort%e4%bb%8b%e7%bb%8d&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1690.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1690.entry</guid><pubDate>Mon, 03 Dec 2007 13:44:52 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1690/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1690.entry#comment</wfw:comment><dcterms:modified>2007-12-03T13:46:52Z</dcterms:modified></item><item><title>IM之争</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1689.entry</link><description>    我不记得这个Title是否已经写过了，不过无所谓，因为国际形势发生了变化。&lt;br&gt;    以前是ICQ和QQ争霸中国市场。后来MSN加进来一脚，ICQ淡出了。现在Fetion跑进来了。那么未来呢？&lt;br&gt;    我们先看看IM软件的发展方向吧。IM最早的远亲应当是IRC和电子邮件。不过电子邮件对于服务器需求太强大，用于实时对聊做不到。IRC虽然需求小了点，但也在不可承受的范围内。随着网络的发展，大家挂网时间越来越多。所以大家要求一种廉价有效的即时通讯手段。可以和某个人对话，而不用耗费太多的服务器成本。于是，ICQ应运而生了。ICQ可以说是最初的P2P体系者，两个人聊天的时候数据都是互相发送的，只有登录的时候才和服务器通讯。这样的好处是避免了大量的服务器开销，坏处是无法穿透防火墙。&lt;br&gt;    从协议上说，IM的协议互动机制和电子邮件基本是一致的。如果不介意服务器开销的话，我们可以把IM协议构架在POP3和SMTP上。对于这种倾向，有人应该感觉熟悉。那不是MSN的离线消息么？差不多。我们定义发送逻辑为，如果可以找到对方IP就找对方IP，不可以找到对方IP就给对方发送邮件。接受的时候我们就接受邮件，如果碰到特殊格式的就解析掉当做消息处理。同时如果在线则服务器会主动推送邮件消息过来(如果不这样就要非常快的定时查询新消息，非常耗费资源)。那么我们就构成了一个跨越服务商的IM方案了，并且还支持多种客户端和离线消息。例如我们通过智能手机的终端接入进来(记得么？我们的客户端其实只是个特殊点的邮件程序)，那就成了无线IM。&lt;br&gt;    问题是，我们动了谁的奶酪？&lt;br&gt;    服务商恐怕对此会非常不高兴。大家知道，电子邮件服务商的竞争比IM残酷多了。那么多IT公司，有多少是纯粹做电子邮件做发起来的？几乎没有。为什么呢？因为电子邮件的开放性强。开放性强是历史的产物，早在主机时代邮件协议就已经固定了，而且有了大量的实现。如果哪个ISP不遵循，那么就没有用户。但是遵循标准的结果就是谁都可以被谁替代。也许某某邮箱系统的界面好看点，某某邮箱系统的容量大点，某某邮箱的速度快点，某某邮箱的垃圾少点。但是都不是不可以替代的，属于非强用户粘着性的产品。(注意我没有使用弱这个词，因为一般人习惯用一个邮箱后也就不怎么更改了)如果邮箱服务收费，ISP会发现，几乎是立刻就没有用户了——&lt;br&gt;    然而IM则是在端点时代才发展出来的，而且始作俑者不是IETF成员，IETF也没有太关注。——这捅了大篓子。现在的IM产品，几乎一个产品和另外一个无法连接。一旦你大部分的朋友使用了某种IM，你也必须被迫使用某种IM。好比贝壳虽然不喜欢QQ(这厮没Linux版本还老封锁协议)，但一帮朋友都是QQ的，难道不用？这是意味着IM是扩散用户粘着的产品！&lt;br&gt;    这意味着什么呢？ISP们不用推销，只要他们拥有一定的用户了，用户就会自动扩展用户群。而且你的用户不会轻易离开你，即使你收费，也有相当的用户。如果改成开放的形式，很多大型的IM商就等着客户流失吧。因为他们有相当的客户群，因此往往会收取一定的费用或者产生较多的广告。而IETF已经开始制订IM的交互协议了，即SIMPLE协议。先不说这个协议是否先进是否安全，至少这个协议是开放的。开放的协议意味低附加值的服务，因此IM商肯定会抵制协议的推行。一般的逻辑是。如果SIMPLE协议的总客户集群无法和自己的客户群比较，则不和SIMPLE互通。这样有利于维持自己的IM群，进而取得收益。如果SIMPLE协议的总客户集群已经大大超过了自身的客户群，则和SIMPLE互通。因为可以扩大自己的群，进而扩大用户。所以SIMPLE协议应该是从新兴公司开始推广的。&lt;br&gt;    因此，作为一个用户来说，我更希望大家现在开始使用带有SIMPLE特征的服务。这样更有利于促使更多IM商互通服务，而且还会减少服务的费用。&lt;br&gt;    从历史上说，当今的各大IM厂商自有其来。QQ是特殊历史时期的特殊软件。开始的时候其实就是简化的ICQ中文版，除了中国制造外没有什么特长。后来中国的互联网娱乐潮起，QQ向娱乐转型，主攻大众市场，结果红的发紫。MSN则是更晚时期的产物，是MS攻占全球IM市场的拳头产品，主攻的是商务市场。Fetion是中移动今年新推出的IM产品，特点是和手机互通。&lt;br&gt;    就发展趋势来预期，IM主要呈现两个特点，一个是全分布化，一个是嵌入化。&lt;br&gt;    虽然IM软件的工作原理对于服务器要求不高，然而很多后续服务对于服务器却有强烈需求。我们先仅仅计算基础通讯消费吧。一个人登录的时候先认证，后回传所有好友的名单，套接字。一般登录一次开销最小也要在3K上下。一般成熟的IM软件总用户量至少是1000W以上(国内市场)，峰值冗余计算为五倍。计算结果就是一天的通信最少300G，最低带宽需求是20M。这还仅仅是登录造成的通讯成本。我们再考虑持续心跳激活某个特定客户端的重复时间——那这个开销就不是某个服务器所能支持的了。现在的IM服务器端，一般都是服务器组来完成这系列的需求。当然——未来的IM软件，我们的期许绝对不是仅仅1000W用户这个级别了，至少要包含国内的上亿人，加上国际的上亿人。每个IM的有效注册用户规模可能达到数亿这种恐怖规模。加上嵌入化的发展，在线时间也会越来越长。因此服务器的规模也会随之上升，进而造成IM收费时代的到来。&lt;br&gt;    如果要IM持续免费，则我们就必定要发展分布式IM。简单来说，用户登录，持续心跳等等都不以服务器为中心，而以分布网络为中心。服务器只辅之以用户入口和统一的模糊查询的功能。这样会大大减轻服务器的负担，但是也会带来几个问题。&lt;br&gt;    首先是用户的注册，没有用户数据库了。不过不难解决，可以让用户不需要注册。因为没有一个统一的服务器，因此用户注册只需要生成一个UUID，生成一对公私密钥，就算完成了。登录的时候即是告知别人自己的UUID，公钥和套接字即可。需要寻找一个好友的时候，可以使用UUID查询此人的套接字，具体方法请看DHT，Kademila，我上面有写的。&lt;br&gt;    其次是大规模块内容的传输，简单来说其实就是传文件。这些数据如果可以直接传输则没有问题，但是在无根分布系统中，间接数据传输是要过中间机的。这样会造成中间机的网络开销。这个还要看人家乐意不乐意呢。这个没有什么好的解决方法。&lt;br&gt;    最后则是安全问题。这倒不难解决，发送内容用私钥和对方公钥各加密一遍，接受用对方公钥和私钥解密就好了。第一次发送一个统一加密块，后面就用这个块加密，定时更换。兼顾了安全和效率。&lt;br&gt;    IM的另外一个特点就是嵌入化，简单来说就是移植向手机上。中国的移动运营是特殊状态，不过世界的发展大致都是一样的。就是将手机发展为网络终端，然后尽量用软件解决问题。那么中国移动现在的短信优势还能持续多久就是一个非常大的问题了。当然不排除短信优势消灭前飞信拥有了新的特性的可能。
&lt;div&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+IM%e4%b9%8b%e4%ba%89&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1689.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1689.entry</guid><pubDate>Sat, 01 Dec 2007 14:56:53 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1689/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1689.entry#comment</wfw:comment><dcterms:modified>2007-12-01T14:58:06Z</dcterms:modified></item><item><title>网络银行安全性的理论分析</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1687.entry</link><description>&lt;div&gt;    最近好像用网银的人比较多阿，贝壳就做件好事，简单介绍下密码学体系。让大家了解下网银安全性的方方面面。&lt;br&gt;    我们说，银行系统的安全性和易用性往往是一个磁石的南北极，不大可能出现在一个地方的。从易用性角度来说，输入用户名和取款密码直接操作的网银是最方便的。可惜，你的钱被偷的概率也是最高的。因为你和银行间的通讯过程需要流经无数节点，任何一个地方都可以轻易拿到你的登录密码。那么重复这个过程就可以登录并且操作你的钱。所以，任何一家银行都不会提供直接的登录手段。&lt;br&gt;    一般来说，银行在设计网银的时候，往往会提防以下的攻击手段。社会工程学，嗅探，重复发送，钓鱼，中间人钓鱼，猜解，内部盗窃。我们先来大致了解下这些攻击手段的方法和实施条件，然后再说银行的对应手段。&lt;br&gt;    社会工程学攻击是成功率最高的，技术要求最低的攻击。其要决就是一个字，“骗”！社会工程学攻击主体上就是各种骗术，例如把机器塞上，旁边写一个处理电话。等你打电话的时候，就过来一个“工作人员”。然后弄出你的卡来，说要验明你是否是卡主，问你密码。等确认好了身份，你拿到的就不是自己的卡了，那个工作人员也就拿了钱跑了。诸如此类的攻击核心要点就是骗取客户信任。所以社会工程学的对应手段只有让客户提高警惕，其他没别的好办法。&lt;br&gt;    嗅探指的是从登录的机器上或者附近符合一定条件的机器上(具体是哪些需要一定的专业知识)，窃取登录过程数据，并且从中还原出用户密码的手段。这种攻击往往和重复发送一起使用。无法还原密码的情况下，将原先登录的包重新发送一次。对应嗅探攻击的方法很简单，就是挑战-回应方法(Challenge-Responses)。现代加密算法有专门对应已知明文攻击的，用于对抗已经知道明文和密文情况下反解密码。服务器发送一个随机数过来，客户端加密后发送回去。服务器端核验客户端的加密结果和服务器端的加密结果，就知道客户端是否通过认证了。而嗅探者需要相当数目的明密文对才能知道密码。所以相对安全程度更高。&lt;br&gt;    钓鱼是一种社会工程攻击。一般是通过邮件或者其他手段引导你到某个网站上，看上去和网银很像。等你登录想用的时候，会发现上面说网银现在正在调整。如果当时没有在意，等下次登录的时候帐户里面的钱就没了。由于窃取的是密码本身，所以挑战-回应方法无法解决这个问题。这种情况下就必须使用挑战-回应方法的变形，例如零知识验证。大致上看起来就是这样的，银行给你本很长的书，里面写什么你也不知道。然后银行问你，第512页三行15个字是啥？钓鱼收集到这个知识就没用了。但是中间人攻击还是有效的。中间人和钓鱼看起来很像，只是中间人不是窃取密码，而是窃取会话。当你以为登录到银行的时候，其实是登录到了一个中间服务器。一切你的操作其实是通过中间服务器代理上去的。当你退出的时候，中间服务器就会替换你的操作，实施一次转帐和退出。要屏蔽中间人攻击，就必须使用签名证书系统来认证服务器地址。&lt;br&gt;    猜解和内部盗窃是通过对主人情况的了解来猜测或者偷窃密码/密码设备的攻击。目前没有啥好办法，只有想点自己都想不到的东西作为密码才行。生日，电话，车牌，名字，都不可以直接作为密码。当然，做一些基础变形后作为弱密码还是可以的。例如将生日倒过来作为查询密码。&lt;br&gt;    目前网银的认证系统有以下几种，密码直接验证，文件证书验证，密码卡认证，手机动态认证，硬件设备认证。&lt;br&gt;    密码直接认证一般使用了SSL技术来防止嗅探，但是对于钓鱼，中间人，猜解，内部盗窃都没有防护能力。一般都是各个网银的最差防护状态，为某些对安全不在意的人设计的。只是使用方便而已。&lt;br&gt;    文件证书验证是利用密码和文件数字证书来验证身份的方法，对于钓鱼，中间人有比较好的防护手段。可以防止猜解，但是无法防止内部盗窃。因为文件证书为了方便起见都是存放在电脑内部的，所以文件证书的安全就又成了问题。即使是存放在U盘上，也会在使用的瞬间被复制。电脑中木马，文件或者U盘被盗拷，都是产生不安全的原因。&lt;br&gt;    密码卡是某种零知识验证的变形。差不多就是给你张密码卡，刮一次能上一次。对于钓鱼有一定防护能力，但是对于中间人攻击无能为力。可以防止猜解，但是无法防止内部盗窃。&lt;br&gt;    手机动态认证是通过手机收取临时动态验证码来确认客户的身份。如果要窃取客户的身份，就必须同时得到用户手机卡和用户密码。所以，也是防嗅探，钓鱼，猜解，但是不防中间人和内部盗窃。注意这里有种特殊形式，大家也许不知道，手机发送的短信是可以被特殊设备截获破解的——&lt;br&gt;    硬件设备认证则是将密钥和计算放入了特殊硬件内。银行发送挑战数到硬件上，硬件设备返回数据到银行。如果要窃取身份，就必须获得设备和密码。因此，也是防嗅探，钓鱼，猜解，但是不防中间人和内部盗窃。一般就是指银行的U盾设备，但是要注意区分U盾究竟是用来计算呢，还是用来存放密钥。后者的安全级别和文件证书一致。&lt;br&gt;    我们对比各种攻击之前，先去掉两个特殊选项，社会工程和中间人攻击。社会工程某种意义上是无法防御的，你说你要把东西交给别人，银行怎么防范？拿你的生物特征？那就太麻烦了。中间人则是因为可以用CA证书验证地址有效性，因此现在很少成功。当然，也有先欺骗DNS服务器的。碰上这种蓄意的中间人攻击，差不多就和碰上人强奸一样——反抗是没意义的。这两种方法，只要是有心算无心，基本都可以成功。因此我们先去掉这两个成功么未必成功，防范么没法防范的选项。&lt;br&gt;    SSL技术是网银登录的基础技术，没有的话请记得早日离开这家银行。文件证书使用方便，但是电脑一旦中木马就立刻危险。密码卡看似安全，其实对于精心设计的钓鱼还是没用的。而且使用麻烦，不如趁早不用。手机动态验证的安全性是非常高啦，可是要记得手机的安全就是帐户的安全。所以手机卡千万看住，别被人复制了。(手机卡是可以复制的，然后就可以用这个号码打电话了。当然这种事情发生概率很小，一般倒是用在一卡多号上比较多)还有手机信号问题，找个深山老林上网吧。&lt;br&gt;    硬件设备认证是比较硬的方法，一般是比较完美的。可惜价格太贵。&lt;br&gt;    综合下来，偷懒的可以用手机。怕事的还是用硬件。&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e7%bd%91%e7%bb%9c%e9%93%b6%e8%a1%8c%e5%ae%89%e5%85%a8%e6%80%a7%e7%9a%84%e7%90%86%e8%ae%ba%e5%88%86%e6%9e%90&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1687.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1687.entry</guid><pubDate>Wed, 28 Nov 2007 07:55:11 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1687/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1687.entry#comment</wfw:comment><dcterms:modified>2007-11-28T07:55:11Z</dcterms:modified></item><item><title>Google Calender</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1685.entry</link><description>    Google有很多产品，Google Calender就是其中之一，这个东西主要的目的就是管理日历。&lt;br&gt;    其实从常规角度考虑，这是最不适合bs的产品。日历的要点就是随身，谁会高兴为了看个日历找宽带上网阿。可不能不感慨Google的水平，凭着各种技术的支持，这么一个产品居然还真让我觉得好用。&lt;br&gt;    Google Calender的两个核心思想就是同步和共享，同步用的是iCalender标准，共享也很类似。Google Calender的管理中，允许在多种客户端内同步Google Calender的日程。这样Google Calender就从一个不适合的产品一下变成了多个日程工具的平台标准。贝壳现在是利用他同步多个机器上的多个软件，主要的产品包括Sunbird/Lighting，raincalender，部分的手机日历，相信很多人也会做这个应用。贝壳用的就是其中的Sunbird，这个软件是Mozilla的产品之一。(贝壳现在是Mozilla的忠实用户，FireFox，Thunderbird，Sunbird三件套常备，都做了跨系统共享)不加载&lt;a href="https://addons.mozilla.org/zh-TW/sunbird/addon/4631"&gt;Provider for Google Calendar&lt;/a&gt;的情况下，可以读取iCalender格式的远程日历。加载插件后会多出一个Google日历的选项，用Google中的个人xml链接，保存入个人的用户名和密码(个人的gmail，带域名)，然后就可以双向同步gcal了。&lt;br&gt;    至于共享，在管理的时候应该可以看到和谁共享。做项目的时候，拉组员进来共享。或者没有gmail的可以用全可见加给html链接的方式。这样就可以给组员看他们的工作状态，别人的工作状态，将来的项目安排。如果组员可信任，可以给予写权限。这样他们会自动更新进度，可谓超级省事。&lt;br&gt;    最后，Google Calender可以被结合入iGoogle里面，成为标准平台的一部分。
&lt;div&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+Google+Calender&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1685.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1685.entry</guid><pubDate>Mon, 26 Nov 2007 01:49:12 GMT</pubDate><slash:comments>2</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1685/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1685.entry#comment</wfw:comment><dcterms:modified>2007-11-26T01:49:12Z</dcterms:modified></item><item><title>英雄传说6空之轨迹SC修改</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1667.entry</link><description>    以下是空之轨迹SC的存档修改方法和部分物品代码表，六牙四皂小姐可以跳过了。&lt;br&gt;晶片数目：&lt;br&gt;0x2534C 金钱&lt;br&gt;0x25354 地&lt;br&gt;0x25358 水&lt;br&gt;0x2535C 火&lt;br&gt;0x25360 风&lt;br&gt;0x25364 行动&lt;br&gt;0x25368 EP&lt;br&gt;0x2536C 时间&lt;br&gt;个人经验：&lt;br&gt;0x1F460 艾丝蒂尔经验&lt;br&gt;0x1F514 奥利维尔经验&lt;br&gt;0x1F550 科络丝经验&lt;br&gt;0x1F604 金经验&lt;br&gt;物品代码：&lt;br&gt;01c9 最终浓缩药草茶&lt;br&gt;01c8 大麦奶酪果冻&lt;br&gt;01c7 苦味兽肉焖&lt;br&gt;01C6 每日天妇罗&lt;br&gt;01AE 提神果冻&lt;br&gt;01C4 营养果汁&lt;br&gt;019F 清凉药草茶&lt;br&gt;01B9 内陆佳肴&lt;br&gt;01BD 卡布其诺薄饼&lt;br&gt;0195 千层薄饼&lt;br&gt;01a0 红莲炖兽肉&lt;br&gt;01a6 春风螺狮面&lt;br&gt;01ba 阳光冰淇凌&lt;br&gt;01bb 月光冰淇凌&lt;br&gt;01A1 不可思议的糊&lt;br&gt;01AF 激情蛋卷&lt;br&gt;01be 终极冰淇凌&lt;br&gt;01b0 海味鲜珍&lt;br&gt;000f 火绒草杖&lt;br&gt;0014 蓝璃&lt;br&gt;001b 麒麟&lt;br&gt;002e 漆黑之刃&lt;br&gt;0031 凤凰剑&lt;br&gt;004b 积木鞭&lt;br&gt;006a 独眼巨人&lt;br&gt;0087 天琴&lt;br&gt;0105 树脂装甲&lt;br&gt;0108 大地女神之服&lt;br&gt;010E 古代神铠&lt;br&gt;0171 女战士机甲&lt;br&gt;0172 炮术师战甲&lt;br&gt;0129 普罗米修斯神靴&lt;br&gt;0139 神圣挂链&lt;br&gt;0140 土人偶&lt;br&gt;    物品这里只有贝壳测试出来的部分，不过理论上也很强了。&lt;br&gt;    下面说明怎么使用上面的数据。&lt;br&gt;    首先，用16进制编辑器打开存档，推荐用HEdit。存档在save下面，按照次序存储的SVDAT???.SAV文件。&lt;br&gt;    晶片的话，跳到这个偏移位置，直接修改就行了。注意NUXI问题，高低字节是颠倒的。例如9999就写入0F27。&lt;br&gt;    经验的话基本是没用的，因为升级时候的算法很有意思。如果当前经验小于下一级别经验，加了获得经验后大于下一级别经验，则完成升级步骤。否则光写到了多少级别，不调整当前的级别和参数。因此经验改高后，反而会造成无法升级的问题。除非你修改到当前级别的最高经验，然后K一次怪升级，再重复……&lt;br&gt;    物品的话是这样存储的，XX XX NN NN。四字节一组，前两个是物品代码，后两个是物品数量。注意都是高低位反过来的WORD型数据。上面给出的代码也全是反过来的，使用的时候注意颠倒(贝壳颠倒成习惯了……)。&lt;br&gt;    例如我们要把火绒草杖变成神圣挂链x99(最强的辅助物品，除了战斗不能的一切异常免疫)。那么请先首先确定你当前火绒草杖的数目。用别的物品的话需要预先知道物品代码，或者你自己搞出物品代码表来。然后推算一下，数据应当被存储为0F 00 01 00。(假定你就一个)打开存档，查找这个数据，然后修改为39 01 63 00，存盘结束。&lt;br&gt;    基本这些就够用了把……&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e8%8b%b1%e9%9b%84%e4%bc%a0%e8%af%b46%e7%a9%ba%e4%b9%8b%e8%bd%a8%e8%bf%b9SC%e4%bf%ae%e6%94%b9&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1667.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1667.entry</guid><pubDate>Tue, 09 Oct 2007 14:01:26 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1667/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1667.entry#comment</wfw:comment><dcterms:modified>2007-10-09T14:02:01Z</dcterms:modified></item><item><title>libxml2入门和中文支持</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1663.entry</link><description>    libxml2是gnome做的一个xml的库，支持SAX和DOM。&lt;br&gt;    在解析xml的时候，libxml2会将xml中不属于标签的部分作为text节点插入。如果是属性，则添加一个属性节点到父节点上，一个文字节点到属性节点下。那么整个xml就变成了一颗单纯的树。&lt;br&gt;    支持多语言的问题上，libxml2的内核只支持UTF-8。但是可以通过注册编码句柄来添加语言支持，一般是配合iconv[2]使用的，因为libxml2的编译依赖就是iconv。下面是代码。&lt;br&gt;&lt;br&gt;iconv_t         iconv_utf8_gbk;&lt;br&gt;iconv_t         iconv_gbk_utf8;&lt;br&gt;&lt;br&gt;int gbk_input (unsigned char *out, int *outlen, const unsigned char *in,&lt;br&gt;               int *inlen)&lt;br&gt;{&lt;br&gt;    char           *outbuf = (char *) out;&lt;br&gt;    char           *inbuf = (char *) in;&lt;br&gt;    size_t          rslt;&lt;br&gt;    rslt =&lt;br&gt;        iconv (iconv_utf8_gbk, (const char **) &amp;amp;inbuf, (size_t *) inlen,&lt;br&gt;               &amp;amp;outbuf, (size_t *) outlen);&lt;br&gt;    if (rslt &amp;lt; 0)&lt;br&gt;        return rslt;&lt;br&gt;    *outlen = ((unsigned char *) outbuf - out);&lt;br&gt;    *inlen = ((unsigned char *) inbuf - in);&lt;br&gt;    return *outlen;&lt;br&gt;}&lt;br&gt;&lt;br&gt;int gbk_output (unsigned char *out,&lt;br&gt;                int *outlen, const unsigned char *in, int *inlen)&lt;br&gt;{&lt;br&gt;    char           *outbuf = (char *) out;&lt;br&gt;    char           *inbuf = (char *) in;&lt;br&gt;    size_t          rslt;&lt;br&gt;    rslt =&lt;br&gt;        iconv (iconv_gbk_utf8, (const char **) &amp;amp;inbuf, (size_t *) inlen,&lt;br&gt;               &amp;amp;outbuf, (size_t *) outlen);&lt;br&gt;    if (rslt &amp;lt; 0)&lt;br&gt;        return rslt;&lt;br&gt;    *outlen = ((unsigned char *) outbuf - out);&lt;br&gt;    *inlen = ((unsigned char *) inbuf - in);&lt;br&gt;    return *outlen;&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;static void print_element_names (xmlDocPtr doc, xmlNode * a_node, int n)&lt;br&gt;{&lt;br&gt;    xmlNode        *cur_node = NULL;&lt;br&gt;    xmlAttr           *cur_attr = NULL;&lt;br&gt;    xmlChar *key;&lt;br&gt;&lt;br&gt;    for (cur_node = a_node; cur_node; cur_node = cur_node-&amp;gt;next) {&lt;br&gt;            for (int i = 0; i &amp;lt; n; ++i)&lt;br&gt;                printf (&amp;quot; &amp;quot;);&lt;br&gt;//            key = xmlNodeListGetString(doc, cur_node-&amp;gt;xmlChildrenNode, 1);&lt;br&gt;            printf (&amp;quot;node %d: %s = %s\n&amp;quot;, cur_node-&amp;gt;type, cur_node-&amp;gt;name, cur_node-&amp;gt;content);&lt;br&gt;            if (cur_node-&amp;gt;properties != NULL){&lt;br&gt;                for (cur_attr = cur_node-&amp;gt;properties; cur_attr; cur_attr = cur_attr-&amp;gt;next){&lt;br&gt;                    printf (&amp;quot;attr %s = %s\n&amp;quot;, cur_attr-&amp;gt;name, cur_attr-&amp;gt;children-&amp;gt;content);&lt;br&gt;                }&lt;br&gt;            }&lt;br&gt;//            xmlFree(key);&lt;br&gt;&lt;br&gt;        if (cur_node-&amp;gt;type == XML_ELEMENT_NODE)&lt;br&gt;            print_element_names (doc, cur_node-&amp;gt;children, n + 1);&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;int _tmain (int argc, _TCHAR * argv[])&lt;br&gt;{&lt;br&gt;    xmlDoc         *doc = NULL;&lt;br&gt;    xmlNode        *root_element = NULL;&lt;br&gt;    LIBXML_TEST_VERSION;&lt;br&gt;    iconv_utf8_gbk = iconv_open (&amp;quot;utf-8&amp;quot;, &amp;quot;gbk&amp;quot;);&lt;br&gt;    iconv_gbk_utf8 = iconv_open (&amp;quot;gbk&amp;quot;, &amp;quot;utf-8&amp;quot;);&lt;br&gt;&lt;br&gt;    xmlNewCharEncodingHandler (&amp;quot;gb2312&amp;quot;, gbk_input, gbk_output);//添加gb2312编码支持&lt;br&gt;    xmlNewCharEncodingHandler (&amp;quot;gbk&amp;quot;, gbk_input, gbk_output);//添加gbk编码支持&lt;br&gt;&lt;br&gt;    doc = xmlReadFile (&amp;quot;Q.xml&amp;quot;, NULL, 0);&lt;br&gt;    if (doc == NULL) {&lt;br&gt;        printf (&amp;quot;Failed to parse %s\n&amp;quot;, &amp;quot;Q.xml&amp;quot;);&lt;br&gt;        return 0;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    root_element = xmlDocGetRootElement (doc);&lt;br&gt;    print_element_names (doc, root_element, 0);&lt;br&gt;    xmlFreeDoc (doc);&lt;br&gt;&lt;br&gt;    xmlCleanupParser ();&lt;br&gt;    xmlMemoryDump ();&lt;br&gt;    iconv_close (iconv_gbk_utf8);&lt;br&gt;    iconv_close (iconv_utf8_gbk);&lt;br&gt;    return 0;&lt;br&gt;}&lt;br&gt;&lt;br&gt;    在XML无指定编码的时候没有测试过，不过按照XML标准，这时候应该是UTF-8编码。不符合标准的话……自己想办法吧。&lt;br&gt;&lt;br&gt;Reference:&lt;br&gt;1. The XML C parser and toolkit of Gnome: http://xmlsoft.org/&lt;br&gt;2. libiconv: http://www.gnu.org/savannah-checkouts/gnu/libiconv/&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+libxml2%e5%85%a5%e9%97%a8%e5%92%8c%e4%b8%ad%e6%96%87%e6%94%af%e6%8c%81&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1663.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1663.entry</guid><pubDate>Fri, 28 Sep 2007 06:43:40 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1663/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1663.entry#comment</wfw:comment><dcterms:modified>2007-09-28T06:43:40Z</dcterms:modified></item><item><title>wget介绍</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1658.entry</link><description>    从今天开始，贝壳每周介绍一些小软件，作为基础的电脑知识普及。软件可能是Windows的，也可能是Linux的，要点是轻巧好用。由于是简介，不会写的太详细。想要看专业介绍的，会给出Reference。&lt;br&gt;    今天介绍的软件就是wget[1]。这个是*nix下的下载软件，也有windows移植[2]。现在可以运行在任何一种POSIX系统上。软件是GPL版权的，属于GNU开源组织的核心代码，也是GNU组织的几大招牌之一(最出名的是GCC)。如果要看详细的资料，请看这里[3]，可惜是英文的。&lt;br&gt;    wget是*nix时代出名的下载软件，以稳定和通用出名。主要针对http和ftp协议的文件下载，拥有很多配置选项和能力。其中比较有名的是链接跟随，这种能力可以跟踪html内的链接。例如将所有链接所需的文件下载到本地，并且修改链接地址，即抓取完整页面文件。跟随链接抓取多重页面(网络蜘蛛)。&lt;br&gt;    wget不支持多线程下载，但是支持断点续传。最常用的用法是wget -c [URL]。如果没有文件就直接下载，有文件就尝试续传。如果没有文件重试次数的指定，几乎就是无限制的下载。下载非常稳定，就算每小时下载10字节都不会断线。&lt;br&gt;    和今天的GUI多线程，甚至带P2P的下载软件相比，wget无疑是非常单薄的。然而由于是基于命令行的，而且非常稳定，因此经常被用于脚本语言中。例如bash或者python，用于下载网络文件后的处理。windows中的很多脚本也可以用这个软件来下载网络文件，非常方便。&lt;br&gt;Reference:&lt;br&gt;1. GNU Wget: http://www.gnu.org/software/wget/&lt;br&gt;2. Wget for Windows: http://gnuwin32.sourceforge.net/packages/wget.htm&lt;br&gt;3. GNU Wget Manual: http://www.gnu.org/software/wget/manual&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+wget%e4%bb%8b%e7%bb%8d&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1658.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1658.entry</guid><pubDate>Tue, 25 Sep 2007 01:53:48 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1658/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1658.entry#comment</wfw:comment><dcterms:modified>2007-09-25T01:53:48Z</dcterms:modified></item><item><title>散热器的种类，测量和挑选</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1636.entry</link><description>    上篇文章中贝壳提到了散热垫。非常不幸的，经过贝壳的实际测量，贝壳所购买的散热垫基本没有任何效果。为了让大家对散热产品有个了解，贝壳就大致介绍一下散热器的分类和作用。还有一些常用术语，常见参数和解释。&lt;br&gt;    首先一类是散热垫，这是最常见的产品。优势在于可以非常快的散去表面温度，手感非常明显。缺点在于不方便携带。主要分为吹风式，抽风式和双向循环三种工作方式。同时可以按照表面材质分为非金属，铁，铝合金三种，按照供电方式分为外接，USB, USB HUB三种。&lt;br&gt;    吹风式的主要特点是从后部或者其他部位吸收空气，向底部吹风。吸风式则相反。双向循环两者都有。一般笔记本如果带风扇，都是从下面吸收空气向外排出(大多数是左上或者后面，因为没有鼠标干涉)。这时候如果采用吸风式，则会产生干涉，导致效果不明显。贝壳的头个散热垫就是这个问题。但是一般吸风式的散热效果比较明显。热量不必经过复杂的通道流转，因此对于表面温度的抑制非常明显。建议如果是带风扇的本本，按照风扇方向选择，没有风扇就用吸风式的。双向循环是最好的一种，可惜比较贵。&lt;br&gt;    表面材质是关于被动散热问题的关键，如果本本底部是平的(没有垫脚垫高)。金属材质的表面会有很明显的散热作用，尤其以铝合金的为最(BTW，其实纯铜的导热最好，可惜价格贵，容易腐蚀，所以没听说谁用)。但是如果底部被垫高了(多数主动风扇散热的本本都要垫高的)，那么效果就大打折扣。建议如果本本是小型式的，平底无风扇的，千万记得选购一个铝合金的吸风散热垫。&lt;br&gt;    外接的供电最充足，功率相对大。可惜需要额外的电源，而且噪音大，因此相对少见。一般只有在特别固定的场所，例如家中，才会固定放置一个。否则带散热垫还带一个电源和插座，谁也受不了的。USB是最常见的形式，需要用本本的一级供电口。一般取用电流都在200mA上下，功率大约1W上下，因此无源hub口是用不上的。但是大家知道，小型本本一般usb只有两个，分一个出来专门供电怎么行？因此好的散热器是usb hub的，正如上篇文章所说，取电的同时还能输出至少两个usb接口(严格是四个，不过限于功率问题，大家应该知道是无法同时接上的)。&lt;br&gt;    再下来就是主动抽取式的外挂风扇。现在我只看到EVERCOOL有一款。也是唯一用下来对我有价值的一款。上文说了，散热垫的主要作用是整体散热。对于主板过热和硬盘过热都有很好的抑制作用。不过什么时候这两者过热呢？一般空气温度都要超过30度了，这两者才会过热，多数环境下是比较少见的。而CPU的温度则不是特别受散热垫的影响。一般CPU的散热过程都是从CPU上直接接一个热管到散热器上，将CPU的热能通过热管传输。如果热量很大，热管传输不足的话，就会造成结构性的热能堆积。这是散热设备无能为力的。而有的时候是热管传输出去的热能堆积在散热器上，导致热管效率下降(热管的工作效率取决于两端温度差，这根本是牛顿散热定律)。这时候可以给散热器强制排风增强散热，这就需要主动抽取式风扇了。按照以上所述，主动抽取风扇最擅长的是给CPU降温。缺点是价格高，使用范围有限，对主板和硬盘无效。顺便说一下，贝壳的主动风扇使用后，温度下降5度，是唯一能看出明显差距的散热器。&lt;br&gt;    下面就是非本本的散热器了，首先是我们最熟悉的CPU风扇，主要用途就是给CPU散热。大家别小看这风扇，弄个不好上百的CPU就会毁在一个几块的风扇上。CPU风扇和散热器合起来叫做CPU散热设备，按照散热器材质分为铝合金，纯铜两种，按照散热器造型分为方阵和鳍片两种。鳍片就是大家在显卡上经常看到的从中心向外辐射的散热片，一般Intel的原状散热器这样居多。&lt;br&gt;    CPU有几个参数，首先是最重要的，转数。越快越好。这决定了CPU本质的散热能力。其次，口径。这东西是匹配CPU的，小口不用大风扇，大口不用小风扇，不用贝壳废话。然后是CFM，这是排风量，可以根据口径，叶片角度，转速来计算。最后也是最重要的，轴承。决定了风扇的寿命和噪音。转速的一般性指标是1000－10000转，视具体产品而定。一般的机箱散热器都是1000多转的大口径风扇，排风量大，散热也很快。只是风无法聚集吹送，用来给CPU散热就废物了。CPU风扇最小是3000转起，高的有7000多转的。CFM小的只有10上下，大的有60多的，一般都在30上下。一般风扇都是滚珠轴承的，高档的才用液压轴承。&lt;br&gt;    除了风冷外还有一类，水冷介质。如果您不是超级超频DIYer，这节对您没用。如果是，您还来看我的文？所以跳过。同理，液氮冷也跳过。我们说说半导体冷却。&lt;br&gt;    半导体是贝壳觉得最有实用价值的一类冷却设备。不便宜，可效果好。一块CPU同等大小的半导体制冷片所最需要关心的问题是凝露而不是过热。就是说，CPU同大小的制冷片足够把热量降到0度以下。唯一遗憾的是所需的功率也很惊人，大约在30-300W，足足半台电脑的功率。贝壳在考虑是否将来的本本会加很小一块在热管和散热器之间，然后将热管扩展到整个本本(其实不用这么夸张，大多数的纯铜散热片，中间热管穿以下就够了)。热管的工作足够将整个本本的所有热量导入到高热的散热器上，然后排出。只是这功率的问题——&lt;br&gt;    另外说以下贝壳积累下的经验数据，经验而已，大家指正。下面的室温都是25度上下。&lt;br&gt;    硬盘，Hitachi的。经常性非工作温度为38度上下，全力工作温度为44度上下。根据贝壳经验，建议温度不要超过45度(台式硬盘在这个温度挺了几年没事)。按照这个计算，机器大规模使用硬盘的环境最高温度为25度。&lt;br&gt;    CPU，AMD Turion64 MK-36。经常性非工作温度为45度上下，全力工作温度为65度上下。根据贝壳读到的数据，建议不要超过70度。加装散热器后温度低了5度。按照这个计算，机器大规模使用CPU的环境最高温度为35度以下。&lt;br&gt;    手感温度，按照室温25度衡量，无热感为20-30度，30度以上有热感，40度以上温暖，50度以上开始烫手，60度差不多就无法留手了。&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+%e6%95%a3%e7%83%ad%e5%99%a8%e7%9a%84%e7%a7%8d%e7%b1%bb%ef%bc%8c%e6%b5%8b%e9%87%8f%e5%92%8c%e6%8c%91%e9%80%89&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1636.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1636.entry</guid><pubDate>Mon, 27 Aug 2007 13:36:17 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1636/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1636.entry#comment</wfw:comment><dcterms:modified>2007-08-27T13:36:17Z</dcterms:modified></item><item><title>Linux下设备可靠性控制</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1634.entry</link><description>    上篇文章中提到了一个问题，CPU温度。关于这个问题，就涉及了另外一个问题。Linux下如何获得设备可靠性参数，例如电压，功率，温度，风扇转速，SMART等等。至于获得后要如何做的问题，这还轮不到我关心，相信大家都会使用各种用法。&lt;br&gt;    首先是最主要的组件，lm-sensors包。安装后有一个叫做sensors-detect的程序，运行一下。这个程序会检测你有什么性能控制设备，并且提示你加载相应的驱动模块。在完成加载后(不加载驱动的话就无法查看)，使用sensors查看各个传感器的各个数据。通常有CPU温度和电压等等。贝壳使用的是xfce4，因此还需要一个xfce4-sensors-plugin包。安装后可以在控制面板中添加一个applet，用于检查当前温度。&lt;br&gt;    而后，是硬盘的温度。贝壳不知道是否所有的硬盘都支持温度控制，不过目前本本上的这个Hitachi HTS541612J9SA00支持硬盘温度测量。贝壳实验过，真的会变化。安装hddtemp包，而后以root身份运行hddtemp就可以了。如果要获得干净的文本，可以使用hddtemp [dev] | cut -d: -f3来取得。唯一可惜的就是这个程序必须以root运行，因而无法运用在applet上进行即时检测。&lt;br&gt;    最后，是SMART信息。包是smartmontools，可以检测硬盘的SMART状态。&lt;br&gt;    基本就上面这些了。&lt;br&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=8850414288015442459&amp;page=RSS%3a+Linux%e4%b8%8b%e8%ae%be%e5%a4%87%e5%8f%af%e9%9d%a0%e6%80%a7%e6%8e%a7%e5%88%b6&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=shell909090.spaces.live.com&amp;amp;GT1=shell909090"&gt;</description><comments>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1634.entry#comment</comments><guid isPermaLink="true">http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1634.entry</guid><pubDate>Thu, 16 Aug 2007 03:27:04 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://shell909090.spaces.live.com/blog/cns!7AD2FCE74833C21B!1634/comments/feed.rss</wfw:commentRss><wfw:comment>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1634.entry#comment</wfw:comment><dcterms:modified>2007-08-27T13:30:22Z</dcterms:modified></item><item><title>散热器和扩展坞</title><link>http://shell909090.spaces.live.com/Blog/cns!7AD2FCE74833C21B!1627.entry</link><description>    贝壳的本本烧了一次，大家都知道吧？痛定思痛，贝壳认为，这是给热的——&lt;br&gt;    于是贝壳上网查了下本本的散热状况。不查不知道，一查吓一跳。贝壳本本的出口温度体感大约是40度，内部温度至少是50度。长期这样工作，难怪会烧。最简单的解决方案是垫高本本底部。垫高一厘米后，下层手感倒是没了，但是出口温度基本没有变化。看来需要更强劲的解决方案。&lt;br&gt;    贝壳去中关村淘了一个本本用的散热器，带一个usb hub，85块，便宜的也有70多的。垫在本本下面非常稳当，电源使用usb端口取电，不用变压器，直接用线接在本本上就好。usb的标准电压是5V，初级端口的最高电流是500mA，小型设备的最高电流是100mA，因此一个无源hub可以扩展4个小型设备。这个散热器的功率是0.9W，电流消耗小于180mA，加上一定的hub芯片和中途损耗，还可以在hub端口上连接两个小功率设备。悬点能连接三个，不过总电流就达到了纯480mA以上，稳定性就要掂量着点了。反正加一个鼠标一个U盘还是没啥问题的。三个风扇全开后，出口温度在平时没有升温的感觉，大约是20-30度上下，全功率工作的时候才有温感，大约是30-40度。内部温度不会超过40度。硬盘温度降低到不明显，因为风扇没有正对硬盘，而是对上了硬盘的进风口。硬盘又没有辅助散热片，所以温度自然无法明显降低，大约目前是40度上下吧。&lt;br&gt;    由这个散热产品，贝壳想到了本本的两重化问题。一个是要求小型化便携化，要求可以发挥本本的长处，到处带了跑。一个是要求全面化，要求能够替代台式机，能够个自行更改升级。这是两个违背的要求，一个要求设备少设计紧密，一个要求设备多设计松散。就拿光驱来说吧，带了个光驱到处跑，怎么做到小型化？但是不带光驱，怎么和主机比？打个游戏放个电影都是问题。&lt;br&gt;    解决这个问题的曙光是扩展坞，很多超小型化设计的本本，为了追求超小超薄，经常就牺牲了很多周边设备，包括最关键的usb端口数目。一般小型本本上都只有两个，一个插一个鼠标，这必定要用的吧。另外一个呢？移动硬盘？摄像头？打架了吧？所以很多商家就增加了扩展坞，