??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久久夜精品精品免费啦,国产精品免费福利久久,精品久久久久久国产http://www.shnenglu.com/eXile/archive/2010/01/11/105422.htmleXileeXileMon, 11 Jan 2010 11:48:00 GMThttp://www.shnenglu.com/eXile/archive/2010/01/11/105422.htmlhttp://www.shnenglu.com/eXile/comments/105422.htmlhttp://www.shnenglu.com/eXile/archive/2010/01/11/105422.html#Feedback39http://www.shnenglu.com/eXile/comments/commentRss/105422.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/105422.html     1.什么是Go语言

    Go语言是Google推出的新的一个致力于pȝU的~程语言。很多h说它?C + PythonQ既有c的灵z高效,又有Python的简单易用,它的原则?Simple && Fast。它的语法规则很单。其官方|站上有一个《三天学会Go语言》的教程Q包括三部分Q基本结构,面向对象Qƈ发。一个周末的旉差不多可以掌握其基本面貌。相Ҏ_W三部分“q发”g难接受一些。但是如果你对多U程Q同步,消息队列q些东西很有l验的话Q对它的概念也会Ҏ理解?br>
     2.Go语言的面向对?/span>

     Go语言在C语言语法的基上,以最z的形式加入了面向对象?br>    关于l承QGo语言没有l承。但是它支持嵌入Q这个有点类g其它语言的mixinQ可以用来模拟ѝ?br>    关于多态:Go 语言的最大特Ҏ它的接口定义。所?#8220;接口”Q就是一l方法的集合。Q何一个类只要实现了一个接口的所有方法,则是该接口的实现者,不需要显式声明实现该接口。所以一个没有Q何方法的I接口可以代表Q何类型?br style="FONT-WEIGHT: bold">   
     3.Go语言的ƈ?/span>

     Go语言提出一个新的概念—Go例程Q有点类gU程Q但是更加轻量,更省资源。Go例程之间的通信方式 ——信道,q是GO 语言的核心概念,有点cM于UNIX的Pipe。在Go语言中,不需要接触线E,锁这些低阶概c?br>
     4.Go语言可以用来做什?/span>

     Go语言目前最强的是它的网l功能。它的package中已l实C最常见的网l协议和~码处理。Go的官方网站用的是Go语言Q实际上它就是Go的文档系lgodoc?br>      q没有官方对数据库支持,不过因ؓ通过某种办法可以在Go语言中直接调用C函数Q所以很Ҏ的实现对MYSQL 或?Sqlite q些数据库的支持?br>      至于GUIQ这估计目前q不在设计者的考虑范围之内Q因Z们连Windows都不舍得支持。不q可以通过它的http包和template包等{,已经构成了一个WEB框架Q可以用来实现WEB GUI的开发,使用Go写一个带有\径分zHttp服务器也几行代码的事?br>    




eXile 2010-01-11 19:48 发表评论
]]>
说说C++指针(2): 标准库中的智能指?/title><link>http://www.shnenglu.com/eXile/archive/2009/11/16/101062.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Mon, 16 Nov 2009 05:57:00 GMT</pubDate><guid>http://www.shnenglu.com/eXile/archive/2009/11/16/101062.html</guid><wfw:comment>http://www.shnenglu.com/eXile/comments/101062.html</wfw:comment><comments>http://www.shnenglu.com/eXile/archive/2009/11/16/101062.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/eXile/comments/commentRss/101062.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/eXile/services/trackbacks/101062.html</trackback:ping><description><![CDATA[ <p><span style="FONT-FAMILY: courier new; FONT-SIZE: 12pt">  <span style="FONT-FAMILY: Courier">使用指针是C++中常用的理内存的方式。关于智能指针的设计Q各路C++高手也是各展通?br><br>  ?994q? Greg Colvin向C++标准委员会提Z自己设计的智能指针:auto_ptr和counted_ptr。auto_ptr实现基本的RAII理Q不可复Ӟcounted_ptr采用引用计数实现了一个可复制的智能指针。两者用于不同的场合?br>  但是标准委员会最l只通过了auto_ptrQƈ且对auto_ptr加入了一个古怪的“所有权转移”语义。后来auto_ptr和counted_ptrq入了Boost C++ 库,改名为scoped_ptr和shared_ptr?br>  <br>  std::auto_ptr只所以设计ؓ可拷贝的Q也许是Z以下考虑Q比如下例函敎ͼ</span></span></p> <font size="4"> <div style="border-left-color: rgb(204, 204, 204); padding-bottom: 4px; background-color: rgb(238, 238, 238); padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; padding-top: 4px; "><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> f1(</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> ptr);<br></span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> f2();</span></div> </font><p><font size="4">  </font><span style="FONT-SIZE: 12pt"> f1中的参数所指向的对象应该由谁来删除呢?调用者还是被调用者?如果不看E序文档的话Q无法知道这一炏Vf2函数也存在同L问题?br><br>   用auto_ptr可以消除q种歧义性:</span></p> <font size="4"> <div style="border-left-color: rgb(204, 204, 204); padding-bottom: 4px; background-color: rgb(238, 238, 238); padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; padding-top: 4px; "><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> f1(auto_ptr</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> ptr);<br>auto_ptr</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">object</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> f2();</span></div> </font><p><font size="4">  <br></font>      <span style="FONT-FAMILY: courier new">管如此Qauto_ptr?#8220;所有权转移”语义q是会带来副作用Q因Z修改原值的帔R拯q背了一般的设计原则Q它也许会在你意想不到的情况下就把对象{UM。它也不能用于标准容器中?br>   所以auto_ptr在新的标准库已经不再推荐使用。取而代之的是unique_ptr。unique_ptr与auto_ptrcMQ但限制了auto_ptr的拷贝行为。同Ӟ像上面D的例子一Punique_ptr可以作ؓ函数的参数和q回g用。这是因为C++增加了一个新的特征:叛_引用?br><br>   shared_ptr也进入了标准库。对于引用计数的指针而言Q@环引用是一个大问题。标准库为此把shared_ptr定义为强引用指针Q它q实C一个弱引用指针weak_ptr。显Ӟ标准库ƈ没有从根本上解决循环引用的问题,它把q个问题交给了程序员。在一个简单的pȝ中,你可以区分用shared_ptr和weak_ptrQ以此来避免出现循环引用。但是在一个大的对象系l中Q有时还是容易出错。@环引用的问题Q严重减׃shared_ptr的可用性?br><br>   那么能不能自动检是否出现@环引用呢Q事实上Q对于shared_ptrq种使用非R入式{略实现的智能指针,是很隑֮现自动检的。但是如果采用R入式设计Q我们可以引入一些接口,来解册个问题。@环引用的,实际上是图论中的回\问题?br></span><br>      本文?a style="FONT-SIZE: 12pt" title="eXile" href="http://www.shnenglu.com/eXile/">eXile</a><span style="FONT-SIZE: 12pt"> 原创Q{载请表明原脓地址?nbsp;</span><a href="http://www.shnenglu.com/eXile/">http://www.shnenglu.com/eXile/</a>?/p><img src ="http://www.shnenglu.com/eXile/aggbug/101062.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/eXile/" target="_blank">eXile</a> 2009-11-16 13:57 <a href="http://www.shnenglu.com/eXile/archive/2009/11/16/101062.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>说说C++指针(1): 关于shared_ptrhttp://www.shnenglu.com/eXile/archive/2009/11/02/99995.htmleXileeXileMon, 02 Nov 2009 09:38:00 GMThttp://www.shnenglu.com/eXile/archive/2009/11/02/99995.htmlhttp://www.shnenglu.com/eXile/comments/99995.htmlhttp://www.shnenglu.com/eXile/archive/2009/11/02/99995.html#Feedback2http://www.shnenglu.com/eXile/comments/commentRss/99995.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/99995.html   shared_ptr是新的标准库的一个主要成员,作ؓ一个非嵌入式的指针Q其设计可谓已经是绞脑汁。当Ӟq有很多人对它提Z不满。没有完的设计Q只有合适的设计?br>
1. shared_ptr最大的特点是接口的单性与实现的灵zL?br>    对于shared_ptr<Object>,object的内存管理是可定制的Q甚臛_以定制引用计数结点的内存分配Q以满对内存有Ҏ要求的情c而这一切,都被Object的实现者隐藏v来,使用Object的客L是不用关心的。这和以前标准库的组件实现策略有些不同。比如说, vector<int, A1>和vector<int, A2>Q由于内存分配策略的不同Q而变成类型的不同Q造成接口的改变?/span>q一点在shared_ptr的设计时被避免了Q当然以一定的性能代h。shared_ptr作ؓC++面向对象设计的一个重要组Ӟ接口的简单性是很重要的Q必要?/span>接口和实现的分离。与此相似的q有tr1::function的设计?br>
2.在同一体系中,各种cd的智能指针可以互相{换?br>
   如下例:

struct Object : InterfaceA, InterfaceB {
    MemberA memberA;
};


shared_ptr
<Object> obj(new Object);
shared_ptr
<InterfaceA> a = obj;
shared_ptr
<InterfaceB> b = obj;
shared_ptr<Object> p = static_pointer_cast<Object>(b);
shared_ptr<void> p2 = obj;


  甚至q可以取得数据成员的指针Q?br>
shared_ptr<Object> obj(new Object);
shared_ptr
<MemberA> memberA(obj, &obj->memberA);


  再来说说shared_ptr的缺炏V?br>

1.对于使用引用计数的智能指针来_必须要小心出现@环引用?br>     在重度?/span>shared_ptr的系l中Q你必须一开始就明确cMcȝ关系Q以军_哪里使用shared_ptrQ哪里?/span>weak_ptrQ否则就会出现内存泄霌Ӏ?span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>shared_ptr的接?/span>转换的灵zL,也很ҎD指针被滥用?/span>内存自动理的问题ƈ没有得到解决Q它只是被{UM?br>
2.shared_ptr使用非嵌入式设计Q这样可以用于基本cdQ比?shared_ptr<int>。但是根据个人经验,q种情况在很用。大部分情况q是使用自己设计的类。这有一个问题,是没有很方便的办法实现this指针?/span>指针的{换。标准库中提供了enable_shared_from_thiscL解决q个问题。但q?/span>已经使所谓的非嵌入式设计徒有虚名。而假如一开始采?span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: #000000; WORD-SPACING: 0px" class=Apple-style-span>嵌入式设计的话,则在性能代h和多U程设计斚wh更大的灵zL?/span>



eXile 2009-11-02 17:38 发表评论
]]>
TDD for GUIhttp://www.shnenglu.com/eXile/archive/2009/06/22/88271.htmleXileeXileMon, 22 Jun 2009 05:15:00 GMThttp://www.shnenglu.com/eXile/archive/2009/06/22/88271.htmlhttp://www.shnenglu.com/eXile/comments/88271.htmlhttp://www.shnenglu.com/eXile/archive/2009/06/22/88271.html#Feedback0http://www.shnenglu.com/eXile/comments/commentRss/88271.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/88271.html阅读全文

eXile 2009-06-22 13:15 发表评论
]]>
最单的foreach实现(VC & GCC)http://www.shnenglu.com/eXile/archive/2009/05/08/82201.htmleXileeXileThu, 07 May 2009 17:25:00 GMThttp://www.shnenglu.com/eXile/archive/2009/05/08/82201.htmlhttp://www.shnenglu.com/eXile/comments/82201.htmlhttp://www.shnenglu.com/eXile/archive/2009/05/08/82201.html#Feedback10http://www.shnenglu.com/eXile/comments/commentRss/82201.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/82201.html阅读全文

eXile 2009-05-08 01:25 发表评论
]]>
[T] ICE实例学习QLet's Chat! (2) 实现服务?/title><link>http://www.shnenglu.com/eXile/archive/2009/03/26/77897.html</link><dc:creator>eXile</dc:creator><author>eXile</author><pubDate>Wed, 25 Mar 2009 16:54:00 GMT</pubDate><guid>http://www.shnenglu.com/eXile/archive/2009/03/26/77897.html</guid><wfw:comment>http://www.shnenglu.com/eXile/comments/77897.html</wfw:comment><comments>http://www.shnenglu.com/eXile/archive/2009/03/26/77897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/eXile/comments/commentRss/77897.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/eXile/services/trackbacks/77897.html</trackback:ping><description><![CDATA[<br><span style="FONT-SIZE: 18pt"><strong>服务器实玎ͼ</strong></span><br><br>       服务器用C++。注意它的结构:c?ChatRoom 实现了大部分的应用逻辑。ؓ了支持推模型与拉模型Q服务器实现了类ChatSession 和类 PollingChatSession?ChatRoom 调用 ChatRoomCallbackAdapter 对象?send 函数来传递客h息,该对象隐藏了两种模型之间的差异?br><br>ChatRoom 实现Q?br><br>      ChatRoom是一个普通的C++对象Q而不是一个Servant.<br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> C++ </span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> ChatRoomCallbackAdapter { </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> <img src="http://www.shnenglu.com/Images/dot.gif"> </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"> }; <br>typedef IceUtil::Handle</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">ChatRoomCallbackAdapter</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> ChatRoomCallbackAdapterPtr; <br> <br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> ChatRoom : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> IceUtil::Shared <br>{ <br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> reserve(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> unreserve(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> join(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomCallbackAdapterPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> leave(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br>    Ice::Long send(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br> <br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">: <br>    typedef map</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">, ChatRoomCallbackAdapterPtr</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> ChatRoomCallbackMap; <br> <br>    ChatRoomCallbackMap _members; <br>    </span><span style="COLOR: #0000ff">set</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> _reserved; <br>    IceUtil::Mutex _mutex; <br>}; <br>typedef IceUtil::Handle</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">ChatRoom</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> ChatRoomPtr;</span></div> <p>      成员_reserverd是一个字W串集合Q它存储已经建立回话Q但是还没有加入聊天室的客户名。_members存储当前聊天室的所有用P已经调用qjoin函数的用P?br><br>     成员函数 reserve ?unreserve l护 _reserved 集合?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> C++ </span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <br>ChatRoom::reserve(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> name) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_reserved.find(name) </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> _reserved.end() </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> _members.find(name) </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> _members.end()) <br>    { <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">The name </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> name </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> is already in use.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br>    } <br>    _reserved.insert(name); <br>} <br> <br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <br>ChatRoom::unreserve(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> name) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    _reserved.erase(name); <br>}</span></div> <p><br>     join操作d用户到聊天室?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> C++ </span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <br>ChatRoom::join(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> name, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomCallbackAdapterPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> callback) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    IceUtil::Int64 timestamp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> IceUtil::Time::now().toMilliSeconds(); <br>    _reserved.erase(name); <br> <br>    Ice::StringSeq names; <br>    ChatRoomCallbackMap::const_iterator q; <br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(q </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _members.begin(); q </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> _members.end(); </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">q) <br>    { <br>        names.push_back((</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">q).first); <br>    } <br> <br>    callback</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">init(names); <br> <br>    _members[name] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> callback; <br> <br>    UserJoinedEventPtr e </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> UserJoinedEvent(timestamp, name); <br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(q </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _members.begin(); q </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> _members.end(); </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">q) <br>    { <br>        q</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">second</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">join(e); <br>    } <br>}<br></span></div> <p><br>      send实现Q同join实现非常cMQ?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> C++ </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">Ice::Long <br>ChatRoom::send(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> name, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> message) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    IceUtil::Int64 timestamp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> IceUtil::Time::now().toMilliSeconds(); <br> <br>    MessageEventPtr e </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> MessageEvent(timestamp, name, message); <br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(ChatRoomCallbackMap::iterator q </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _members.begin(); q </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> _members.end(); </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">q) <br>    { <br>        q</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">second</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">send(e); <br>    } <br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> timestamp; <br>}</span></div> <p> </p> <p> c?ChatRoomCallbackAdapter<br><br></p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> C++ </span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> ChatRoomCallbackAdapter : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> IceUtil::Shared <br>{ <br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> init(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::StringSeq</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> join(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> UserJoinedEventPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> leave(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> UserLeftEventPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> send(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> MessageEventPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; <br>};</span></div> <br>推模?CallbackAdapter 实现Q? <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> SessionCallbackAdapter : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> ChatRoomCallbackAdapter <br>{ <br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br>    SessionCallbackAdapter(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomCallbackPrx</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> callback, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatSessionPrx</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> session)    : _callback(callback), _session(session) <br>    { <br>    } <br> <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> init(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::StringSeq</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> users) <br>    { <br>        _callback</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">init_async(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> AMICallback</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">AMI_ChatRoomCallback_init</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">(_session), users); <br>    } <br> <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> join(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> UserJoinedEventPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> e) <br>    { <br>        _callback</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">join_async(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> AMICallback</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">AMI_ChatRoomCallback_join</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">(_session), <br>                              e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">timestamp, <br>                              e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">name); <br>    } <br> <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> leave(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> UserLeftEventPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> e) <br>    { <br>        _callback</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">leave_async(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> AMICallback</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">AMI_ChatRoomCallback_leave</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">(_session), <br>                               e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">timestamp, <br>                               e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">name); <br>    } <br> <br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> send(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> MessageEventPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> e) <br>    { <br>        _callback</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">send_async(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> AMICallback</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">AMI_ChatRoomCallback_send</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">(_session), <br>                              e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">timestamp, <br>                              e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">name, <br>                              e</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">message); <br>    } <br> <br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">: <br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomCallbackPrx _callback; <br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatSessionPrx _session; <br>};<br></span></div> <br>      看一下SessionCallbackAdapter的四个成员函敎ͼ当异步调用完成时Q都使用cAMICallback来接攉知。它的定义如下:<br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">template</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> AMICallback : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> T <br>{ <br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br>    AMICallback(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatSessionPrx</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> session) : _session(session) <br>    { <br>    }<br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> ice_response() <br>    { <br>    } <br> <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> ice_exception(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Exception</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) <br>    { <br>        </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> <br>        { <br>            _session</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">destroy(); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Collocated </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">        } <br>        </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::LocalException</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) <br>        { <br>        } <br>    } <br> <br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">: <br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatSessionPrx _session; <br>};<br></span></div>        当用户回调操作抛出异常,服务器立即销毁客户会话,x该用戯天室。这是因为,一旦客L回调对象出现了一ơ异常,它以后也׃可能再正常?br><br><br><span style="FONT-SIZE: 14pt">推模式会话创?/span>Q?br><br>     现在来看一下会话创建。推模式的客户用Glacier2Q所以要使用Glacier2的会话创建机制。Glacier2 允许用户通过提供一个Glacier2::SessionManager对象的代理来自定义会话创建机制。通过讄Glacier2.SessionManager属性来配置Gloacier2Q就可以使用自己的会话管理器。会话管理器除了一个trivial构造函敎ͼ讄聊天室指针)Q只有一个操作,createQGlacier2调用它来代理应用的会话创建?create 操作必须q回一个会话代理(cd为Glacier2::Session*Q。实现如下:<br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">Glacier2::SessionPrx <br>ChatSessionManagerI::create(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> name,<br>                            </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Glacier2::SessionControlPrx</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">, <br>                            </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> c) <br>{ <br>    </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000"> vname; <br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> <br>    { <br>        vname </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> validateName(name); <br>        _chatRoom</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">reserve(vname); <br>    } <br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> reason) <br>    { <br>       </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> CannotCreateSessionException(reason); <br>    } <br> <br>    Glacier2::SessionPrx proxy; <br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> <br>    { <br>        ChatSessionIPtr session </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> ChatSessionI(_chatRoom, vname); <br>        proxy </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> SessionPrx::uncheckedCast(c.adapter</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">addWithUUID(session)); <br> <br>        Ice::IdentitySeq ids; <br>        ids.push_back(proxy</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">ice_getIdentity()); <br>        sessionControl</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">identities()</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">add(ids); <br>    } <br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::LocalException</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) <br>    { <br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(proxy) <br>        { <br>            proxy</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">destroy(); <br>        } <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> CannotCreateSessionException(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Internal server error</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br>    } <br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> proxy; <br>}</span></div> <br>     首先调用一个简单的帮助函数 validateName, 来检查传递的用户名是否包含非法字W,q把它{为大写,然后调用 reserver函数把它加到聊天室的_reserved集合中。我们要监视q些操作抛出的消息,q把它{化ؓGlacide2::CannotCreateSessionException异常Q即在create操作的异常规范声明的异常?br>     接着实例化一个ChatSessionI对象Q见下面Q来创徏会话。注意这个会话用UUID作ؓ对象标识Q所以保证标识符唯一?br>    最后,dq个新创建的会话标识QGllacier2只通过它来转发l过q个会话的请求。实际上Q?#8220;只{发经q这个会话的q且只到q个会话的请?#8221;Q这是一U安全的办法Q如果有恶意客户能猜出另一个客户会话的标识Q它也不能向别的对象发送请求(可能在除了聊天服务器之外的服务器上)。如果出错,销毁刚创徏的会话对象,q样避免了资源泄霌Ӏ?br>       q就是利用Glacier2创徏会话的全部。如果你希望使用Glacier2的认证机Ӟ可以讄属性Glacier2.PermissionsVerifier为执行认证的对象代理。(Glacier2提供一个内|的权限验证器,NullPermissionsVerifierQ可以检查用户名和密码)?br>       图:会话创徏交互图(略)<br><br>       ChatSessionIcdCChatSession接口?br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> ChatSessionI : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> ChatSession <br>{ <br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">: <br>    ChatSessionI(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomPtr</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br> <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> setCallback(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomCallbackPrx</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> Ice::Long send(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br>    </span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> destroy(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">); <br> <br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">: <br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomPtr _chatRoom; <br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000"> _name; <br>    ChatRoomCallbackAdapterPtr _callback; <br>    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> _destroy; <br>    IceUtil::Mutex _mutex; <br>}; <br>typedef IceUtil::Handle</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">ChatSessionI</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> ChatSessionIPtr;</span></div>          构造函数设|聊天室和用户名Qƈ把_destroy讄为False.<br>       <br>        ׃Glacier2::create操作不允怼递代理,必须把创Z话和讄回调分成两步。这是setCallback的实玎ͼ<br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <br>ChatSessionI::setCallback(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> ChatRoomCallbackPrx</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> callback, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> c) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_destroy) <br>    { <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> Ice::ObjectNotExistException(__FILE__, __LINE__); <br>    } <br> <br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_callback </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">callback) <br>    { <br>        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">; <br>    } <br> <br>    Ice::Context ctx; <br>    ctx[</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">_fwd</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">o</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">; <br>    _callback </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> SessionCallbackAdapter(callback</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">ice_context(ctx), <br>                                           ChatSessionPrx::uncheckedCast( <br>                                               c.adapter</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">createProxy(c.id))); <br>    _chatRoom</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">join(_name, _callback); <br>}</span></div> <p>      注意Q在使用join传递代理之前,向客户代理添加了一个gؓ "o" 的_fwd上下文。它提示Glacier使用单向调用来{发客户回调。这h双向调用更加有效。因为所有的回调操作均ؓvoidq回|所以可以单向调用?br>     服务器的回调为普通的双向调用。这样当出错时可以通知服务器。当客户端出错时Q这个对l束客户会话很有用?br><br>     一旦客戯用了setCallbackQ就可以接收聊天室的各种行ؓ通知。下为send实现Q?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">Ice::Long <br>ChatSessionI::send(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> message, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_destroy) <br>    { <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> Ice::ObjectNotExistException(__FILE__, __LINE__); <br>    } <br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">_callback) <br>    { <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> InvalidMessageException(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">You cannot send messages until you joined the chat.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br>    } <br>    </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">; <br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> <br>    { <br>        msg </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> validateMessage(message); <br>    } <br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> reason) <br>    { <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> InvalidMessageException(reason); <br>    } <br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> _chatRoom</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">send(_name, msg); <br>}</span></div> <p> <br>    客户要离开聊天室,只要调用 destory.</p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <br>ChatSessionI::destroy(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::Current</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> c) <br>{ <br>    IceUtil::Mutex::Lock sync(_mutex); <br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_destroy) <br>    { <br>        </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> Ice::ObjectNotExistException(__FILE__, __LINE__); <br>    } <br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"> <br>    { <br>        c.adapter</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">remove(c.id);<br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(_callback </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) <br>        { <br>            _chatRoom</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">unreserve(_name); <br>        } <br>        </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> <br>        { <br>            _chatRoom</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">leave(_name); <br>        } <br>    } <br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Ice::ObjectAdapterDeactivatedException</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">) <br>    { <br>        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> No need to clean up, the server is shutting down. </span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">    } <br>    _destroy </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">; <br>}</span></div> <p> </p> <p> </p> <img src ="http://www.shnenglu.com/eXile/aggbug/77897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/eXile/" target="_blank">eXile</a> 2009-03-26 00:54 <a href="http://www.shnenglu.com/eXile/archive/2009/03/26/77897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[T] ICE实例学习QLet's Chat! 节译 (1)http://www.shnenglu.com/eXile/archive/2009/03/25/77890.htmleXileeXileWed, 25 Mar 2009 15:52:00 GMThttp://www.shnenglu.com/eXile/archive/2009/03/25/77890.htmlhttp://www.shnenglu.com/eXile/comments/77890.htmlhttp://www.shnenglu.com/eXile/archive/2009/03/25/77890.html#Feedback0http://www.shnenglu.com/eXile/comments/commentRss/77890.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/77890.htmlhttp://www.zeroc.com/articles/index.html

需?br>
      1Q一个典型的聊天室应用,使用客户?服务器架构,客户发送消息到中心服务器,然后Q消息发送给其它客户?br>      2Q尽量减服务器理Q甚臛_以不需要?br>      3Q通信必须安全Q通过公共|络时必要保护个h隐私?br>      4Q当客户端和服务器有防火墙保护时也能正常q行Q客L不用修改它的|络或者防火墙讄?br>      5Q客L可以在各U^C利用多种语言实现Q比如说利用Web览器作为客L?br>      6Q客L可能|络带宽有限Q所以应该尽量减网l流量?br>      只支持单个聊天室。(多个聊天室只是代码多了点Qƈ没有增加M隑ֺQ?br>
设计

      在本文中Q将会演C多U客L的设计和实现。包括:
      1QC++命o行客LQ?br>      2QJAVA SWing GUI客户端;
      3Q?NET WPF客户端;
      4QPHP|页客户端;
      5QSilverlight |页客户端;
     
     注意Q对于ICE3.3, PHP和Ruby只提供了客户端的Run Time。我们在考虑当连接的客户如何从服务器获得消息Ӟ必须要想到这一炏V对于消息发布,有两U通信模型Q?br>     1Q推模型Q略
     2Q拉模型Q略
     推模型比较简单,Ҏ实现Q我们的Chat 客户端中QC++QJava, .Net, Silverlight(0.3)都用该模型。PHP客户端用拉模型?br>
推模型定?br>     每个客户端中提供一?ChatRoomCallback cd的ICE对象到服务器。当发生事gӞ服务器调用该对象的操作通知客户。SLICE定义如下Q?br>
// Slice 
module Chat 

// Implemented by clients 
interface ChatRoomCallback 

    [
"ami"void init(Ice::StringSeq users); 
    [
"ami"void join(long timestamp, string name); 
    [
"ami"void leave(long timestamp, string name); 
    [
"ami"void send(long timestamp, string name, string message); 
}; 
};

     1Q当用户首次q接到聊天室Ӟ服务器调?init 操作.     users参数告诉用户目前q接到聊天室的所有用户信息?br>     2Q有用户q接到聊天室Ӟ服务器调?join 操作?br>     3Q有用户断开q接Ӟ服务器调?nbsp;leave 操作?br>     4Q有用户发送消息时Q服务器调用 send 操作?br>     注意设计使用异步事g。元数据指o ["ami"] 标明服务器异步调用回调操作。当客户端行为异常时Q这Ҏ务器是一个保护:客户端可能长旉dQ服务器调用期间不会因此失去对线E的控制?br>
与防火墙协作
      ?.....

      Glacer2是ICE针对q种情况的预建的解决ҎQ它扮演一个服务器前端。Glacer2h以下特征Q?br>      1Q支持会话概念,API支持认证机制Q可实现自定义的会话创徏和认证?br>      2Q单个Glacer2可进行Q意数量的服务器和客户端{发。服务器只要有一个端口接受外来连接,而不用管具体服务器个数?br>     3Q对于具有防火墙的客LQ服务器也可调用其提供的回调?br>
     因ؓ Glacer2会话概念是面向连接的Q只有当客户端同Glacer2的连接打开Ӟ更精的_同Glacer2保持一个激zȝ会话Ӟ服务器才可以对客戯行回调。换句话_当客L同Glacer2失去q接QGlacer2自动销毁会话。ؓ了阻止客L到Glacer2的连接被意外关闭Q客L必须要禁用ACMQAutomic Connection Management, 自动q接理Q。而且QGlacer2通常寚w旉I闲的会话设|超时。当聊天室长旉没有动作ӞZ防止Glacer2销毁会话,客户端必d期性进行激z,比如Q调?ice_ping, 来对Glacer2的会话超时进行重|?br>
     Chat客户端通过服务器提供的 ChatSession接口来和服务器通信?ChatSession 从Glacer2::Sessionz?br>
// Slice 
module Chat 

exception InvalidMessageException 

    
string reason; 
}; 
 
interface ChatSession extends Glacier2::Session 

    
void setCallback(ChatRoomCallback* cb); 
    [
"ami"long send(string message) throws InvalidMessageException; 
}; 
};

      q就是推模型QChat客户端调用ChatSession的send来发送消息,服务器调用每一个客LChatRoomCallback的send操作q行分发?br>
拉模型定?br>
TODO




eXile 2009-03-25 23:52 发表评论
]]>
[T] 利用QTq行web与本地؜合应用开?http://www.shnenglu.com/eXile/archive/2009/03/09/75997.htmleXileeXileMon, 09 Mar 2009 08:41:00 GMThttp://www.shnenglu.com/eXile/archive/2009/03/09/75997.htmlhttp://www.shnenglu.com/eXile/comments/75997.htmlhttp://www.shnenglu.com/eXile/archive/2009/03/09/75997.html#Feedback7http://www.shnenglu.com/eXile/comments/commentRss/75997.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/75997.html阅读全文

eXile 2009-03-09 16:41 发表评论
]]>
(Z)正则表达?0分钟入门教程http://www.shnenglu.com/eXile/archive/2009/01/15/72092.htmleXileeXileThu, 15 Jan 2009 06:58:00 GMThttp://www.shnenglu.com/eXile/archive/2009/01/15/72092.htmlhttp://www.shnenglu.com/eXile/comments/72092.htmlhttp://www.shnenglu.com/eXile/archive/2009/01/15/72092.html#Feedback2http://www.shnenglu.com/eXile/comments/commentRss/72092.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/72092.html

正则表达?0分钟入门教程

版本Qv2.3 (2008-4-13) 作者:deerchao 转蝲h?a >来源

目录

跌目录

  1. 本文目标
  2. 如何使用本教E?/font>
  3. 正则表达式到底是什么东西?
  4. 入门
  5. 试正则表达?/font>
  6. 元字W?/font>
  7. 字符转义
  8. 重复
  9. 字符c?/font>
  10. 分枝条g
  11. 反义
  12. 分组
  13. 后向引用
  14. 零宽断言
  15. 负向零宽断言
  16. 注释
  17. 贪婪与懒?/font>
  18. 处理选项
  19. ql?递归匚w
  20. q有些什么东西没提到
  21. 联系作?/font>
  22. 最?来点q告...
  23. |上的资源及本文参考文?/font>
  24. 更新说明

本文目标

30分钟内让你明白正则表辑ּ是什么,q对它有一些基本的了解Q让你可以在自己的程序或|页里用它?/p>

如何使用本教E?/h2>

最重要的是——请l我30分钟Q如果你没有使用正则表达式的l验Q请不要试图?0U?/em>内入门——除非你是超?:)

别被下面那些复杂的表辑ּ吓倒,只要跟着我一步一步来Q你会发现正则表辑ּ其实q?span lang="zh-cn">没有你想? 中的那么困难。当Ӟ如果你看完了q篇教程之后Q发现自己明白了很多Q却又几乎什么都C得,那也是很正常的——我认ؓQ没接触q正则表辑ּ的h在看完这 教E后Q能把提到过的语法记?0%以上的可能性ؓ零。这里只是让你明白基本的原理Q以后你q需要多l习Q多使用Q才能熟l掌握正则表辑ּ?/p>

除了作ؓ入门教程之外Q本文还试图成ؓ可以在日常工作中使用的正则表辑ּ语法参考手册。就作者本人的l历来说Q这个目标还是完成得不错的——你看,我自׃没能把所有的东西C来,不是吗?

清除格式 文本格式U定Q?span class="name">专业术语 元字W?语法格式 正则表达?/span> 正则表达式中的一部分(用于分析) 对其q行匚w的源字符?/span> Ҏ则表辑ּ或其中一部分的说?/span>

隐藏Ҏ 本文双有一些注释,主要是用来提供一些相关信息,或者给没有E序员背景的读者解释一些基本概念,通常可以忽略?/p>

正则表达式到底是什么东西?

字符是计机软g处理文字时最基本的单位,可能是字母,数字Q标点符PI格Q换行符Q汉字等{?span class="name">字符?/span>?个或更多个字W的序列?span class="name">文本也就是文字,字符丌Ӏ说某个字符?span class="name">匚w某个正则表达式,通常是指q个字符串里有一部分Q或几部分分别)能满辑ּl出的条件?/p>

在编写处理字W串的程序或|页Ӟl常会有查找W合某些复杂规则的字W串的需要?span class="name">正则表达?/span>是用于描述q些规则的工兗换句话_正则表达式就是记录文本规则的代码?/p>

很可能你使用qWindows/Dos下用于文件查扄通配W?wildcard)Q也是*?span class="code">?。如果你x找某个目录下的所有的Word文档的话Q你会搜?span style="color: red;">*.doc。在q里Q?span class="code">*会被解释成Q意的字符丌Ӏ和通配W类|正则表达式也是用来进行文本匹配的工具Q只不过比v通配W,它能更精地描述你的需求——当Ӟ代h是更复杂——比如你可以~写一个正则表辑ּQ用来查?span class="desc">所有以0开_后面跟着2-3个数字,然后是一个连字号“-”Q最后是7?位数字的字符?/span>(?span class="string">010-12345678?span class="string">0376-7654321)?/p>

入门

学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子q行修改Q实验。下面给Z不少单的例子Qƈ对它们作了详l的说明?/p>

假设你在一英文小说里查找hiQ你可以使用正则表达?span class="regex">hi?/p>

q几乎是最单的正则表达式了Q它可以_匚wq样的字W串Q?span class="desc">׃个字W组成,前一个字W是h,后一个是i。通常Q处理正则表辑ּ的工具会提供一个忽略大写的选项Q如果选中了这个选项Q它可以匚whi,HI,Hi,hIq四U情况中的Q意一U?/p>

不幸的是Q很多单词里包含hiq两个连l的字符Q比?span class="string">him,history,high{等。用hi来查扄话,q里边的hi也会被找出来。如果要_地查找hiq个单词的话Q我们应该?span class="regex">\bhi\b?/p>

\b是正则表辑ּ规定的一个特D代码(好吧Q某些h叫它元字W,metacharacterQ,代表着单词的开头或l尾Q也是单词的分界处。虽焉常英文的单词是q|标点W号或者换行来分隔的,但是\bq不匚wq些单词分隔字符中的M一个,?strong>只匹配一个位|?/strong>?/p>

如果需要更_的说法,\b匚wq样的位|:它的前一个字W和后一个字W不全是(一个是,一个不是或不存?\w?/p>

假如你要扄?span class="desc">hi后面不远处跟着一个LucyQ你应该?span class="regex">\bhi\b.*\bLucy\b?/p>

q里Q?span class="part">.是另一个元字符Q匹?span class="desc">除了换行W以外的L字符?span class="part">*同样是元字符Q不q它代表的不是字W,也不是位|,而是数量——它指定*前边的内容可以连l重复出CQ意次以整个表达式得到匹?/span>。因此,.*q在一起就意味着L数量的不包含换行的字W?/span>。现?span class="regex">\bhi\b.*\bLucy\b的意思就很明显了Q?span class="desc">先是一个单词hi,然后是Q意个L字符(但不能是换行)Q最后是Lucyq个单词?/p>

换行W就?\n',ASCII~码?0(十六q制0x0A)的字W?/p>

如果同时使用其它元字W,我们p构造出功能更强大的正则表达式。比如下面这个例子:

0\d\d-\d\d\d\d\d\d\d\d匚wq样的字W串Q?span class="desc">?开_然后是两个数字,然后是一个连字号“-”Q最后是8个数?/span>(也就是中国的电话L。当Ӟq个例子只能匚w区号?位的情Ş)?/p>

q里?span class="part">\d是个新的元字W,匚w一位数?0Q或1Q或2Q或……)?span class="part">-不是元字W,只匹配它本n——连字符或者减受?/p>

Z避免那么多烦人的重复Q我们也可以q样写这个表辑ּQ?span class="regex">0\d{2}-\d{8}?q里\d后面?span class="part">{2}({8})的意思是前面\d必须q箋重复匚w2?8??/p>

试正则表达?/h2>

如果你不觉得正则表达式很难读写的话,要么你是一个天才,要么Q你不是地球人。正则表辑ּ的语法很令h头疼Q即使对l常使用它的人来说也是如此。由于难于读写,Ҏ出错Q所以找一U工具对正则表达式进行测试是很有必要的?/p>

׃在不同的环境下正则表辑ּ的一些细节是不相同的Q本教程介绍的是微Y .Net Framework 2.0下正则表辑ּ的行为,所以,我向你介l一?Net下的工具Regex Tester。首先你保已经安装?a title="转到下蝲.Net Framework 2.0的页?>.Net Framework 2.0Q然?a title="从www.unibetter.com下蝲Regex Tester, 75KB">下蝲Regex Tester。这是个l色软gQ下载完后打开压羃?直接q行RegexTester.exe可以了?/p>

下面是Regex Testerq行时的截图Q?/p>

Regex Testerq行时的截图

元字W?/h2>

现在你已l知道几个很有用的元字符了,?span class="code">\b,.,*Q还?span class="code">\d.正则表达式里q有更多的元字符Q比?span class="code">\s匚wL的空白符Q包括空|制表W?Tab)Q换行符Q中文全角空格等?span class="code">\w匚w字母或数字或下划U或汉字{?/span>?/p>

对中?汉字的特D处理是?Net提供的正则表辑ּ引擎支持的,其它环境下的具体情况h看相x档?/p>

下面来看看更多的例子Q?/p>

\ba\w*\b匚w以字?span class="part">a开头的单词——先是某个单词开始处(\b)Q然后是字母a,然后是Q意数量的字母或数?\w*)Q最后是单词l束?\b)?/p>

好吧Q现在我们说说正则表辑ּ里的单词是什么意思吧Q就是多于一个的q箋?span class="code">\w。不错,q与学习英文时要背的成千上万个同名的东西的确关系不大 :)

\d+匚w1个或更多q箋的数?/span>。这里的+是和*cM的元字符Q不同的?span class="code">*匚w重复L?可能??Q?span class="code">+则匹?span class="desc">重复1ơ或更多?/span>?/p>

\b\w{6}\b 匚w刚好6个字?数字的单?/span>?/p>
?.常用的元字符
代码 说明
. 匚w除换行符以外的Q意字W?/span>
\w 匚w字母或数字或下划U或汉字
\s 匚wL的空白符
\d 匚w数字
\b 匚w单词的开始或l束
^ 匚w字符串的开?/span>
$ 匚w字符串的l束

元字W?span class="code">^Q和数字6在同一个键位上的符P?span class="code">$都匹配一个位|,q和\b有点cM?span class="code">^匚w你要用来查找的字W串的开_$匚wl尾。这两个代码在验证输入的内容旉常有用,比如一个网站如果要求你填写的QQ号必Mؓ5位到12位数字时Q可以用:^\d{5,12}$?/p>

q里?span class="part">{5,12}和前面介l过?span class="part">{2}是类似的Q只不过{2}匚w只能不多不少重复2?/span>Q?span class="part">{5,12}则是重复的次C能少?ơ,不能多于12?/span>Q否则都不匹配?/p>

因ؓ使用?span class="part">^?span class="part">$Q所以输入的整个字符串都要用来和\d{5,12}来匹配,也就是说整个输入必须??2个数?/span>Q因此如果输入的QQ可匚wq个正则表达式的话,那就W合要求了?/p>

和忽略大写的选项cMQ有些正则表辑ּ处理工具q有一个处理多行的选项。如果选中了这个选项Q?span class="code">^?span class="code">$的意义就变成?span class="desc">匚w行的开始处和结束处?/p>

字符转义

如果你想查找元字W本w的话,比如你查?span class="desc">.,或?span class="desc">*,出C问题Q你没办法指定它们,因ؓ它们会被解释成别的意思。这时你得使用\来取消这些字W的Ҏ意义。因此,你应该?span class="regex">\.?span class="regex">\*。当Ӟ要查?span class="desc">\本nQ你也得?span class="regex">\\.

例如Q?span class="regex">unibetter\.com匚wunibetter.comQ?span class="regex">C:\\Windows匚wC:\Windows?/p>

重复

你已l看q了前面?span class="code">*,+,{2},{5,12}q几个匹配重复的方式了。下面是正则表达式中所有的限定W?指定数量的代码,例如*,{5,12}{?Q?/p>
?.常用的限定符
代码/语法 说明
* 重复零次或更多次
+ 重复一ơ或更多?/span>
? 重复零次或一?/span>
{n} 重复n?/span>
{n,} 重复nơ或更多?/span>
{n,m} 重复n到m?/span>

下面是一些用重复的例子Q?/p>

Windows\d+匚wWindows后面?个或更多数字

^\w+匚w一行的W一个单?或整个字W串的第一个单词,具体匚w哪个意思得看选项讄)

字符c?/h2>

要想查找数字Q字母或数字Q空白是很简单的Q因为已l有了对应这些字W集合的元字W,但是如果你想匚w没有预定义元字符的字W集?比如元音字母a,e,i,o,u),应该怎么办?

很简单,你只需要在Ҏ号里列出它们p了,?span class="regex">[aeiou]匹?span class="desc">M一个英文元韛_?/span>Q?span class="regex">[.?!]匚w标点W号(.??)?/p>

我们也可以轻村֜指定一个字W?span class="name">范围Q像[0-9]代表的含意与\d是完全一致的Q?span class="desc">一位数?/span>Q同?span class="regex">[a-z0-9A-Z_]也完全等同于\wQ如果只考虑英文的话Q?/p>

下面是一个更复杂的表辑ּQ?span class="regex">\(?0\d{2}[) -]?\d{8}?/p>

“(”?#8220;)”也是元字W,后面?a >分组?/font>里会提到Q所以在q里需要?a >转义?/p>

q个表达式可以匹?span class="desc">几种格式的电话号?/span>Q像(010)88886666Q或022-22334455Q或02912345678{。我们对它进行一些分析吧Q首先是一个{义字W?span class="part">\(,它能出现0ơ或1??),然后是一?span class="part">0Q后面跟着2个数?\d{2})Q然后是)?span class="part">-?span class="part">I格中的一个,它出?ơ或不出??)Q最后是8个数?\d{8})?/p>

分枝条g

不幸的是Q刚才那个表辑ּ也能匚w010)12345678?span class="string">(022-87654321q样?#8220;不正?#8221;的格式。要解决q个问题Q我们需要用?span class="name">分枝条g。正则表辑ּ里的分枝条g指的是有几种规则Q如果满_中Q意一U规则都应该当成匚wQ具体方法是?span class="code">|把不同的规则分隔开。听不明白?没关p,看例子:

0\d{2}-\d{8}|0\d{3}-\d{7}q个表达式能匚w两种以连字号分隔的电话号码:一U是三位区号Q?位本地号(?10-12345678)Q一U是4位区P7位本地号(0376-2233445)?/p>

\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}q个表达?span class="desc">匚w3位区L电话LQ其中区号可以用括hhQ也可以不用Q区号与本地号间可以用连字号或空格间隔,也可以没有间?/span>。你可以试试用分枝条件把q个表达式扩展成也支?位区L?/p>

\d{5}-\d{4}|\d{5}q个表达式用于匹配美国的邮政~码。美国邮~的规则?位数字,或者用q字号间隔的9位数字。之所以要l出q个例子是因为它能说明一个问题:使用分枝条gӞ要注意各个条件的序。如果你把它Ҏ\d{5}|\d{5}-\d{4}的话Q那么就只会匚w5位的邮编(以及9位邮~的??。原因是匚w分枝条gӞ会从左到右地测试每个条Ӟ如果满了某个分枝的话,׃会去再管其它的条件了?/p>

分组

我们已经提到了怎么重复单个字符Q直接在字符后面加上限定W就行了Q;但如果想要重复多个字W又该怎么办?你可以用括h指定子表辑ּ(也叫?span class="name">分组)Q然后你可以指定这个子表达式的重复ơ数了,你也可以对子表达式进行其它一些操?后面会有介绍)?/p>

(\d{1,3}\.){3}\d{1,3}是一?span class="desc">单的IP地址匚w表达式。要理解q个表达式,h下列序分析它:\d{1,3}匚w1?位的数字Q?span class="part">(\d{1,3}\.){3}匚w三位数字加上一个英文句?q个整体也就是这?span class="name">分组)重复3?/span>Q最后再加上一个一C位的数字(\d{1,3})?/p>

IP地址中每个数字都不能大于255Q大家千万不要被?4》第三季的编剧给忽悠?..

不幸的是Q它也将匚w256.300.888.999q种不可能存在的IP地址。如果能使用术比较的话Q或许能单地解决q个问题Q但是正则表辑ּ中ƈ不提供关于数学的M功能Q所以只能用冗长的分组Q选择Q字W类来描qC个正的IP地址Q?span class="regex">((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)?/p>

理解q个表达式的关键是理?span class="part">2[0-4]\d|25[0-5]|[01]?\d\d?Q这里我׃l说了,你自己应该能分析得出来它的意义?/p>

反义

有时需要查找不属于某个能简单定义的字符cȝ字符。比如想查找除了数字以外Q其它Q意字W都行的情况Q这旉要用?span class="name">反义Q?/p>
?.常用的反义代?/caption>
代码/语法 说明
\W 匚wL不是字母Q数字,下划U,汉字的字W?/span>
\S 匚wL不是I白W的字符
\D 匚wL非数字的字符
\B 匚w不是单词开头或l束的位|?/span>
[^x] 匚w除了x以外的Q意字W?/span>
[^aeiou] 匚w除了aeiouq几个字母以外的L字符

例子Q?span class="regex">\S+匚w不包含空白符的字W串?/p>

<a[^>]+>匚w用尖括号括v来的以a开头的字符?/span>?/p>

后向引用

使用括h定一个子表达式后Q?strong>匚wq个子表辑ּ的文?/strong>(也就是此分组捕获的内?可以在表辑ּ或其它程序中作进一步的处理。默认情况下Q每个分l会自动拥有一?span class="name">l号Q规则是Q从左向叻I以分l的左括号ؓ标志Q第一个出现的分组的组号ؓ1Q第二个?Q以此类推?/p>

后向引用用于重复搜烦前面某个分组匚w的文本。例如,\1代表分组1匚w的文?/span>。难以理解?LCZQ?/p>

\b(\w+)\b\s+\1\b可以用来匚w重复的单?/span>Q像go go, 或?span class="string">kitty kitty。这个表辑ּ首先?span class="desc">一个单?/span>Q也是单词开始处和结束处之间的多于一个的字母或数?/span>(\b(\w+)\b)Q这个单词会被捕获到~号?的分l中Q然后是1个或几个I白W?/span>(\s+)Q最后是分组1中捕L内容Q也是前面匚w的那个单词)(\1)?/p>

你也可以自己指定子表辑ּ?span class="name">l名。要指定一个子表达式的l名Q请使用q样的语法:(?<Word>\w+)(或者把括h?span class="code">'也行Q?span class="code">(?'Word'\w+)),q样把\w+的组名指定ؓWord了。要反向引用q个分组捕获的内容,你可以?span class="code">\k<Word>,所以上一个例子也可以写成q样Q?span class="regex">\b(?<Word>\w+)\b\s+\k<Word>\b?/p>

使用括L时候,q有很多特定用途的语法。下面列Z最常用的一些:

?.常用分组语法
分类 代码/语法 说明
捕获 (exp) 匚wexp,q捕h本到自动命名的组?/span>
(?<name>exp) 匚wexp,q捕h本到名称为name的组里,也可以写??'name'exp)
(?:exp) 匚wexp,不捕获匹配的文本Q也不给此分l分配组?/span>
零宽断言 (?=exp) 匚wexp前面的位|?/span>
(?<=exp) 匚wexp后面的位|?/span>
(?!exp) 匚w后面跟的不是exp的位|?/span>
(?<!exp) 匚w前面不是exp的位|?/span>
注释 (?#comment) q种cd的分l不Ҏ则表辑ּ的处理生Q何媄响,用于提供注释让h阅读

我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式Q只是这Ll匹配的内容不会像前两种那样被捕获到某个l里面,也不会拥有组?/span>?/p>

零宽断言

地球人,是不是觉得这些术语名U太复杂Q太难记了?我也和你一栗知道有q么一U东西就行了Q它叫什么,随它dQ?#8220;无名Q万物之?..”

接下来的四个用于查找在某些内?但ƈ不包括这些内?之前或之后的东西Q也是说它们像\b,^,$那样用于指定一个位|,q个位置应该满一定的条g(xa)Q因此它们也被称?span class="name">零宽断言。最好还是拿例子来说明吧Q?/p>

断言用来声明一个应该ؓ真的事实。正则表辑ּ中只有当断言为真时才会l进行匹配?/p>

(?=exp)也叫零宽度正预测先行断言Q它断言自n出现的位|的后面能匹配表辑ּexp。比?span class="regex">\b\w+(?=ing\b)Q匹?span class="desc">以ingl尾的单词的前面部分(除了ing以外的部?Q如查找I'm singing while you're dancing.Ӟ它会匚wsing?span class="desc">danc?/p>

(?<=exp)也叫零宽度正回顾后发断言Q它断言自n出现的位|的前面能匹配表辑ּexp。比?span class="regex">(?<=\bre)\w+\b会匹?span class="desc">以re开头的单词的后半部?除了re以外的部?Q例如在查找reading a bookӞ它匹?span class="desc">ading?/p>

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从双加v?Q你可以q样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})*\bQ用它对1234567890q行查找时结果是234567890?/p>

下面q个例子同时使用了这两种断言Q?span class="regex">(?<=\s)\d+(?=\s)匚w以空白符间隔的数?再次Q不包括q些I白W??/p>

负向零宽断言

前面我们提到q怎么查找不是某个字符或不在某个字W类?/strong>的字W的Ҏ(反义)。但是如果我们只是想?strong>保某个字符没有出现Q但q不惛_匚w?/strong>时怎么办?例如Q如果我们想查找q样的单?-它里面出C字母q,但是q后面跟的不是字母u,我们可以试q样Q?/p>

\b\w*q[^u]\w*\b匚w包含后面不是字母u的字母q的单?/span>。但是如果多做测?或者你思维_敏锐Q直接就观察出来?Q你会发玎ͼ如果q出现在单词的l尾的话Q像Iraq,BenqQ这个表辑ּ׃出错。这是因?span class="part">[^u]总要匚w一个字W,所以如果q是单词的最后一个字W的话,后面?span class="part">[^u]会匚wq后面的单词分隔符(可能是空|或者是句号或其它的什?Q后面的\w*\b会匚w下一个单词,于是\b\w*q[^u]\w*\bp匚w整个Iraq fighting?span class="name">负向零宽断言能解册L问题Q因为它只匹配一个位|,q不消费M字符。现在,我们可以q样来解册个问题:\b\w*q(?!u)\w*\b?/p>

零宽度负预测先行断言(?!exp)Q?span class="desc">断言此位|的后面不能匚w表达式exp。例如:\d{3}(?!\d)匚w三位数字Q而且q三位数字的后面不能是数?/span>Q?span class="regex">\b((?!abc)\w)+\b匚w不包含连l字W串abc的单?/span>?/p>

同理Q我们可以用(?<!exp),零宽度正回顾后发断言?span class="desc">断言此位|的前面不能匚w表达式expQ?span class="regex">(?<![a-z])\d{7}匚w前面不是写字母的七位数?/span>?/p>

误l分析表辑ּ(?<=<(\w+)>).*(?=<\/\1>)Q这个表辑ּ最能表现零宽断a的真正用途?/p>

一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匚w不包含属性的单HTML标签内里的内?/span>?span class="code">(<?(\w+)>)指定了这L前缀Q?span class="desc">被尖括号括v来的单词(比如可能?lt;b>)Q然后是.*(L的字W串),最后是一?span class="name">后缀(?=<\/\1>)。注意后~里的\/Q它用到了前面提q的字符转义Q?span class="part">\1则是一个反向引用,引用的正?span class="desc">捕获的第一l?/span>Q前面的(\w+)匚w的内容,q样如果前缀实际上是<b>的话Q后~是</b>了。整个表辑ּ匚w的是<b>?lt;/b>之间的内?再次提醒Q不包括前缀和后~本n)?/p>

注释

括L另一U用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)?/p>

要包含注释的话,最好是启用“忽略模式里的I白W?#8221;选项Q这样在~写表达式时能Q意的dI格QTabQ换行,而实际用时q些都将被忽略。启用这个选项后,?后面到这一行结束的所有文本都被当成注释忽略掉。例如,我们可以前面的一个表辑ּ写成q样Q?/p>

      (?<=    # 断言要匹配的文本的前~
<(\w+)> # 查找括hh的字母或数字(即HTML/XML标签)
) # 前缀l束
.* # 匚wL文本
(?= # 断言要匹配的文本的后~
<\/\1> # 查找括hh的内容:前面是一?/"Q后面是先前捕获的标{?br> ) # 后缀l束

贪婪与懒?/h2>

当正则表辑ּ中包含能接受重复的限定符Ӟ通常的行为是Q在使整个表辑ּ能得到匹配的前提下)匚w可能多的字W。考虑q个表达式:a.*bQ它会匚w最长的以a开始,以bl束的字W串。如果用它来搜烦aabab的话Q它会匹配整个字W串aabab。这被称?span class="name">贪婪匚w?/p>

有时Q我们更需?span class="name">懒惰匚wQ也是匚w可能少的字W。前面给出的限定W都可以被{化ؓ懒惰匚w模式Q只要在它后面加上一个问?span class="code">?。这?span class="regex">.*?意味着匚wL数量的重复,但是在能使整个匹配成功的前提下用最的重复。现在看看懒惰版的例子吧Q?/p>

a.*?b匚w最短的Q以a开始,以bl束的字W串。如果把它应用于aabab的话Q它会匹?span class="desc">aabQ第一到第三个字符Q?/span>?span class="desc">abQ第四到W五个字W)?/p>

Z么第一个匹配是aabQ第一到第三个字符Q而不是abQ第二到W三个字W)Q简单地_因ؓ正则表达式有另一条规则,比懒惎ͼ贪婪规则的优先更高Q最先开始的匚w拥有最高的优先权——The match that begins earliest wins?/p>
?.懒惰限定W?/caption>
代码/语法 说明
*? 重复Lơ,但尽可能重?/span>
+? 重复1ơ或更多ơ,但尽可能重?/span>
?? 重复0ơ或1ơ,但尽可能重?/span>
{n,m}? 重复n到mơ,但尽可能重?/span>
{n,}? 重复nơ以上,但尽可能重?/span>

处理选项

在C#中,你可以?a title="MSDN 相关文档">Regex(String, RegexOptions)构造函?/font>来设|正则表辑ּ的处理选项。如QRegex regex = new Regex("\ba\w{6}\b", RegexOptions.IgnoreCase);

上面介绍了几个选项如忽略大写Q处理多行等Q这些选项能用来改变处理正则表辑ּ的方式。下面是.Net中常用的正则表达式选项Q?/p>
?.常用的处理选项
名称 说明
IgnoreCase(忽略大小? 匚w时不区分大小写?/td>
Multiline(多行模式) 更改^?span class="code">$的含义,使它们分别在L一行的行首和行֌配,而不仅仅在整个字W串的开头和l尾匚w?在此模式?$的精含意是:匚w\n之前的位|以及字W串l束前的位置.)
Singleline(单行模式) 更改.的含义,使它与每一个字W匹配(包括换行W\nQ?
IgnorePatternWhitespace(忽略I白) 忽略表达式中的非转义I白q启用由#标记的注释?/td>
RightToLeft(从右向左查找) 匚w从右向左而不是从左向双行?/td>
ExplicitCapture(昑ּ捕获) 仅捕获已被显式命名的l?/td>
ECMAScript(JavaScript兼容模式) 使表辑ּ的行Z它在JavaScript里的行ؓ一致?/td>

一个经常被问到的问题是Q是不是只能同时使用多行模式和单行模式中的一U?{案是:不是。这两个选项之间没有M关系Q除了它们的名字比较怼Q以至于让h感到疑惑Q以外?/p>

ql?递归匚w

q里介绍的^衡组语法是由.Net Framework支持的;其它语言Q库不一定支持这U功能,或者支持此功能但需要用不同的语法?/p>

有时我们需要匹配像( 100 * ( 50 + 15 ) )q样的可嵌套的层ơ性结?/span>Q这时简单地使用\(.+\)则只会匹配到最左边的左括号和最双的右括号之间的内?q里我们讨论的是贪婪模式Q懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次C相等Q比?span class="string">( 5 / ( 3 + 2 ) ) )Q那我们的匹配结果里两者的个数也不会相{。有没有办法在这L字符串里匚w到最长的Q配对的括号之间的内容呢Q?/p>

Z避免(?span class="code">\(把你的大脑彻底搞p涂Q我们还是用括号代替圆括号吧。现在我们的问题变成了如何把xx <aa <bbb> <bbb> aa> yyq样的字W串里,最长的配对的尖括号内的内容捕获出来Q?/p>

q里需要用C下的语法构造:

  • (?'group') 把捕L内容命名为group,q压?span class="name">堆栈(Stack)
  • (?'-group') 从堆栈上弹出最后压入堆栈的名ؓgroup的捕获内容,如果堆栈本来为空Q则本分l的匚wp|
  • (?(group)yes|no) 如果堆栈上存在以名ؓgroup的捕获内容的话,l箋匚wyes部分的表辑ּQ否则l匹配no部分
  • (?!) 零宽负向先行断言Q由于没有后~表达式,试图匚wLp|

如果你不是一个程序员Q或者你自称E序员但是不知道堆栈是什么东西)Q你pL解上面的三种语法吧:W一个就是在黑板 上写一?group"Q第二个是从黑板上擦掉一?group"Q第三个是看黑板上写的q有没有"group"Q如果有ql匹配yes部分Q否? 匹配no部分?/p>

我们需要做的是每碰C左括P在压入一?Open",每碰C个右括号Q就弹出一个,C最后就看看堆栈是否为空Q-如果不ؓI那p明左括号比右括号多,那匹配就应该p|。正则表辑ּ引擎会进行回?攑ּ最前面或最后面的一些字W?Q尽量整个表达式得到匹配?/p>

<                         #最外层的左括号
[^<>]* #最外层的左括号后面的不是括L内容
(
(
(?'Open'<) #到了左括号Q在黑板上写一?Open"
[^<>]* #匚w左括号后面的不是括号的内?br> )+
(
(?'-Open'>) #到了右括号Q擦掉一?Open"
[^<>]* #匚wx号后面不是括L内容
)+
)*
(?(Open)(?!)) #在遇到最外层的右括号前面Q判断黑板上q有没有没擦掉的"Open"Q如果还有,则匹配失?br>> #最外层的右括号

ql的一个最常见的应用就是匹配HTML,下面q个例子可以匚w嵌套?lt;div>标签Q?span class="regex"><div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>.

q有些什么东西没提到

我已l描qC构造正则表辑ּ的大量元素,q有一些我没有提到的东ѝ下面是未提到的元素的列表,包含语法和简单的说明。你可以在网上找到更详细的参 考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到关?net下正则表辑ּ详细的文档?/p>
?.未详细讨论的语?/caption>
代码/语法 说明
\a 报警字符(打印它的效果是电脑嘀一?
\b 通常是单词分界位|,但如果在字符c里使用代表退?/span>
\t 制表W,Tab
\r 回R
\v 竖向制表W?/span>
\f 换页W?/span>
\n 换行W?/span>
\e Escape
\0nn ASCII代码中八q制代码为nn的字W?/span>
\xnn ASCII代码中十六进制代码ؓnn的字W?/span>
\unnnn Unicode代码中十六进制代码ؓnnnn的字W?/span>
\cN ASCII控制字符。比如\cC代表Ctrl+C
\A 字符串开?cM^Q但不受处理多行选项的媄?
\Z 字符串结或行尾(不受处理多行选项的媄?
\z 字符串结?cM$Q但不受处理多行选项的媄?
\G 当前搜烦的开?/span>
\p{name} Unicode中命名ؓname的字W类Q例如\p{IsGreek}
(?>exp) 贪婪子表辑ּ
(?<x>-<y>exp) ql?/span>
(?im-nsx:exp) 在子表达式exp中改变处理选项
(?im-nsx) 辑ּ后面的部分改变处理选项
(?(exp)yes|no) 把exp当作零宽正向先行断言Q如果在q个位置能匹配,使用yes作ؓ此组的表辑ּQ否则用no
(?(exp)yes) 同上Q只是用空表达式作为no
(?(name)yes|no) 如果命名为name的组捕获C内容Q用yes作ؓ表达式;否则使用no
(?(name)yes) 同上Q只是用空表达式作为no

联系作?/h2>

好吧,我承?我骗了你,dq里你肯定花了不?0分钟.怿?q是我的?而不是因Z太笨.我之所以说"30分钟",是ؓ了让你有信心,有耐心l箋下去.既然你看Cq里,那证明我的阴谋成功了.被忽悠的感觉很爽吧?

要投诉我,或者觉得我其实可以做得更好,或者有M其它问题,Ƣ迎?a >我的博客让我知道.



eXile 2009-01-15 14:58 发表评论
]]>Qt 4.5使用LGPLhttp://www.shnenglu.com/eXile/archive/2009/01/14/72031.htmleXileeXileWed, 14 Jan 2009 11:01:00 GMThttp://www.shnenglu.com/eXile/archive/2009/01/14/72031.htmlhttp://www.shnenglu.com/eXile/comments/72031.htmlhttp://www.shnenglu.com/eXile/archive/2009/01/14/72031.html#Feedback1http://www.shnenglu.com/eXile/comments/commentRss/72031.htmlhttp://www.shnenglu.com/eXile/services/trackbacks/72031.html

Nokia today announced that its Qt cross-platform user interface (UI) and application framework for desktop and embedded platforms will be available under the open source LGPL version 2.1 license from the release of Qt 4.5, scheduled for March 2009.  In addition:

  • Qt source code repositories will be made publicly available and will encourage contributions from desktop and embedded developer communities.
  • Service offerings for Qt will be expanded to ensure that all Qt development projects can have access to the same levels of support, independent of the selected license.
Nokia to license Qt under LGPL

We have some exciting news we’d like to share with the free software community: Qt will be licensed under the terms of the LGPL version 2.1 with the upcoming Qt 4.5 release, in addition to our standard GPL and commercial licenses. We are also pleased to announce that we are going to open up the Qt source code repository and also make it easier for the community to contribute to Qt.

Adding LGPL version 2.1 will greatly increase adoption of Qt across Windows, Linux, embedded Linux, Mac, S60, Windows CE, maemo, and Ovi web services. Having a larger number of users, including Nokia developers, providing feedback and contributions will help Qt remain a cutting edge, robust UI and application framework.

Going forward we will speed up the development of Qt using additional resources and work in even closer cooperation with the free software community. We will do this in a number of ways, including:

  • Employing more Qt developers
  • Opening our source code repository
  • Reducing the overhead needed to make a submission, including no longer requiring copyright assignments.
  • Launching a new web infrastructure to support contributions later this year.

As we know that license versions are important for many in the free software community, we wanted to also take the opportunity to provide some highlights of our upcoming changes:

  • Versions of Qt prior to 4.5 are not impacted by this announcement
  • We will continue to support the GPL version 2 through the newly added LGPL version 2.1 license, as it allows for the automatic conversion to the GPL.
  • We will continue to release Qt under GPL 3

As a first step we have selected LGPL version 2.1 as this is the version of the LGPL that best fits our purposes and we are most comfortable with at this point in time. We will continue to evaluate the adoption, use and legal interpretation of LGPL version 3 by the community and may use this version of the LGPL for future releases.

Finally, we will open the Qt repositories and provide more information regarding how interested parties can contribute to Qt with the release of Qt 4.5, which is scheduled for March. Until then, if you have any questions, please feel free to post your questions below.

Sincerely,

Sebastian Nyström
Vice President, Qt Software




eXile 2009-01-14 19:01 发表评论
]]>
ƷŮþþþavˬ| պŷһþþþ | þþȹ͵ۺ| þþƷһ| ɫþAVۺ| ŷ߽˾þ| þĻavŮ| ҰAVþһ| 97Ʒ˾þô߽| ޾þˬ˾Ʒ| þþۺϾɫۺ̾| þ¶Ʒ| þҹҹݺ| ŷ޾ƷþþavӰ| 99ƷþþƷһ| Ʒþþþþþþ| þ޾ƷĻ| þ93Ʒ91þۺ| þ¶Ʒ| þAV߳AVAV| Ʒþ99| þþƷAɫ| ޹һɾþþƷۺ| þþƷަvDz| þùƷHDAV| ѹۿ˾þѹۿ| þþþþݴۺϾƷ| ȾþӾþþƷ18| 99þۺϺݺۺϾþֹ| þþžѸƵ| AVպAVþ| Ļһþվ| ޾ƷŮþþþ99С˵| 91Ʒ91þۺ| ŷƷ˿þþĻ| һɫþ88Ʒۺ| 99ȶǾƷþþþþ| AVպAVþ| þ99Ʒŷ| þþһƷ99þþƷ88 | ޹Ʒþһ|