登录|免费注册
[搜索][菜单]
®
高级...

浏览选项

  • 手机网站排名
[子菜单]

(无标题)

?博客园_首页代码改变世界uuid:ee468d0b-f916-4fef-b11d-d88ee0b00c74;id=66992014-10-23T12:58:03Zfeed.cnblogs.comhttp://www.cnblogs.com/Jack47/p/read-gz-suffix-text-file-in-mapreduce.html如何让Hadoop读取以gz结尾的文本格式的文件 - Jack47如果没有配置解码的参数,hadoop默认会匹配文件名来解码文件内容。那么如何让Hadoop读取以gz结尾的文本格式的文件呢?2014-10-23T12:51:00Z2014-10-23T12:51:00ZJack47http://www.cnblogs.com/Jack47/<p><strong>背景:</strong></p><p>搜索引擎在build全量时,会产生数G的xml的中间文件,我需要去查询这些中间文件中,是否有某个特殊的字符。xml文件有很多,每个都有几百M,存储在hdfs上,而且是以gz结尾的文本格式的文件。</p><p>查找时,我是写了一个实现Tool接口,继承自Configured类的MapReduce,这样就可以传入自定义的参数给我的MapReduce程序了。需要在文件里Grep的内容,就是以参数的形式传入的。</p><p>写完代码调试时,问题来了,会报这个异常:</p><code>14/10/17 12:06:33 INFO mapred.JobClient: Task Id : attempt_201405252001_273614_m_000013_0, Status : FAILED<br/>java.io.IOException: incorrect header check<br/> at org.apache.hadoop.io.compress.zlib.ZlibDecompressor.inflateBytesDirect(Native Method)<br/> at org.apache.hadoop.io.compress.zlib.ZlibDecompressor.decompress(ZlibDecompressor.java:221)<br/> at org.apache.hadoop.io.compress.DecompressorStream.decompress(DecompressorStream.java:81)<br/> at org.apache.hadoop.io.compress.DecompressorStream.read(DecompressorStream.java:75)<br/> at java.io.InputStream.read(InputStream.java:85)<br/> at org.apache.hadoop.util.LineReader.readLine(LineReader.java:134)<br/> at org.apache.hadoop.mapred.LineRecordReader.next(LineRecordReader.java:133)<br/> at org.apache.hadoop.mapred.LineRecordReader.next(LineRecordReader.java:38)<br/> at org.apache.hadoop.mapred.MapTask$TrackedRecordReader.moveToNext(MapTask.java:208)<br/> at org.apache.hadoop.mapred.MapTask$TrackedRecordReader.next(MapTask.java:193)<br/> at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:48)<br/> at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:390)<br/> at org.apache.hadoop.mapred.MapTask.run(MapTask.java:324)<br/> at org.apache.hadoop.mapred.Child$4.run(Child.java:268)<br/> at java.security.AccessController.doPrivileged(Native Method)<br/> at javax.security.auth.Subject.doAs(Subject.java:396)<br/> at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1115)<br/> at org.apache.hadoop.mapred.Child.main(Child.java:262)<br/> </code><p><strong>分析过程:</strong></p><p>通过上面的异常,立马猜想到是由于我的文件是gz结尾,所以hadoop把它当作了压缩文件,然后尝试解压缩后读取,所以解压失败了。于是去问google,没有搜到能够直接解决我问题的答案,但是搜到了此处相关的源代码:<a href="http://grepcode.com/file/repository.cloudera.com/content/repositories/releases/com.cloudera.hadoop/hadoop-core/0.20.2-737/org/apache/hadoop/mapreduce/lib/input/">LineRecordReader.java</a>;于是尝试着去阅读代码来解决问题,这个类很简单,继承自RecordReader,没有看到next函数和readLine函数,那就应该是基类实现的。很快发现了看名字是跟压缩解码相关的代码:</p><code>private CompressionCodecFactory compressionCodecs = null;<br/>...<br/>compressionCodecs = new CompressionCodecFactory(job);<br/>final CompressionCodec codec = compressionCodecs.getCodec(file);<br/>...<br/>if (codec != null) {<br/>in = new LineReader(codec.createInputStream(fileIn), job);<br/>}<br/>else{<br/>...<br/>in = new LineReader(fileIn, job);<br/>}<br/> </code><p>此处file就是拿到的文件路径,可以看到,应该就是通过CompressionCode.getCode(file)函数,拿到的codec类,然后读取的时候出异常了。那怎么让MapReduce程序把这个.gz文件当作普通的文本文件呢?再点进去看<a href="http://grepcode.com/file/repository.cloudera.com/content/repositories/releases/com.cloudera.hadoop/hadoop-core/0.20.2-737/org/apache/hadoop/io/compress/CompressionCodecFactory.java#CompressionCodecFactory.%3Cinit%3E%28org.apache.hadoop.conf.Configuration%29">CompressionCodeFactory.java</a>的代码。getCodec函数的代码如下:</p><code>/**<br/>* Find the relevant compression codec for the given file based on its<br/>* filename suffix.<br/>* @param file the filename to check<br/>* @return the codec object<br/>*/<br/>public CompressionCodec getCodec(Path file) {<br/>CompressionCodec result = null;<br/> if (codecs != null) {<br/>String filename = file.getName();<br/> String reversedFilename = new StringBuffer(filename).reverse().toString();<br/> SortedMap&lt;String, CompressionCodec&gt; subMap = codecs.headMap(reversedFilename);<br/> if (!subMap.isEmpty()) {<br/> String potentialSuffix = subMap.lastKey();<br/> if (reversedFilename.startsWith(potentialSuffix)) {<br/> result = codecs.get(potentialSuffix);<br/> }<br/> }<br/>}<br/> return result;</code><p>}</p><p>就是根据文件名称匹配来得到对应的解压缩类。咋们按图索骥,去看看codecs是在哪里赋值的:</p><code>/**<br/>* Find the codecs specified in the config value io.compression.codecs <br/>* and register them. Defaults to gzip and zip.<br/>*/<br/>public CompressionCodecFactory(Configuration conf) {<br/>codecs = new TreeMap&lt;String, CompressionCodec&gt;();<br/>List&lt;Class&lt;? extends CompressionCodec&gt;&gt; codecClasses = getCodecClasses(conf);<br/>if (codecClasses == null) {<br/> addCodec(new GzipCodec());<br/> addCodec(new DefaultCodec()); <br/>} else {<br/> Iterator&lt;Class&lt;? extends CompressionCodec&gt;&gt; itr = codecClasses.iterator();<br/> while (itr.hasNext()) {<br/> CompressionCodec codec = ReflectionUtils.newInstance(itr.next(), conf);<br/> addCodec(codec); <br/> }<br/>}<br/>}</code><p>看样子从配置文件里,拿不到编码相关的配置,就会默认把GzipCodec,DefaultCodec加进去。再跟到getCodecClasses(conf)函数里去:</p><code>/**<br/>* Get the list of codecs listed in the configuration<br/>* @param conf the configuration to look in<br/>* @return a list of the Configuration classes or null if the attribute<br/>* was not set<br/>*/<br/>public static List&lt;Class&lt;? extends CompressionCodec&gt;&gt; getCodecClasses(Configuration conf) {<br/>String codecsString = conf.get(&quot;io.compression.codecs&quot;);<br/> if (codecsString != null) {<br/> List&lt;Class&lt;? extends CompressionCodec&gt;&gt; result = new ArrayList&lt;Class&lt;? extends CompressionCodec&gt;&gt;();<br/> StringTokenizer codecSplit = new StringTokenizer(codecsString, &quot;,&quot;);<br/> while (codecSplit.hasMoreElements()) {<br/> String codecSubstring = codecSplit.nextToken();<br/> if (codecSubstring.length() != 0) {<br/> try {<br/> Class&lt;?&gt; cls = conf.getClassByName(codecSubstring);<br/> if (!CompressionCodec.class.isAssignableFrom(cls)) {<br/> throw new IllegalArgumentException(&quot;Class &quot; + codecSubstring +<br/> &quot; is not a CompressionCodec&quot;);<br/> }<br/> result.add(cls.asSubclass(CompressionCodec.class));<br/> } catch (ClassNotFoundException ex) {<br/> throw new IllegalArgumentException(&quot;Compression codec &quot; + <br/> codecSubstring + &quot; not found.&quot;,<br/> ex);<br/> }<br/> }<br/> }<br/> return result;<br/>} else {<br/> return null;<br/>}<br/>}</code><p>从这个函数里能够看到编码的配置是 <strong>io.compression.codecs</strong> 。可以看到,我们必须返回非null的result,那么直接让io.compression.codecs配置成空,应该就可以了,此时返回的result里面没有任何元素。</p><p><strong>问题解决方案:</strong></p><p>试了一把,执行这个MapReduce程序时,加上 <strong>-Dio.compression.codecs=,</strong> 的参数,就可以了:</p><code>hadoop jar ./dumptools-0.1.jarddump.tools.mr.Grep -Dio.compression.codecs=, &quot;adgroupId=319356697&quot; doc val</code><img src="http://counter.cnblogs.com/blog/rss/4046860" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/Jack47/p/read-gz-suffix-text-file-in-mapreduce.html" target="_blank">如何让Hadoop读取以gz结尾的文本格式的文件</a>,转载请注明。</p>http://www.cnblogs.com/myprogram/p/4046734.html使用SharePoint CSOM 编写高效的程序 - 独上高楼上一篇文章中简单的介绍了使用CSOM进行编程。今天主要讲一下CSOM使用中一些小技巧,可以让你的程序运行的更快。单独加载某些属性在上文中的例子,需要返回Web对象信息的时候,我们使用了如下的代码:var web= clientContext.Web;clientContext.Load(web);/...2014-10-23T12:45:00Z2014-10-23T12:45:00Z独上高楼http://www.cnblogs.com/myprogram/<p><a href="http://www.cnblogs.com/myprogram/p/3997096.html" target="_blank">上一篇文章</a>中简单的介绍了使用CSOM进行编程。今天主要讲一下CSOM使用中一些小技巧,可以让你的程序运行的更快。</p><p><strong>单独加载某些属性</strong></p><p>在上文中的例子,需要返回Web对象信息的时候,我们使用了如下的代码:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">var</span> web=<span style="color: #000000;"> clientContext.Web;<br/>clientContext.Load(web);</span><span style="color: #008000;">//</span><span style="color: #008000;">设置查询信息</span></div><p>进行查询Web的信息,这时候,Web会返回很多属性,很多是我们不需要的,如果我们只需要返回某些属性的时候,我们可以使用如下的方式:&nbsp;</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">var</span> currentWeb =<span style="color: #000000;"> clientContext.Web;<br/>clientContext.Load(currentWeb, web </span>=&gt; web.Title, web =&gt; web.Url, web =&gt;<span style="color: #000000;"> web.WebTemplate);<br/>clientContext.ExecuteQuery();</span></div><p>这时候返回的报文变成了如下格式:</p><p><img src="http://images.cnitblog.com/blog/147759/201410/232034409803933.png" alt="" /></p><p>我们可以看到报文格式中,只返回了我们需要的属性。</p><p>以上两种情况下对比,返回的Respone长度分别是1200 和500,因此在网络吞吐有限的情况下,尽量少的返回查询属性,对于效率的提升有很重要的作用。</p><p><strong>集合属性的查询</strong></p><p>CSOM如何处理集合信息的查询呢,比如获取web下所有的list信息,我们可以:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #000000;">clientContext.Load(currentWeb.Lists);<br/>clientContext.ExecuteQuery();</span></div><p>&nbsp;这时候,每一个list的所有信息都会返回来,如果我们只想回去某个list的Title和BaseTemplate,那么我们只需要:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">var</span> currentWeb =<span style="color: #000000;"> clientContext.Web;<br/>clientContext.Load(currentWeb.Lists, lists </span>=&gt; lists.Include(list =&gt; list.Title, list =&gt; list.BaseTemplate));</div><p>或者可以使用:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">clientContext.LoadQuery(currentWeb.Lists.Include(list =&gt; list.Title, list =&gt;<span style="color: #000000;"> list.BaseTemplate));<br/>clientContext.ExecuteQuery();</span></div><p>&nbsp;这两种情况下,在一个有25个list的Web中,Response的报文长度分别是38963 和8172,因此在加载集合的时候,选择合适的查询条件对性能的影响至关重要。</p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046734" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/myprogram/p/4046734.html" target="_blank">使用SharePoint CSOM 编写高效的程序</a>,转载请注明。</p>http://www.cnblogs.com/index-html/p/mitm-cookie-sniffer.html沉默中的狂怒 —— Cookie 大喷发 - EtherDream在公共的网络里,只浏览网页不登陆就没事了吗?一个小小的中间人攻击器,可以让你打开页面的瞬间,众多账号被黑客所控制。2014-10-23T11:58:00Z2014-10-23T11:58:00ZEtherDreamhttp://www.cnblogs.com/index-html/<p><strong>前言</strong></p><p><a href="http://www.cnblogs.com/index-html/p/ssl-frontend-hijack.html">上一篇文章</a> 讲解了如何借助前端技术,打造一个比 SSLStrip 更高大上的工具。</p><p>今天我们再次使用这套战术,通过前后端的里应外合,实现一个杀手锏级的攻击方案 —— Cookie 数据大喷发。</p><p><strong>传统嗅探</strong></p><p>在过去,Cookie 的窃取大多通过嗅探流量来实现。</p><p>这种方法具有很强的隐蔽性,让人几乎难以察觉。然而,正因为如此,也面临一个巨大的缺陷:速度太过缓慢。</p><p>中间人只能嗅探到用户正在访问的页面,对于那些令人期待的网站,只能默默期待了。在家庭、办公场所这些稳定的网络环境里,长久的等待或许还能得到想要的结果;但对于公共场所上网的用户,就没那么容易了。</p><p>在公共网络里,大家多少保持一些警惕,很少会去访问一些重要的网站。况且,临时的网络用户也不会停留太久。因此纯粹的流量嗅探,难以捕捉到更有意义的数据。</p><p><strong>前端出击</strong></p><p>既然用户不按我们的套路出牌,那么我们的前端战术就得派上用场了 —— 只要能控制页面,一切皆可由我们做主。哪怕用户就是不中圈套,我们的脚本也可以强制跳转过去,从而轻易拿下想要的 Cookie 数据。</p><p>不过强制跳转的方式也太过暴力了。尽管我们使用了劫持页面这种高调的方式,但之后的所作所为,仍需保持隐蔽。</p><p>也许你会说可以通过<strong>隐藏框架页</strong>来代替,就可大幅提升隐蔽性了。这个方式确实不错,离我们的目标又近了一步,但仍然不够完美。为什么非得用访问页面的方式来获取 Cookie,这代价不免也太大了。</p><p>事实上,Cookie 的发送和请求类型是没有任何关系的。无论是页面的访问、还是第三方资源的加载,只要目标 URL 匹配了 Cookie 数据库的路径,符合的记录最终都会被带上。或许你平时并没有注意到这一点,但我们可以马上来验证下。</p><p>我们先在页面里,发起一个第三方的资源请求:</p><p><img src="http://images.cnitblog.com/blog/273626/201410/231951051214294.jpg" /></p><p>抓到请求包,自然就获得了其中的 Cookie:</p><p><img src="http://images.cnitblog.com/blog/273626/201410/231951178084383.png" /></p><p>但这些数据究竟是不是完整的,能否直接利用?不多猜测,我们把它粘到其他浏览器里试试:</p><p><img src="http://images.cnitblog.com/blog/273626/201410/231951273406504.jpg" /></p><p>当我们再次刷新页面时,奇迹发生了:</p><p><img src="http://images.cnitblog.com/blog/273626/201410/231951367773356.jpg" /></p><p>通过 Cookie,我们成功还原了之前的登录状态。而这一切,仅仅从一个第三方的图片请求中获得!</p><p>所以,中间人可以使用非常轻量的方式,来获取某个站点下的 Cookie。</p><p>我们可以事先收集大量的网站地址,让前端间谍进行逐一侦探,从而能嗅探到相当一部分账号了:</p><p><img src="http://images.cnitblog.com/blog/273626/201410/231953135581955.png" /></p><p><strong>方案优化</strong></p><p>前后端结合战术,在此又一次得到了展现。但为了能将其发挥到淋漓尽致,我们还需进行充分优化。</p><p><strong>路径标记</strong></p><p>虽然我们可以通过加载第三方资源的方式,将目标站点的 Cookie 送到流量上。但中间人收到请求后又该如何处理?返回空白内容,还是代理正常页面?</p><p>如果真走一遍代理,那实在是太浪费了。既然我们已得到 Cookie,随便返回什么都可以;但若返回空内容,要是用户正好打开这个网站,那就白屏了。</p><p>为了不影响 Cookie 的发送,同时能让中间人明白这个请求是咱们自己人的,我们在请求的 URL 里加上一个特殊的标记。</p><p>当中间人发现请求带有这个暗号,自然就明白了 —— 记录下其中携带的情报,然后放心的返回空白就可以了。</p><p><img src="http://images.cnitblog.com/blog/273626/201410/231954284966528.png" /></p><p>因为 Cookie 的 <code>Path</code> 属性不包括 Query,所以加上这个记号,并不影响 Cookie 的携带。原来有哪些,现在仍一样。</p><p>此外,修改了路径还有另一个好处:<strong>即使侦探被缓存了的站点,也能产生请求流量</strong>。从而不错过任何一个目标!</p><h3 id="dns-">DNS 加速</strong></p><p>解决了代理问题,发送 Cookie 现在只需极小的流量。</p><p>这时的瓶颈,已不仅仅是 HTTP 流量了。因为我们事先准备了大量的网站,他们都有各自的域名,因此 DNS 查询也成为不可忽视的一部分。</p><p>为了缩短查询时间,我们可以将所有发往 UDP/53 的数据包,全转发到中间人的 DNS 服务下,并且都解析成自己的 IP。这样不仅加快域名查询的过程,而且还能给中间人节省不少带宽。</p><p>当然,如今的浏览器,对域名解析做了大量的优化。因此在前端上,速度提升或许并不明显。</p><p>但这种方式仍有极大的意义 —— 我们同时劫持了 DNS 和 HTTP,这意味着整套方案,可以不依赖互联网,进行离线攻击!这尤其适用于上网成本较高的户外环境里。</p><p><strong>痕迹收集</strong></p><p>当然,并不是所有账号都得通过 Cookie 成功还原的。稍微重视安全的网站,其登录会话都绑定了 IP 地址段。如果还原时的外网 IP,和用户之前使用的存在较大区别,这个 Cookie 很有可能就失效了。</p><p>但大多数时候,我们劫持的都是附近的用户,甚至是同一内网的,所以仍有不少能够还原的。</p><p>但随着安全等级的提高,一些网站不仅仅绑定 IP 地址,有的还关联了 User-Agent 等信息。在将来,甚至还会绑定用户更多的痕迹,例如屏幕分辨率、插件版本、绘图算法等等,更精确的识别用户。</p><p>为了能提高还原成功率,我们也尽可能多的收集用户信息。除了 User-Agent,我们还可以考虑通过前端代码,收集更详细的浏览器特征信息。在账号还原时,把这些信息都模拟到沙盒里,伪装到天衣无缝。</p><p><strong>攻击演示</strong></p><p>Demo: <a href="https://github.com/EtherDream/cookie_hijack_demo"><a href="https://github.com/EtherDream/cookie_hijack_demo">https://github.com/EtherDream/cookie_hijack_demo</a></a></p><p>当然,这里只演示最基本的功能,将嗅探到的 Cookie 保存在文件里。至于如何还原,有无数种方式,这里就不再介绍了。</p><img src="http://counter.cnblogs.com/blog/rss/4046677" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/index-html/p/mitm-cookie-sniffer.html" target="_blank">沉默中的狂怒 —— Cookie 大喷发</a>,转载请注明。</p>http://www.cnblogs.com/grass-and-moon/p/4046668.html基本概念----Beginning Visual C# - grass of moon更多相关文章,见本人的个人主页:zhongxiewei.com变量注释方式:// 注释在这里和/* 注释在这里 */整形变量的类型:TypeAlias forAllowed ValuessbyteSystem.SByteInteger between -2^7 and 2^7-1byteSystem...2014-10-23T11:54:00Z2014-10-23T11:54:00Zgrass of moonhttp://www.cnblogs.com/grass-and-moon/<p><strong><span style="font-size: 15px;">更多相关文章,见本人的个人主页:<a title="zhongxiewei.com" href="http://www.cnblogs.com/zhongxiewei.com" target="_blank">zhongxiewei.com</a></span></strong></p><h1 id="变量">变量</strong></p><p>注释方式:<code>// 注释在这里</code>和<code>/* 注释在这里 */</code></p><p>整形变量的类型:</p><table><thead><tr class="header"><th align="left">Type</th><th align="center">Alias for</th><th align="center">Allowed Values</th></tr></thead><tbody><tr class="odd"><td align="left">sbyte</td><td align="center">System.SByte</td><td align="center">Integer between -2^7 and 2^7-1</td></tr><tr class="even"><td align="left">byte</td><td align="center">System.Byte</td><td align="center">Integer between 0 and 2^8-1</td></tr><tr class="odd"><td align="left">short</td><td align="center">System.Int16</td><td align="center">Integer between -2^15 and 2^15-1</td></tr><tr class="even"><td align="left">ushort</td><td align="center">System.UInt16</td><td align="center">Integer between 0 and 2^16-1</td></tr><tr class="odd"><td align="left">int</td><td align="center">System.Int32</td><td align="center">Integer between -2^31 and 2^31-1</td></tr><tr class="even"><td align="left">uint</td><td align="center">System.UInt32</td><td align="center">Integer between 0 and 2^32-1</td></tr><tr class="odd"><td align="left">long</td><td align="center">System.Int64</td><td align="center">Integer between -2^63 and 2^63-1</td></tr><tr class="even"><td align="left">ulong</td><td align="center">System.UInt64</td><td align="center">Integer between 0 and 2^64-1</td></tr></tbody></table><p>浮点型:</p><table><thead><tr class="header"><th align="center">Type</th><th align="left">Alias for</th><th align="left">Approx Min Value</th><th align="left">Approx Max Value</th></tr></thead><tbody><tr class="odd"><td align="center">float</td><td align="left">System.Single</td><td align="left"><span class="LaTeX"> <span class="inlinemath">1.5x10-45 </span></span></td><td align="left"><span class="LaTeX"> <span class="inlinemath">3.4x1038 </span></span></td></tr><tr class="even"><td align="center">double</td><td align="left">System.Double</td><td align="left"><span class="LaTeX"> <span class="inlinemath">5.0x10-324 </span></span></td><td align="left"><span class="LaTeX"> <span class="inlinemath">1.7x10308 </span></span></td></tr><tr class="odd"><td align="center">decimal</td><td align="left">System.Decimal</td><td align="left"><span class="LaTeX"> <span class="inlinemath">1.0x10-28 </span></span></td><td align="left"><span class="LaTeX"> <span class="inlinemath">7.9x1028 </span></span></td></tr></tbody></table><p>其他简单类型:</p><table><thead><tr class="header"><th align="left">Type</th><th align="left">Alias for</th><th align="left">Allowed Values</th></tr></thead><tbody><tr class="odd"><td align="left">char</td><td align="left">System.Char</td><td align="left">Single Unicode char, between 0 and 65535</td></tr><tr class="even"><td align="left">bool</td><td align="left">System.Boolean</td><td align="left">true or false</td></tr><tr class="odd"><td align="left">string</td><td align="left">System.String</td><td align="left">a sequence of characters</td></tr></tbody></table><p>关于变量命名:</p><p>对于简单的变量可以采用camelCase格式,如:firstName,对于一些高级的变量可以采用PascalCase格式,如LastName,这是微软建议的。</p><p>字面常量:</p><p>true, false, 100, 100U, 100L, 100UL, 1.5F, 1.5, 1.5M, 'a', "hello"</p><p>verbatim, 逐字的常量:</p><p><code>"C:\\Temp\\mydir\\myfile.doc"</code>等同于<code>@"C:\Temp\mydir\myfile.doc"</code>,另外可以跨行输入字符串,如:</p><code>@"first line<br/>second line<br/>third line"</code><p>关于变量的使用,在很多变成语言中都有一个要求,就是<strong>在使用前必须进行初始化</strong>。</p><h1 id="表达式">表达式</strong></p><p>操作符与C语言类似</p><p>操作符的顺序:</p><table><thead><tr class="header"><th align="left">Precedence</th><th align="left">Operators</th></tr></thead><tbody><tr class="odd"><td align="left">Highest</td><td align="left">++, --(used as prefixes); (), +, -(unary), !, ~</td></tr><tr class="even"><td align="left">&nbsp;</td><td align="left">*,/,%</td></tr><tr class="odd"><td align="left">&nbsp;</td><td align="left">+,-</td></tr><tr class="even"><td align="left">&nbsp;</td><td align="left">&lt;&lt;, &gt;&gt;</td></tr><tr class="odd"><td align="left">&nbsp;</td><td align="left">&lt;,&gt;,&lt;=,&gt;=</td></tr><tr class="even"><td align="left">&nbsp;</td><td align="left">==,!=</td></tr><tr class="odd"><td align="left">&nbsp;</td><td align="left">&amp;</td></tr><tr class="even"><td align="left">&nbsp;</td><td align="left">^</td></tr><tr class="odd"><td align="left">&nbsp;</td><td align="left">|</td></tr><tr class="even"><td align="left">&nbsp;</td><td align="left">&amp;&amp;</td></tr><tr class="odd"><td align="left">&nbsp;</td><td align="left">||</td></tr><tr class="even"><td align="left">&nbsp;</td><td align="left">=,*=,/=,%=,+=,-=,&lt;&lt;=,&gt;&gt;=,&amp;=,^=,|=</td></tr><tr class="odd"><td align="left">Lowest</td><td align="left">++,--(used as suffixes)</td></tr></tbody></table><h1 id="控制流">控制流</strong></p><p>允许使用goto语句。条件表达式返回的类型必须是<code>bool</code>。如: <code>if (10) return false; // 这句话是不能通过编译的</code></p><p>在使用switch-case的时候,有一点和c++的用法是不同的,如:</p><code>switch(testVar)<br/>{<br/> case var1:<br/> // execute code<br/> ... // 如果这里没有break语句的话,编译器是不能通过的,而在c++中可以,<br/> // 如果想要让它继续执行下面的case,必须加上&ldquo;goto case var2;&rdquo;语句<br/> // 当然如果case var1下面没有执行语句的话,也是合理的<br/> case var2:<br/> // execute code<br/> ...<br/> break;<br/> default:<br/> break;<br/>}</code><p>循环语句和C++类似</p><h1 id="更多变量相关">更多变量相关</strong></p><h2 id="类型转换">类型转换</strong></p><table><thead><tr class="header"><th align="left">Type</th><th align="left">Can safely be converted to</th></tr></thead><tbody><tr class="odd"><td align="left">byte</td><td align="left">short,ushort,int,uint,long,ulong,float,double,decimal</td></tr><tr class="even"><td align="left">sbyte</td><td align="left">short,int,long,float,double,decimal</td></tr><tr class="odd"><td align="left">short</td><td align="left">int,long,float,double,decimal</td></tr><tr class="even"><td align="left">ushort</td><td align="left">int,uint,long,ulong,float,double,decimal</td></tr><tr class="odd"><td align="left">int</td><td align="left">long,float,double,decimal</td></tr><tr class="even"><td align="left">uint</td><td align="left">long,ulong,float,double,decimal</td></tr><tr class="odd"><td align="left">long</td><td align="left">float,double,decimal</td></tr><tr class="even"><td align="left">ulong</td><td align="left">float,double,decimal</td></tr><tr class="odd"><td align="left">float</td><td align="left">double</td></tr><tr class="even"><td align="left">char</td><td align="left">ushort,int,uint,long,ulong,float,double,decimal</td></tr></tbody></table><p>除了以上的隐式转换之外,还存在显示转换。为了防止溢出发生,可以用<code>checked(expression)</code>表达式进行处理,如:</p><code>byte destVar;<br/>short srcVar = 281;<br/>destVar = checked((byte)srcVar);</code><p>或是在项目的选项中,直接开启默认转换检测机制。如下图所示:</p><div class="figure"><img src="http://www.zhongxiewei.com/images/monochecked.png" alt="" /></div><h2 id="一些复杂的变量类型">一些复杂的变量类型</strong></p><h3 id="enumeration">Enumeration</strong></p><p>定义一个enum,如下:</p><code>enum orientation : byte // byte能够被其他的整型类型,如int,long等替换<br/>{<br/> north,<br/> south,<br/> east,<br/> west<br/>}</code><p>那么声明一个枚举类型采用的方法为:<code>orientation myDirect = orientation.north;</code>;直接输出myDirect的结果为:<code>north</code>。想要输出它所表示的byte类型的具体数值,就必须采用显示的类型转换:<code>(byte)myDirect</code>。</p><p>也可以将&ldquo;north&rdquo;字符串转换成枚举类型,采用的方式稍微复杂,具体如下:</p><code>string myStr = "north";<br/>orientation myDirect = (orientation)Enum.Parse(typeof(orientation), myStr);</code><h3 id="struct">struct</strong></p><p>struct类型和C++不同的是,变量的类型默认不是public的。而是private的。</p><h3 id="arrays">Arrays</strong></p><p>数组的声明方式如下:<code>&lt;baseType&gt;[] &lt;name&gt;;</code>,如:<code>int[] myIntArray = {1,2,3};</code>,<code>int[] myIntArray = new int[5];</code>。不能够采用如下的方式进行声明:<code>&lt;baseType&gt; &lt;name&gt;[];</code></p><p>多维数组的语法结构也有其特殊性。声明方式如下:<code>&lt;baseType&gt;[,] &lt;name&gt;;</code>,如:<code>double[,] hillHeight = new double[3,4];</code>。在多维数组中各个数据的排序顺序为行优先排序,如:</p><code>double[,] hillHeight = {{1,2,3,4}, {2,3,4,5}, {3,4,5,6}};<br/>foreach (double height in hillHeight)<br/>{<br/> Console.WriteLine("{0}", height);<br/>}<br/>// 输出结果依次为:<br/>// [0,0]<br/>// [0,1]<br/>// ...</code><p>在当每一行的数据量不相等的时候,可以使用Arrays of Arrays。在使用数组的数组的时候,不能像多维数组一样进行使用,如:</p><code>int[][] jagged;<br/>jagged = new int[3][4]; // 在编译的过程中会出现&rsquo;cannot implicitly convert type 'int' to 'int[][]'的错误</code><p>有两种方式可以用来实现声明。如:</p><code>jagged = new int[2][];<br/>jagged[0] = new int[3];<br/>jagged[1] = new int[4];<br/><br/>// or like below<br/>jagged = {new int[] {1,2,3}, new int[] {1}, new int[] {4,5,6,7}};</code><p>在对其进行遍历的时候也需要注意,不能采用如下的方式:</p><code>foreach (int val in jagged) // 出现编译错误,不能将int[]转换成int<br/>{<br/> Console.WriteLine(val);<br/>}<br/><br/>// 于是应该更改为如下方式:<br/><br/>foreach (int[] valArray in jagged)<br/>{<br/> foreach (int val in valArray)<br/> {<br/> Console.WriteLine(val);<br/> }<br/>}</code><h2 id="对string的操作">对String的操作</strong></p><p><code>string str=" hello world ";</code>常见的有: <code>str.Trim();</code>,<code>str.TrimStart()</code>,<code>str.TrimEnd()</code>,<code>str.ToLower()</code>,<code>str.PadLeft(10, '-')</code>,<code>str.Split({' '})</code></p><h2 id="练习">练习</strong></p><ol style="list-style-type: decimal;"><li>逆序输出字符串,递归的方式完成</li></ol><code>public static void printReverse(string str, int i)<br/>{<br/> if (i &lt; str.Length)<br/> {<br/> printReverse(str, i + 1);<br/> Console.Write(str.Substring(i, 1));<br/> }<br/><br/> return;<br/>}</code><img src="http://counter.cnblogs.com/blog/rss/4046668" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/grass-and-moon/p/4046668.html" target="_blank">基本概念----Beginning Visual C#</a>,转载请注明。</p>http://www.cnblogs.com/me-sa/p/term_sharing_in_erlang_otp_one.html[Erlang 0127] Term sharing in Erlang/OTP 上篇 - 坚强2002之前,在 [Erlang 0126] 我们读过的Erlang论文提到过下面这篇论文:On Preserving Term Sharing in the Erlang Virtual Machine地址:http://user.it.uu.se/~kostis/Papers/erlang12_shar...2014-10-23T11:32:00Z2014-10-23T11:32:00Z坚强2002http://www.cnblogs.com/me-sa/<p>之前,在 <a href="http://www.cnblogs.com/me-sa/p/best_thing_i_met.html"><span style="text-decoration: underline;">[Erlang 0126] 我们读过的Erlang论文</span></a>&nbsp;提到过下面这篇论文:&nbsp;<br /><br /><strong>On Preserving Term Sharing in the Erlang Virtual Machine</strong><br />地址:&nbsp;<a href="http://user.it.uu.se/~kostis/Papers/erlang12_sharing.pdf"><span style="text-decoration: underline;">http://user.it.uu.se/~kostis/Papers/erlang12_sharing.pdf</span></a>&nbsp;<br />摘要:In this paper we describe our experiences and argue through examples why ?attening terms during copying is not a good idea for<br />a language like Erlang. More importantly, we propose a sharing&nbsp;preserving copying mechanism for Erlang/OTP and describe a pub-<br />licly available complete implementation of this mechanism.&nbsp;<br /><br />&nbsp; &nbsp;Term Sharing &nbsp;数据项共享这个东西不新鲜,"Efficiency Guide User's Guide"的4.2章节"Constructing binaries"[ <a href="http://www.erlang.org/doc/efficiency_guide/binaryhandling.html"><span style="text-decoration: underline;">链接</span></a> ] 和 8.2 章节的"Loss of sharing"&nbsp;[<a href="http://www.erlang.org/doc/efficiency_guide/processes.html"><span style="text-decoration: underline;">链接</span></a>]就提到过(再次吐槽一下Erlang文档组织,一个主题往往分散在多个文档里面,需要耐心).不仅仅是Binary数据类型,Term Sharing 是一个通用的问题.在Guide中提到了强制拷贝的场景:发送到别的进程或者插入到ETS. 下面是文档摘抄的:</p><blockquote><p>&nbsp; &nbsp;<strong>Loss of sharing</strong><br />&nbsp;&nbsp;<br />&nbsp; Shared sub-terms are not preserved when a term is sent to&nbsp;another process, passed as the initial process arguments&nbsp;in the spawn call, or stored in an ETS table. That is an&nbsp;optimization. Most applications do not send messages with&nbsp;shared sub-terms.</p></blockquote><p>&nbsp;</p><p>&nbsp; &nbsp;数据拷贝过程,Erlang会进行两次遍历.第一次遍历,会计算flat size(erts/emulator/beam/copy.c中的size_object&nbsp;方法)然后为此分配对应的内存,第二次遍历完成实际的拷贝&nbsp;(function copy_structin erts/emulator/beam/copy.c).<br /><br />首先,我们写一个简单的代码演示一下后面要频繁用到的erts_debug:size/1和erts_debug:flat_size/1</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">s3(L)-&gt;<br/> L2=[L,L,L,L],<br/> {{erts_debug:size(L),erts_debug:flat_size(L)},<br/> {erts_debug:size(L2),erts_debug:flat_size(L2)}}<br/>.<br/><br/>9&gt; d:s3([1,2,3,4,5,6]).<br/>{{12,12},{20,56}}<br/></div><p>  下面在shell这段代码,分别演示了spawn,消息发送,以及插入ETS.</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">Eshell V6.0 (abort with ^G)<br/>1&gt; L=[1,2,3,4,5,6,7,8,9,10].<br/>[1,2,3,4,5,6,7,8,9,10]<br/>2&gt; L2=[L,L,L,L,L,L].<br/>[[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10]]<br/>3&gt; erts_debug:size(L2).<br/>32<br/>4&gt; erts_debug:flat_size(L2).<br/>132<br/>5&gt; spawn(fun () -&gt;receive Data -&gt; io:format("~p",[erts_debug:size(Data)]) end end).<br/>&lt;0.39.0&gt;<br/>6&gt; v(5) ! L2.<br/>132[[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10]]<br/>7&gt; erts_debug:size(L2).<br/>32<br/>8&gt; ets:new(test,[named_table]).<br/>test<br/>9&gt; ets:insert(test,{1,L2}).<br/>true<br/>10&gt; ets:lookup(test ,1).<br/>[{1,<br/> [[1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10]]}]<br/>11&gt; [{1,Data}]=v(10).<br/>[{1,<br/> [[1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10],<br/> [1,2,3,4,5,6,7,8,9,10]]}]<br/>12&gt; Data.<br/>[[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10],<br/>[1,2,3,4,5,6,7,8,9,10]]<br/>13&gt; erts_debug:size(Data).<br/>132<br/>14&gt; spawn(d,test,[L2]).<br/>132&lt;0.54.0&gt;<br/><br/> test(Data)-&gt;<br/> io:format("~p",[erts_debug:size(Data)]).<br/><br/> <br/></div><p>  除了上面的情况,还有一些潜在的情况也会导致数据展开,比如上面提到的论文里面设计的例子:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">show_printing_may_be_bad() -&gt;<br/> F = fun (N) -&gt;<br/> T = now(),<br/> L = mklist(N),<br/> S = erts_debug:size(L),<br/> io:format("mklist(~w), size ~w, ", [N, S]),<br/> io:format("is ~P, ", [L, 2]), %%% BAD !!!<br/> D = timer:now_diff(now(), T),<br/> io:format("in ~.3f sec.~n", [D/1000000])<br/> end,<br/> lists:foreach(F, [10, 20, 22, 24, 26, 28, 30]).<br/><br/>mklist(0) -&gt; 0;<br/>mklist(M) -&gt; X = mklist(M-1), [X, X].<br/></div><p>  io:format("is ~P, ", [L, 2]), %%% BAD !!!这行代码删掉前后分别执行代码,在过机器上得到的结果如下:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">Eshell V6.0 (abort with ^G)<br/>1&gt; d:show_printing_may_be_bad().<br/>mklist(10), size 40, in 0.001 sec.<br/>mklist(20), size 80, in 0.000 sec.<br/>mklist(22), size 88, in 0.000 sec.<br/>mklist(24), size 96, in 0.000 sec.<br/>mklist(26), size 104, in 0.000 sec.<br/>mklist(28), size 112, in 0.000 sec.<br/>mklist(30), size 120, in 0.000 sec.<br/>ok<br/><br/><br/>Eshell V6.0 (abort with ^G)<br/>1&gt; d:show_printing_may_be_bad().<br/>mklist(10), size 40, is [[...]|...], in 0.001 sec.<br/>mklist(20), size 80, is [[...]|...], in 0.110 sec.<br/>mklist(22), size 88, is [[...]|...], in 0.421 sec.<br/>mklist(24), size 96, is [[...]|...], in 43.105 sec.<br/>mklist(26), size 104, <br/>Crash dump was written to: erl_crash.dump<br/>eheap_alloc: Cannot allocate 3280272216 bytes of memory (of type "heap").<br/>rlwrap: warning: erl killed by SIGABRT.<br/>rlwrap has not crashed, but for transparency,<br/>it will now kill itself (without dumping core)with the same signal<br/></div><p>&nbsp; &nbsp;很明显看到有这行代码的版本不仅执行时间长,而且需要大量内存.<br /><br />&nbsp; &nbsp;为什么会出现这种情况呢?就是上面提到的"Loss of sharing",为什么会触发数据展开(或者说数据平铺化)呢?之前我们曾经聊过关于io:format的事情( [Erlang 0041] 详解io:format [<a href="http://www.cnblogs.com/me-sa/archive/2012/02/26/erlang0041.html"><span style="text-decoration: underline;">链接</span></a>]),在Erlang/OTP中I/O是通过向I/O Server发起I/O请求实现的.io:format调用实际上是向I/O 发送了一个io request消息,剩下的就由IO Server处理了.虽然上面的L被简略的输出为"&nbsp;[[...]|...]"但是在消息的传递过程中已经触发了数据平铺然后拷贝;<br /><br />&nbsp; &nbsp;这种问题实际上是非常隐蔽的,所以通过宏选项在release生成的时候清理掉所有io:format输出是非常有必要的;&nbsp;</p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046623" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/me-sa/p/term_sharing_in_erlang_otp_one.html" target="_blank">[Erlang 0127] Term sharing in Erlang/OTP 上篇</a>,转载请注明。</p>http://www.cnblogs.com/leocook/p/mq_rabbitmq_6.htmlRabbitMQ系列 第七篇:RCP(远程过程调用协议) - leocook在http://www.cnblogs.com/leocook/p/mq_rabbitmq_2.html 这篇博文中我们实现了怎么去使用work queue来把比较耗时的任务分散给多个worker。但是,如果我们想在远程的机器上的一个函数并等待它返回结果,我们应该怎么办呢?这就是另外一种模式了,它被...2014-10-23T10:31:00Z2014-10-23T10:31:00Zleocookhttp://www.cnblogs.com/leocook/<p>在<a href="http://www.cnblogs.com/leocook/p/mq_rabbitmq_2.html">http://www.cnblogs.com/leocook/p/mq_rabbitmq_2.html</a> 这篇博文中我们实现了怎么去使用work queue来把比较耗时的任务分散给多个worker。</p><p>但是,如果我们想在远程的机器上的一个函数并等待它返回结果,我们应该怎么办呢?这就是另外一种模式了,它被称为RPC(Remote procedure call)。</p><p>本篇博文中我们来实现怎么用RabbitMQ来构建一个RPC系统:一个client(客户端)和一个可扩展的RPC server(服务端)。这里我们来模拟一个返回斐波拉契数的RPC服务。</p><p><strong>1、Client端接口</strong></p><p>为了说明一个RPC服务时怎么工作的,我们来创建一个简单的client类。这里来实现一个名字为call的方法来发送RPC请求,并发生阻塞,直到接收到回复:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">FibonacciRpcClient fibonacciRpc = <span style="color: #0000ff;">new</span><span style="color: #000000;"> FibonacciRpcClient(); <br/>String result </span>= fibonacciRpc.call(<span style="color: #800000;">"</span><span style="color: #800000;">4</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/>System.</span><span style="color: #0000ff;">out</span>.println( <span style="color: #800000;">"</span><span style="color: #800000;">fib(4) is </span><span style="color: #800000;">"</span> + result);</div><p><span style="background-color: #cfcfcf;"><strong>RPC</strong><strong>注意事项:</strong></span></p><p><span style="background-color: #cfcfcf;">虽然RPC是一种常用的模式,但它也有一些缺陷。当无法确定使用本地调用还是使用RPC时,问题就出来了。有的时候不确定程序的运行环境,这样来做会给程序的调试增加了一定的复杂度。使用RPC并不能够让代码变得更简洁,滥用的话只会让代码变得更不方便维护。</span></p><p><span style="background-color: #cfcfcf;">伴随着上边的问题,咱们来看看下边的建议:</span></p><ul><li><span style="background-color: #cfcfcf;">确定能很明显的分辨的出哪些调用是本地调用,哪些是远程调用。</span></li><li><span style="background-color: #cfcfcf;">完善系统的文档。清楚的标记出,模块间的依赖关系。</span></li><li><span style="background-color: #cfcfcf;">处理错误情况。当RPC服务挂了之后,客户端应该怎么去处理呢?</span></li></ul><p><span style="background-color: #cfcfcf;">当有疑问时避免使用RPC。如果可以的话,你可以使用异步管道(不用RPC-阻塞),结果被异步推送到下一个计算环节。</span></p><p><strong>2、回调队列(Callback queue)</strong></p><p>一般用RabbitMQ来实现RPC是很简单的。客户端发送一个请求消息然后服务器端回应一个响应消息。为了接收服务端的响应消息,我们需要在请求中发送一个callback queue地址。我们也可以使用一个默认的queue(Java客户端独有的)。如下:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">callbackQueueName =<span style="color: #000000;"> channel.queueDeclare().getQueue();<br/><br/></span><span style="color: #008000;">//</span><span style="color: #008000;">绑定callback queue</span><br/>BasicProperties props = <span style="color: #0000ff;">new</span><span style="color: #000000;"> BasicProperties.Builder().replyTo(callbackQueueName).build();<br/>channel.basicPublish(</span><span style="color: #800000;">""</span>, <span style="color: #800000;">"</span><span style="color: #800000;">rpc_queue</span><span style="color: #800000;">"</span><span style="color: #000000;">, props, message.getBytes());<br/><br/></span><span style="color: #008000;">//</span><span style="color: #008000;"> ... then code to read a response message from the callback_queue ...</span></div><p><span style="background-color: #cfcfcf;"><strong>消息属性:</strong></span></p><p><span style="background-color: #cfcfcf;">AMQP协议在发送消息时,预定义了14个属性连同消息一起发送出去。很多属性都是很少用到的,除了下边的这些:</span></p><p><span style="background-color: #cfcfcf;">消息的投递模型(deliveryMode):使消息持久化,和work queue里的设置一样。</span></p><p><span style="background-color: #cfcfcf;">上下文类型(contentType):用来描述媒体类型(mime-type)。例如常用的JSON格式,它的mime-type是application/json。</span></p><p>我们需要导包:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">import com.rabbitmq.client.AMQP.BasicProperties;</div><p><strong><span lang="EN-US">3、Correlation Id</span></strong></p><p>在上边的方法中建议我们为每个RPC请求都创建一个call queue,这样效率很低。我们有更好的办法,为每一个client创建一个call queue。</p><p>这样处理的话又出现了一个新的问题,无法确定接收到的响应是对应哪个请求的。这时候就需要correlationId属性,我们为每一个请求都设置一个correlationId属性。当我们从callback queue中接收到一条消息之后,我们将会查看correlationId属性,这样就可以用一个请求来与之匹配了。如果从callback queue接收到了一条消息后,发现其中的correlationId未能找到与之匹配的请求,那么将把这条消息丢掉。</p><p>你可能会问我们为什么要要在callback queue里忽略掉不知道的message,而不是报错呢?这是因为服务器端可能会出现的一种情况,虽然可能性很小,但还是有可能性的,有可能在RPC发送了响应之后,在发送确认完成任务的信息之前服务器重启了。如果这种情况发生了的话,重启了RPC服务之后,它将会再次接收到之前的请求,这样的话client将会重复处理响应,RPC服务应该是等幂的。</p><p><strong>4、总结</strong></p><p><img src="http://images.cnitblog.com/blog/562023/201410/231827169025276.png" alt="" /></p><p>我们的RPC工作原理如下:</p><ul><li>当Client启动时,它将会创建一个匿名的callback queue。</li><li>对于一次RPC请求,client会发送一条含有两个属性的消息:<strong>replyTo</strong>和<strong>correlationId</strong>。Reply是设置的callback queue,correlationId是设置的当前请求的标示符。</li><li>请求将会被发送到rpc_queue里。</li><li>RPC的worker(RPC server)等待queue中的请求。当出现一个请求之后,他将会处理任务,并向replyTo队列中发送消息。</li><li>客户端会等待callback queue上的消息。当消息出现时,它将会检查correlationId属性是否能与之前发送请求时的属性一直,若一致的话,client将会处理回复的消息。</li></ul><p><strong>5、最终实现</strong></p><p>斐波拉契任务:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> fib(<span style="color: #0000ff;">int</span><span style="color: #000000;"> n) throws Exception {<br/> </span><span style="color: #0000ff;">if</span> (n == <span style="color: #800080;">0</span>) <span style="color: #0000ff;">return</span> <span style="color: #800080;">0</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">if</span> (n == <span style="color: #800080;">1</span>) <span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">return</span> fib(n-<span style="color: #800080;">1</span>) + fib(n-<span style="color: #800080;">2</span><span style="color: #000000;">);<br/>}</span></div><p>这里定义计算斐波拉契数的方法,假设传进去的整数都是正整数。</p><p><strong>RPC服务端的代码实现如下RPCServer.java:</strong></p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #000000;">import com.rabbitmq.client.ConnectionFactory;<br/>import com.rabbitmq.client.Connection;<br/>import com.rabbitmq.client.Channel;<br/>import com.rabbitmq.client.QueueingConsumer;<br/>import com.rabbitmq.client.AMQP.BasicProperties;<br/> <br/></span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> RPCServer {<br/> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> final String RPC_QUEUE_NAME = <span style="color: #800000;">"</span><span style="color: #800000;">rpc_queue</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br/><br/> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> fib(<span style="color: #0000ff;">int</span><span style="color: #000000;"> n) {<br/> </span><span style="color: #0000ff;">if</span> (n ==<span style="color: #800080;">0</span>) <span style="color: #0000ff;">return</span> <span style="color: #800080;">0</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">if</span> (n == <span style="color: #800080;">1</span>) <span style="color: #0000ff;">return</span> <span style="color: #800080;">1</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">return</span> fib(n-<span style="color: #800080;">1</span>) + fib(n-<span style="color: #800080;">2</span><span style="color: #000000;">);<br/> }<br/><br/> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] argv) {<br/> Connection connection </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> Channel channel </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br/> ConnectionFactory factory </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ConnectionFactory();<br/> factory.setHost(</span><span style="color: #800000;">"</span><span style="color: #800000;">localhost</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> <br/> connection </span>=<span style="color: #000000;"> factory.newConnection();<br/> channel </span>=<span style="color: #000000;"> connection.createChannel();<br/> <br/> channel.queueDeclare(RPC_QUEUE_NAME, </span><span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> <br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">一次只接收一条消息</span><br/> channel.basicQos(<span style="color: #800080;">1</span><span style="color: #000000;">);<br/> <br/> QueueingConsumer consumer </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> QueueingConsumer(channel);<br/><br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">开启消息应答机制</span><br/> channel.basicConsume(RPC_QUEUE_NAME, <span style="color: #0000ff;">false</span><span style="color: #000000;">, consumer);<br/> System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #800000;">"</span><span style="color: #800000;"> [x] Awaiting RPC requests</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> <br/> </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">) {<br/> String response </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> <br/> QueueingConsumer.Delivery delivery </span>=<span style="color: #000000;"> consumer.nextDelivery();<br/> <br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">拿到correlationId属性</span><br/> BasicProperties props =<span style="color: #000000;"> delivery.getProperties();<br/> BasicProperties replyProps </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> BasicProperties<br/> .Builder()<br/> .correlationId(props.getCorrelationId())<br/> .build();<br/> <br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br/> String message </span>= <span style="color: #0000ff;">new</span> String(delivery.getBody(),<span style="color: #800000;">"</span><span style="color: #800000;">UTF-8</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">int</span> n =<span style="color: #000000;"> Integer.parseInt(message);<br/> <br/> System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #800000;">"</span><span style="color: #800000;"> [.] fib(</span><span style="color: #800000;">"</span> + message + <span style="color: #800000;">"</span><span style="color: #800000;">)</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> response </span>= <span style="color: #800000;">""</span> +<span style="color: #000000;"> fib(n);<br/> } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e){<br/> System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #800000;">"</span><span style="color: #800000;"> [.] </span><span style="color: #800000;">"</span> +<span style="color: #000000;"> e.toString());<br/> response </span>= <span style="color: #800000;">""</span><span style="color: #000000;">;<br/> }<br/> </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> { <br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">拿到replyQueue,并绑定为routing key,发送消息</span><br/> channel.basicPublish( <span style="color: #800000;">""</span>, props.getReplyTo(), replyProps, response.getBytes(<span style="color: #800000;">"</span><span style="color: #800000;">UTF-8</span><span style="color: #800000;">"</span><span style="color: #000000;">));<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">返回消息确认信息</span><br/> channel.basicAck(delivery.getEnvelope().getDeliveryTag(), <span style="color: #0000ff;">false</span><span style="color: #000000;">);<br/> }<br/> }<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {<br/> e.printStackTrace();<br/> }<br/> </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {<br/> </span><span style="color: #0000ff;">if</span> (connection != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br/> connection.close();<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception ignore) {}<br/> }<br/> } <br/> }<br/>}</span></div><p>服务器端代码实现很简单的:</p><ul><li>建立连接,信道,声明队列</li><li>为了能把任务压力平均的分配到各个worker上,我们在方法channel.basicQos里设置prefetchCount的值。</li><li>我们使用basicConsume来接收消息,并等待任务处理,然后发送响应。</li></ul><p><strong>RPC</strong><strong>客户端代码实现RPCClient.java</strong><strong>:</strong></p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #000000;">import com.rabbitmq.client.ConnectionFactory;<br/>import com.rabbitmq.client.Connection;<br/>import com.rabbitmq.client.Channel;<br/>import com.rabbitmq.client.QueueingConsumer;<br/>import com.rabbitmq.client.AMQP.BasicProperties;<br/>import java.util.UUID;<br/><br/></span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> RPCClient {<br/> </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> Connection connection;<br/> </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> Channel channel;<br/> </span><span style="color: #0000ff;">private</span> String requestQueueName = <span style="color: #800000;">"</span><span style="color: #800000;">rpc_queue</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> String replyQueueName;<br/> </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> QueueingConsumer consumer;<br/><br/> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> RPCClient() throws Exception {<br/> ConnectionFactory factory </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ConnectionFactory();<br/> factory.setHost(</span><span style="color: #800000;">"</span><span style="color: #800000;">localhost</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> connection </span>=<span style="color: #000000;"> factory.newConnection();<br/> channel </span>=<span style="color: #000000;"> connection.createChannel();<br/><br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">拿到一个匿名(并非整的匿名,拿到了一个随机生成的队列名)的队列,作为replyQueue。</span><br/> replyQueueName =<span style="color: #000000;"> channel.queueDeclare().getQueue(); <br/> consumer </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> QueueingConsumer(channel);<br/> channel.basicConsume(replyQueueName, </span><span style="color: #0000ff;">true</span><span style="color: #000000;">, consumer);<br/> }<br/> <br/> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String call(String message) throws Exception { <br/> String response </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> String corrId </span>= UUID.randomUUID().toString();<span style="color: #008000;">//</span><span style="color: #008000;">拿到一个UUID<br/> <br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">封装correlationId和replyQueue属性</span><br/> BasicProperties props = <span style="color: #0000ff;">new</span><span style="color: #000000;"> BasicProperties<br/> .Builder()<br/> .correlationId(corrId)<br/> .replyTo(replyQueueName)<br/> .build();<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">推消息,并加上之前封装好的属性</span><br/> channel.basicPublish(<span style="color: #800000;">""</span><span style="color: #000000;">, requestQueueName, props, message.getBytes());<br/> <br/> </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">) {<br/> QueueingConsumer.Delivery delivery </span>=<span style="color: #000000;"> consumer.nextDelivery();<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">检验correlationId是否匹配,确定是不是这次的请求</span><br/> <span style="color: #0000ff;">if</span><span style="color: #000000;"> (delivery.getProperties().getCorrelationId().equals(corrId)) {<br/> response </span>= <span style="color: #0000ff;">new</span> String(delivery.getBody(),<span style="color: #800000;">"</span><span style="color: #800000;">UTF-8</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> }<br/> }<br/><br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> response; <br/> }<br/> <br/> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> close() throws Exception {<br/> connection.close();<br/> }<br/> <br/> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] argv) {<br/> RPCClient fibonacciRpc </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> String response </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br/> fibonacciRpc </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> RPCClient();<br/> <br/> System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #800000;">"</span><span style="color: #800000;"> [x] Requesting fib(30)</span><span style="color: #800000;">"</span><span style="color: #000000;">); <br/> response </span>= fibonacciRpc.call(<span style="color: #800000;">"</span><span style="color: #800000;">30</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> System.</span><span style="color: #0000ff;">out</span>.println(<span style="color: #800000;">"</span><span style="color: #800000;"> [.] Got '</span><span style="color: #800000;">"</span> + response + <span style="color: #800000;">"</span><span style="color: #800000;">'</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {<br/> e.printStackTrace();<br/> }<br/> </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {<br/> </span><span style="color: #0000ff;">if</span> (fibonacciRpc!= <span style="color: #0000ff;">null</span><span style="color: #000000;">) {<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {<br/> fibonacciRpc.close();<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception ignore) {}<br/> }<br/> }<br/> }<br/>}</span></div><p>&nbsp;</p><p>参考链接:http://www.rabbitmq.com/tutorials/tutorial-six-java.html</p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046532" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/leocook/p/mq_rabbitmq_6.html" target="_blank">RabbitMQ系列 第七篇:RCP(远程过程调用协议)</a>,转载请注明。</p>http://www.cnblogs.com/zhuweisky/p/4046501.html解决异常:公共语言运行时检测到无效的程序 - zhuweisky我碰到这个问题比较奇怪,在开发OrayTalk的组织结构功能时,其中的一个方法在win7、win2003下运行没有问题,在winxp下运行就抛异常:“公共语言运行时检测到无效的程序”。那么,这个问题怎么解决了?2014-10-23T10:14:00Z2014-10-23T10:14:00Zzhuweiskyhttp://www.cnblogs.com/zhuweisky/<p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">  我碰到这个问题比较奇怪,在开发OrayTalk的组织结构功能时,其中的一个方法(基于.NET 2.0)在win7、win2003下运行没有问题,在winxp下运行就抛异常:&ldquo;公共语言运行时检测到无效的程序&rdquo;,对应英文为:common language runtime detected an invalid program.</span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">  抛异常的方法代码摘抄如下:</span></p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;"> private</span> Control control =<span style="color: #000000;"> ...;<br/></span><span style="color: #0000ff;"> public</span> <span style="color: #0000ff;">void</span> ActionOnUI&lt;T1&gt;(<span style="color: #0000ff;">bool</span> showMessageBoxOnException, <span style="color: #0000ff;">bool</span> beginInvoke, <span style="color: #008080;">CbGeneric</span>&lt;T1&gt; method, <span style="color: #0000ff;">params</span> <span style="color: #0000ff;">object</span><span style="color: #000000;">[] args)<br/> {<br/> </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span><span style="color: #000000;">.control.InvokeRequired)<br/> {<br/> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (beginInvoke)<br/> {<br/> </span><span style="color: #0000ff;">this</span>.control.BeginInvoke(<span style="color: #0000ff;">new</span> CbGeneric&lt;<span style="color: #0000ff;">bool</span>, <span style="color: #0000ff;">bool</span>, <span style="color: #008080;">CbGeneric</span>&lt;T1&gt;, <span style="color: #0000ff;">object</span>[]&gt;(<span style="color: #0000ff;">this</span><span style="color: #000000;">.ActionOnUI), showMessageBoxOnException, beginInvoke, method, args);<br/> }<br/> </span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br/> {<br/> </span><span style="color: #0000ff;">this</span>.control.Invoke(<span style="color: #0000ff;">new</span> CbGeneric&lt;<span style="color: #0000ff;">bool</span>, <span style="color: #0000ff;">bool</span>, <span style="color: #008080;">CbGeneric</span>&lt;T1&gt;, <span style="color: #0000ff;">object</span>[]&gt;(<span style="color: #0000ff;">this</span><span style="color: #000000;">.ActionOnUI), showMessageBoxOnException, beginInvoke, method, args);<br/> }<br/> }<br/> </span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br/> {<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br/> {<br/> method((T1)args[</span><span style="color: #800080;">0</span><span style="color: #000000;">]);<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (<span style="color: #008080;">Exception</span> ee)<br/> { </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (showMessageBoxOnException)<br/> {<br/> <span style="color: #008080;">MessageBox</span>.Show(ee.Message);<br/> }<br/> }<br/> }<br/> }</span></div><p> <span style="font-size: 16px;">  &nbsp;<span style="font-family: 'Microsoft YaHei';">方法的目的是对UI调用转发做一个封装,让使用者更方便的将调用转发到UI线程。</span></span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">   &nbsp;但是,这个方法在执行时,异常在xp下发生了:</span></p><p><span style="font-family: 'Microsoft YaHei';">   &nbsp;&nbsp;<span style="color: #0000ff;">Common Language Runtime detected an invalid program. </span></span></p><p><span style="color: #0000ff; font-family: 'Microsoft YaHei';">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; at ESBasic.Helpers.UiSafeInvoker.ActionOnUI[T1](Boolean showMessageBoxOnException, Boolean beginInvoke, CbGeneric`1 method, Object[] args)</span></p><p><span style="font-family: 'Microsoft YaHei';">   &nbsp; <span style="font-size: 16px;">我在网上搜了一些相关问题的解答,比较靠谱的一点是这样说的:</span></span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">  &nbsp; &ldquo;这种错误非常少见,是一个编译器错误,通常产生在将C#等托管语言生成为MSIL时候出的错,没有什么好的解决办法,<span style="color: #ff0000;">现在可行的方法好像就是修改现在的程序结构</span>,这样根据新的结构生成新的MSIL时不会出错就基本可以避免这个问题。&rdquo;</span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">   &nbsp;根据这个提示,我对方法的代码进行了各种修改尝试,最后终于得到了一种在xp下也不抛异常的结构,粘贴如下:</span></p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"> <span style="color: #0000ff;">private</span> <span style="color: #008080;">Control</span> control =<span style="color: #000000;"> ...;<br/></span><span style="color: #0000ff;"> public</span> <span style="color: #0000ff;">void</span> ActionOnUI&lt;T1&gt;(<span style="color: #0000ff;">bool</span> showMessageBoxOnException, <span style="color: #0000ff;">bool</span> beginInvoke, <span style="color: #008080;">CbGeneric</span>&lt;T1&gt;<span style="color: #000000;"> method, T1 args)<br/> {<br/> </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span><span style="color: #000000;">.control.InvokeRequired)<br/> {<br/> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (beginInvoke)<br/> {<br/> </span><span style="color: #0000ff;">this</span>.control.BeginInvoke(<span style="color: #0000ff;">new</span> <span style="color: #008080;">CbGeneric</span>&lt;<span style="color: #0000ff;">bool</span>, CbGeneric&lt;T1&gt;, T1&gt;(<span style="color: #0000ff;">this</span>.Do_ActionOnUI&lt;T1&gt;<span style="color: #000000;">), showMessageBoxOnException, method, args);<br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br/> }<br/> </span><span style="color: #0000ff;">this</span>.control.Invoke(<span style="color: #0000ff;">new</span> CbGeneric&lt;<span style="color: #0000ff;">bool</span>, <span style="color: #008080;">CbGeneric</span>&lt;T1&gt;, T1&gt;(<span style="color: #0000ff;">this</span>.Do_ActionOnUI&lt;T1&gt;<span style="color: #000000;">), showMessageBoxOnException, method, args);<br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br/> }<br/><br/> </span><span style="color: #0000ff;">this</span>.Do_ActionOnUI&lt;T1&gt;<span style="color: #000000;">(showMessageBoxOnException, method, args);<br/> }<br/><br/> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> Do_ActionOnUI&lt;T1&gt;(<span style="color: #0000ff;">bool</span> showMessageBoxOnException, <span style="color: #008080;">CbGeneric</span>&lt;T1&gt;<span style="color: #000000;"> method, T1 args)<br/> {<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br/> {<br/> method(args);<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (<span style="color: #008080;">Exception</span> ee)<br/> { </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (showMessageBoxOnException)<br/> {<br/> <span style="color: #008080;">MessageBox</span>.Show(ee.Message);<br/> }<br/> }<br/> } </span></div><p>  <span style="font-family: 'Microsoft YaHei'; font-size: 16px;">总结起来,改变的几点如下:</span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">(1)将真正执行的部分重构为一个方法Do_ActionOnUI,然后,转发调用Invoke都指向这个方法。</span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">(2)Invoke转发调用时,为指向的方法加上泛型参数,避免编译器自动去匹配。</span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">(3)将弱类型的参数object[]修改为强类型的参数T1。</span></p><p><span style="font-family: 'Microsoft YaHei'; font-size: 16px;">  好吧,问题总算是解决了,好好折腾了一番啊~~</span></p><p><span style="line-height: 1.5;">&nbsp;</span></p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046501" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/zhuweisky/p/4046501.html" target="_blank">解决异常:公共语言运行时检测到无效的程序</a>,转载请注明。</p>http://www.cnblogs.com/banshine/p/4045910.htmlWPF:界面布局之- TaiChi - banshine前一段有看到博友用HTML5做了个太极的动画效果,分步骤展示了制作过程,一时兴起遂闲暇之余用WPF 简单用border拼接实现。先来分步实现第一步:先画出左边黑色半圆CornerRadius 属性可以设置四个边角的弧度,通过改变边角弧度达到画圆的目的。效果图如下:第二步:与第一步类似,画出右侧白色半...2014-10-23T10:09:00Z2014-10-23T10:09:00Zbanshinehttp://www.cnblogs.com/banshine/<p>前一段有看到博友用HTML5做了个太极的动画效果,分步骤展示了制作过程,一时兴起遂闲暇之余用WPF 简单用border拼接实现。</p><p>先来分步实现</p><p>第一步:先画出左边黑色半圆</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="200,0,0,200"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="Black"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Left"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span></div><p>CornerRadius 属性可以设置四个边角的弧度,通过改变边角弧度达到画圆的目的。</p><p>效果图如下:</p><p><img src="http://images.cnitblog.com/blog/487183/201410/231754136836993.png" alt="" width="454" height="419" /></p><p>&nbsp;</p><p>第二步:与第一步类似,画出右侧白色半圆</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="0,200,200,0"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Right"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span></div><p>只是将 <span style="color: #ff9900;">Border <span style="color: #333333;">的 <span style="color: #ff0000;">HorizontalAlignment </span></span></span>属性 设置为&ldquo;<span style="color: #ff0000;">Right</span>&rdquo;。</p><p>第三步:添加上方位置 黑色小半圆</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="100"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="0,200,200,0"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="Black"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Left"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Top"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="200,0,0,0"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span></div><p>需要注意的是通过 <span style="color: #ff0000;">Margin</span> 属性定位其位置。<br /><img src="http://images.cnitblog.com/blog/487183/201410/231803486996223.png" alt="" /></p><p>第四步:同理第三步, 添加下方位置 白色小半圆</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="100"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="200,0,0,200"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Left"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Bottom"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="100,0,0,0"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span></div><p><img src="http://images.cnitblog.com/blog/487183/201410/231804153717375.png" alt="" /></p><p>&nbsp;</p><p>基本上已经看的出样子了,接下来</p><p>&nbsp;</p><p>第五步:正上方位置添加 白色小正圆</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Top"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="0,75,0,0"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span></div><p>给定其背景色为白色。<br /><img src="http://images.cnitblog.com/blog/487183/201410/231807538553526.png" alt="" /></p><p>&nbsp;</p><p>第六步:同理第五步,在正下方添加 黑色小正圆,并给定其背景色为黑色。</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="Black"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Bottom"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="0,0,0,75"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span></div><p>效果图如下</p><p><img src="http://images.cnitblog.com/blog/487183/201410/231807339187184.png" alt="" /></p><p>&nbsp;</p><hr /><p>&nbsp;</p><p><span style="color: #888888; font-size: 14pt;">附上完整代码示例</span></p><p>前端完整XAML:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">UserControl </span><span style="color: #ff0000;">x:Class</span><span style="color: #0000ff;">="<span style="color: #0000ff; font-family: Courier New;">Jexton.Jtools.</span>JexTaiChi"</span><span style="color: #ff0000;"><br/> xmlns</span><span style="color: #0000ff;">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span><span style="color: #ff0000;"><br/> xmlns:x</span><span style="color: #0000ff;">="http://schemas.microsoft.com/winfx/2006/xaml"</span><span style="color: #ff0000;"><br/> xmlns:mc</span><span style="color: #0000ff;">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span><span style="color: #ff0000;"> <br/> xmlns:d</span><span style="color: #0000ff;">="http://schemas.microsoft.com/expression/blend/2008"</span><span style="color: #ff0000;"> <br/> mc:Ignorable</span><span style="color: #0000ff;">="d"</span><span style="color: #ff0000;"> <br/> d:DesignHeight</span><span style="color: #0000ff;">="500"</span><span style="color: #ff0000;"> d:DesignWidth</span><span style="color: #0000ff;">="500"</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">x:Name</span><span style="color: #0000ff;">="Taichi"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="20"</span><span style="color: #ff0000;"> Width</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> RenderTransformOrigin</span><span style="color: #0000ff;">="0.5,0.5"</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border.RenderTransform</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">TransformGroup</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">ScaleTransform</span><span style="color: #0000ff;">/&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">SkewTransform</span><span style="color: #0000ff;">/&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">RotateTransform </span><span style="color: #ff0000;">Angle</span><span style="color: #0000ff;">="0"</span><span style="color: #0000ff;">/&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">TranslateTransform</span><span style="color: #0000ff;">/&gt;</span><br/> <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">TransformGroup</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Border.RenderTransform</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border.Effect</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">DropShadowEffect </span><span style="color: #ff0000;">ShadowDepth</span><span style="color: #0000ff;">="0"</span><span style="color: #ff0000;"> BlurRadius</span><span style="color: #0000ff;">="40"</span><span style="color: #ff0000;"> Color</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> Opacity</span><span style="color: #0000ff;">="0.5"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">DropShadowEffect</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Border.Effect</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #008000;">&lt;!--</span><span style="color: #008000;">左边黑半圆</span><span style="color: #008000;">--&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="200,0,0,200"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="Black"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Left"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #008000;">&lt;!--</span><span style="color: #008000;">右边白半圆</span><span style="color: #008000;">--&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="400"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="0,200,200,0"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Right"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #008000;">&lt;!--</span><span style="color: #008000;">黑色小半圆</span><span style="color: #008000;">--&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="100"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="0,200,200,0"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="Black"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Left"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Top"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="200,0,0,0"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #008000;">&lt;!--</span><span style="color: #008000;">白色小半圆</span><span style="color: #008000;">--&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="100"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="200"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="200,0,0,200"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> HorizontalAlignment</span><span style="color: #0000ff;">="Left"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Bottom"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="100,0,0,0"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #008000;">&lt;!--</span><span style="color: #008000;">白色小正圆</span><span style="color: #008000;">--&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="White"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Top"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="0,75,0,0"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #008000;">&lt;!--</span><span style="color: #008000;">黑色小正圆</span><span style="color: #008000;">--&gt;</span><br/> <span style="color: #0000ff;">&lt;</span><span style="color: #800000;">Border </span><span style="color: #ff0000;">Width</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Height</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> CornerRadius</span><span style="color: #0000ff;">="50"</span><span style="color: #ff0000;"> Background</span><span style="color: #0000ff;">="Black"</span><span style="color: #ff0000;"> VerticalAlignment</span><span style="color: #0000ff;">="Bottom"</span><span style="color: #ff0000;"> Margin</span><span style="color: #0000ff;">="0,0,0,75"</span><span style="color: #0000ff;">&gt;&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Grid</span><span style="color: #0000ff;">&gt;</span><br/> <span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">Border</span><span style="color: #0000ff;">&gt;</span><br/><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">UserControl</span><span style="color: #0000ff;">&gt;</span></div><p>至此UI部分完成,接下来还可以让它 &rdquo;动&ldquo; 起来:</p><p>后端代码&nbsp;:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"> ThreadPool.QueueUserWorkItem(<span style="color: #0000ff;">new</span> WaitCallback(w=&gt;<span style="color: #000000;">{<br/> </span><span style="color: #0000ff;">int</span> Angle = <span style="color: #800080;">0</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">)<br/> {<br/> </span><span style="color: #0000ff;">if</span> (Angle == <span style="color: #800080;">360</span>) { Angle = <span style="color: #800080;">0</span><span style="color: #000000;">; }<br/> Taichi.Dispatcher.BeginInvoke(</span><span style="color: #0000ff;">new</span> Action(() =&gt;<span style="color: #000000;"> { <br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">Taichi</span><br/> TransformGroup group = <span style="color: #0000ff;">new</span><span style="color: #000000;"> TransformGroup();<br/> group.Children.Add(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> ScaleTransform());<br/> group.Children.Add(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SkewTransform());<br/> group.Children.Add(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> TranslateTransform());<br/> group.Children.Add(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> RotateTransform(Angle));<br/> Taichi.RenderTransform </span>=<span style="color: #000000;"> group;<br/> }));<br/> Angle </span>= Angle + <span style="color: #800080;">10</span><span style="color: #000000;">;<br/> Thread.Sleep(</span><span style="color: #800080;">50</span><span style="color: #000000;">);<br/> }<br/> }));</span></div><p><br />写在最后的话:</p><p style="margin-left: 30px;">在WPF中很多复杂图形也是可以使用简单布局元素拼凑出来的。</p><img src="http://counter.cnblogs.com/blog/rss/4045910" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/banshine/p/4045910.html" target="_blank">WPF:界面布局之- TaiChi</a>,转载请注明。</p>http://www.cnblogs.com/yongzhengye/p/4046460.html图解win7中IIS7.0的安装及配置ASP环境 - 雍正爷控制面板中“程序”的位置“程序”中“打开或关闭Windows功能”的位置如图,安装IIS7时需要选择要使用的功能模块IIS7安装完成之后可以在开始菜单的所有程序中看到“管理工具”,其中有一个“Internet信息服务管理器”,如果没有可以按以下步骤添加:开始》右击属性》“开始”菜单选项卡》自定义》把...2014-10-23T10:04:00Z2014-10-23T10:04:00Z雍正爷http://www.cnblogs.com/yongzhengye/<p>控制面板中&ldquo;程序&rdquo;的位置</p><p><img src="http://www.newasp.net/attachment/article/2008-7/20087912455487999.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>&ldquo;程序&rdquo;中&ldquo;打开或关闭Windows功能&rdquo;的位置</p><p><img src="http://www.newasp.net/attachment/article/2008-7/20087912461223021.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>如图,安装IIS7时需要选择要使用的功能模块</p><p><img src="http://www.newasp.net/attachment/article/2008-7/20087912464192669.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>IIS7安装完成之后可以在开始菜单的所有程序中看到&ldquo;管理工具&rdquo;,其中有一个&ldquo;Internet信息服务管理器&rdquo;,如果没有可以按以下步骤添加:开始》右击属性》&ldquo;开始&rdquo;菜单选项卡》自定义》把&ldquo;系统管理工具&rdquo;设置为&ldquo;在所有程序菜单显示&rdquo;或者&ldquo;在所有程序菜单和开始菜单上显示&rdquo;。</p><p><img src="http://www.newasp.net/attachment/article/2008-7/20087912483063424.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>打开Internet信息服务管理器就可以看到IIS7的主页了</p><p><img src="http://www.newasp.net/attachment/article/2008-7/20087912485864979.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>IIS7配置ASP+Access使用环境</p><p>默认装完IIS7之后,使用ASP程序会发现提示数据库连接失败,在网上找了找,说是因为MSJet引擎改变了临时目录的位置,但是又没有对临时的存取权限,导致数据库使用失败。</p><p>先要设置应用程序池(ApplicationPool)为Classic.NETAppPool,而不是默认的DefaultAppPool,可以在网站目录里对每个站点设置,也可以在站点进行单独设置。选择好要设置的站点之后,点右边的&ldquo;基本设置&rdquo;即可调出应用程序池设置对话框。</p><p><img src="http://www.newasp.net/attachment/article/2008-7/20087912492531482.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p><img src="http://www.newasp.net/attachment/article/2008-7/2008791305750860.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>然后再给&ldquo;系统盘:\Windows\ServiceProfiles\NetworkService\AppData\Local\ Temp&rdquo;目录添加一个&ldquo;AuthenticatedUsers&rdquo;的用户,其中AppData目录是隐藏的,在进入的时候可以直接在地址栏输入路径,或者在文件夹选项里显示隐藏文件。</p><p>设置权限步骤:右击Temp文件夹,选择&ldquo;属性&rdquo;》选择&ldquo;安全&rdquo;选项卡》单击&ldquo;编辑&rdquo;》出来&ldquo;Temp的权限&rdquo;对话框,单击&ldquo;添加&rdquo;,在下面的&ldquo;输入对象名称来选择&rdquo;中输入AuthenticatedUsers,确定》返回到&ldquo;Temp的权限&rdquo;,将AuthenticatedUsers的权限中的完全控制给勾上,确定》确定。</p><p><img src="http://www.newasp.net/attachment/article/2008-7/200879135154996.jpg" alt="图解Vista中IIS7.0的安装及配置ASP环境" /></p><p>启用父路径支持</p><p>在站点主页上选择&ldquo;ASP&rdquo;,然后在&ldquo;行为&rdquo;组中将&ldquo;启用父路径&rdquo;设置为True即可。</p><img src="http://counter.cnblogs.com/blog/rss/4046460" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/yongzhengye/p/4046460.html" target="_blank">图解win7中IIS7.0的安装及配置ASP环境</a>,转载请注明。</p>http://www.cnblogs.com/preacher/p/4046445.html高并发、海量数据处理尽量少使用using也能提升效率 - 小尧弟刚开始看到这个标题,估计很多人都云里雾里的。 请看下面两段:第一种方式: MemoryStream stream = new MemoryStream(); string text = "aasasdfasdfad;sas;fkqeworpkq...2014-10-23T10:00:00Z2014-10-23T10:00:00Z小尧弟http://www.cnblogs.com/preacher/<p>&nbsp; &nbsp; &nbsp; 刚开始看到这个标题,估计很多人都云里雾里的。</p><p>  请看下面两段:</p><p>第一种方式:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"> MemoryStream stream = <span style="color: #0000ff;">new</span><span style="color: #000000;"> MemoryStream();<br />          <span style="color: #0000ff;">string</span> text = "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf";<br/> </span><span style="color: #0000ff;">byte</span>[] buff =<span style="color: #000000;"> System.Text.ASCIIEncoding.ASCII.GetBytes(text);<br/> stream.Write(buff, </span><span style="color: #800080;">0</span><span style="color: #000000;">, buff.Length);<br/> stream.Flush();<br/> stream.Close();<br/> stream.Dispose();</span></div><p>第二种方式:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"> <span style="color: #0000ff;">string</span> text = <span style="color: #800000;">"</span><span style="color: #800000;">aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">using</span> (MemoryStream stream = <span style="color: #0000ff;">new</span><span style="color: #000000;"> MemoryStream())<br/> {<br/> </span><span style="color: #0000ff;">byte</span>[] buff =<span style="color: #000000;"> System.Text.ASCIIEncoding.ASCII.GetBytes(text);<br/> stream.Write(buff, </span><span style="color: #800080;">0</span><span style="color: #000000;">, buff.Length);<br/> stream.Flush();<br/> stream.Close();<br/> }</span></div><p>不仅仅是我,估计一个老鸟程序员,大都会选择方法二,虽然方法一和方法二实现相同的功能,但是方法二带着套比较保险,即便我们失手,不会制造出垃圾来(这话听着怪怪的,能理解我在说什么就好)。之后,我在做一些消息处理机制的接收、处理、分发测试中,发现使用using关键字和不用using关键字,效率有着很大差异,不使用using关键字效率明显偏高,队列中缓存数据明显大减,而且基本不再出现容器不足溢出现象,这是为什么呢?答案马上揭晓。</p><p>以下是通过反汇编工具所得的一种类似汇编语言(如果以下真是汇编语言,就当我前面"类似"两字说错了,跟我当初学的汇编语言不一样。这个应该是.net架构可识别的中间语言)</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">.method <span style="color: #0000ff;">private</span> hidebysig <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span><span style="color: #000000;">[] args) cil managed<br/>{<br/> .entrypoint<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 代码大小 65 (0x41)</span><br/> .maxstack <span style="color: #800080;">4</span><span style="color: #000000;"><br/> .locals init ([</span><span style="color: #800080;">0</span>] <span style="color: #0000ff;">string</span><span style="color: #000000;"> text,<br/> [</span><span style="color: #800080;">1</span>] <span style="color: #0000ff;">class</span> [mscorlib]System.IO.MemoryStream <span style="color: #800000;">'</span><span style="color: #800000;">stream</span><span style="color: #800000;">'</span><span style="color: #000000;">,<br/> [</span><span style="color: #800080;">2</span><span style="color: #000000;">] uint8[] buff)<br/> IL_0000: nop<br/> IL_0001: ldstr </span><span style="color: #800000;">"</span><span style="color: #800000;">aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf</span><span style="color: #800000;">"</span><span style="color: #000000;"><br/> IL_0006: stloc.</span><span style="color: #800080;">0</span><span style="color: #000000;"><br/> IL_0007: newobj instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.MemoryStream::.ctor()<br/> IL_000c: stloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_000d: call </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_ASCII()<br/> IL_0012: ldloc.</span><span style="color: #800080;">0</span><span style="color: #000000;"><br/> IL_0013: callvirt instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">)<br/> IL_0018: stloc.</span><span style="color: #800080;">2</span><span style="color: #000000;"><br/> IL_0019: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_001a: ldloc.</span><span style="color: #800080;">2</span><span style="color: #000000;"><br/> IL_001b: ldc.i4.</span><span style="color: #800080;">0</span><span style="color: #000000;"><br/> IL_001c: ldloc.</span><span style="color: #800080;">2</span><span style="color: #000000;"><br/> IL_001d: ldlen<br/> IL_001e: conv.i4<br/> IL_001f: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Write(uint8[],<br/> int32,<br/> int32)<br/> IL_0024: nop<br/> IL_0025: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_0026: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Flush()<br/> IL_002b: nop<br/> IL_002c: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_002d: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Close()<br/> IL_0032: nop<br/> IL_0033: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_0034: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Dispose()<br/> IL_0039: nop<br/> IL_0040: ret<br/>} </span><span style="color: #008000;">//</span><span style="color: #008000;"> end of method Program::Main</span></div><p>以上是方法一,所得中间语言,看起来非常干净、流畅。下面看看方法二的:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">.method <span style="color: #0000ff;">private</span> hidebysig <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span><span style="color: #000000;">[] args) cil managed<br/>{<br/> .entrypoint<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;"> 代码大小 79 (0x4f)</span><br/> .maxstack <span style="color: #800080;">4</span><span style="color: #000000;"><br/> .locals init ([</span><span style="color: #800080;">0</span>] <span style="color: #0000ff;">string</span><span style="color: #000000;"> text,<br/> [</span><span style="color: #800080;">1</span>] <span style="color: #0000ff;">class</span> [mscorlib]System.IO.MemoryStream <span style="color: #800000;">'</span><span style="color: #800000;">stream</span><span style="color: #800000;">'</span><span style="color: #000000;">,<br/> [</span><span style="color: #800080;">2</span><span style="color: #000000;">] uint8[] buff,<br/><em><strong><span style="color: #ff0000;"> [</span></strong></em></span><em><strong><span style="color: #ff0000;">3] bool CS$4$0000</span></strong></em><span style="color: #000000;"><em><strong><span style="color: #ff0000;">)</span></strong></em><br/> IL_0000: nop<br/> IL_0001: ldstr </span><span style="color: #800000;">"</span><span style="color: #800000;">aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf</span><span style="color: #800000;">"</span><span style="color: #000000;"><br/> IL_0006: stloc.</span><span style="color: #800080;">0</span><span style="color: #000000;"><br/> IL_0007: newobj instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.MemoryStream::.ctor()<br/> IL_000c: stloc.</span><span style="color: #800080;">1</span><em><strong><span style="color: #ff0000;"><br/> .try</span></strong></em><span style="color: #000000;"><em><strong><span style="color: #ff0000;"><br/> {<br/> IL_000d: nop</span></strong></em><br/> IL_000e: call </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_ASCII()<br/> IL_0013: ldloc.</span><span style="color: #800080;">0</span><span style="color: #000000;"><br/> IL_0014: callvirt instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">)<br/> IL_0019: stloc.</span><span style="color: #800080;">2</span><span style="color: #000000;"><br/> IL_001a: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_001b: ldloc.</span><span style="color: #800080;">2</span><span style="color: #000000;"><br/> IL_001c: ldc.i4.</span><span style="color: #800080;">0</span><span style="color: #000000;"><br/> IL_001d: ldloc.</span><span style="color: #800080;">2</span><span style="color: #000000;"><br/> IL_001e: ldlen<br/> IL_001f: conv.i4<br/> IL_0020: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Write(uint8[],<br/> int32,<br/> int32)<br/> IL_0025: nop<br/> IL_0026: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_0027: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Flush()<br/> IL_002c: nop<br/> IL_002d: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_002e: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IO.Stream::Close()<br/> IL_0033: nop<br/> IL_0034: nop<br/> IL_0035: leave.s IL_0047<br/><em><strong><span style="color: #ff0000;"> } </span></strong></em></span><em><strong><span style="color: #ff0000;">// end .try<br/> finally</span></strong></em><span style="color: #000000;"><em><strong><span style="color: #ff0000;"><br/> {</span></strong></em><br/> IL_0037: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_0038: ldnull<br/> IL_0039: ceq<br/> IL_003b: stloc.</span><span style="color: #800080;">3</span><span style="color: #000000;"><br/> IL_003c: ldloc.</span><span style="color: #800080;">3</span><span style="color: #000000;"><br/> IL_003d: brtrue.s IL_0046<br/> IL_003f: ldloc.</span><span style="color: #800080;">1</span><span style="color: #000000;"><br/> IL_0040: callvirt instance </span><span style="color: #0000ff;">void</span><span style="color: #000000;"> [mscorlib]System.IDisposable::Dispose()<br/> IL_0045: nop<br/> IL_0046: endfinally<br/> } </span><span style="color: #008000;">//</span><span style="color: #008000;"> end handler</span><span style="color: #000000;"><br/> IL_0047: pop<br/> IL_0048: ret<br/>} </span><span style="color: #008000;">//</span><span style="color: #008000;"> end of method Program::Main</span></div><p><strong><span style="color: #ff0000;">(红字部分)</span></strong>这下能看出问题来了吧,本来是功能相同的两段代码,但是在方法二中,多出了一个try..finally模块,多出一个初始存储元的申请CS$4$0000,多出很多行相对来说算是赋址操作。这就是导致方法二效率低的主要原因。</p><p>  但是刚刚我们也提到了,虽然方法一和方法二实现相同的功能,但是方法二带着套比较保险,即便我们失手,不会制造出垃圾来。即使是你忘记使用.close()、.dispose()方法释放资源,using还是会自动帮你处理好你遗忘的的坏事。</p><p>  所以在一般不要求高效开发中,尽量使用using,但是在处理高并发、海量数据等等情况下,尽量不要让using出现。不过现在好了,自从接触erlang后,它处理消息确实比C#/java/C++高效多了。</p><p>&nbsp;</p><hr /><p>&nbsp;</p><p><strong>  还有一点忘记说了,我用消息泵处理消息队列,消息泵放到一个using里面,这会导致所有消息都会在这个using包裹中处理。</strong></p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046445" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/preacher/p/4046445.html" target="_blank">高并发、海量数据处理尽量少使用using也能提升效率</a>,转载请注明。</p>http://www.cnblogs.com/ronny/p/4045979.htmlSURF算法与源码分析、上 - ☆Ronny丶如果说SIFT算法中使用DOG对LOG进行了简化,提高了搜索特征点的速度,那么SURF算法则是对DoH的简化与近似。虽然SIFT算法已经被认为是最有效的,也是最常用的特征点提取的算法,但如果不借助于硬件的加速和专用图像处理器的配合,SIFT算法以现有的计算机仍然很难达到实时的程度。对于需要实时运算的...2014-10-23T09:53:00Z2014-10-23T09:53:00Z☆Ronny丶http://www.cnblogs.com/ronny/<p>如果说SIFT算法中使用DOG对LOG进行了简化,提高了搜索特征点的速度,那么SURF算法则是对DoH的简化与近似。虽然SIFT算法已经被认为是最有效的,也是最常用的特征点提取的算法,但如果不借助于硬件的加速和专用图像处理器的配合,SIFT算法以现有的计算机仍然很难达到实时的程度。对于需要实时运算的场合,如基于特征点匹配的实时目标跟踪系统,每秒要处理8-24帧的图像,需要在毫秒级内完成特征点的搜索、特征矢量生成、特征矢量匹配、目标锁定等工作,这样SIFT算法就很难适应这种需求了。SURF借鉴了SIFT中简化近似的思想,把DoH中的高斯二阶微分模板进行了简化,使得模板对图像的滤波只需要进行几个简单的加减法运算,并且,这种运算与滤波器的尺度无关。实验证明,SURF算法较SIFT在运算速度上要快3倍左右。</p><p><strong>1. 积分图像</strong></p><p>SURF算法中要用到积分图像的概念。借助积分图像,图像与高斯二阶微分模板的滤波转化为对积分图像的加减运算。</p><p>积分图像中任意一点$(i,j)$的值$ii(i,j)$,为原图像左上角到点$(i,j)$相应的对角线区域灰度值的总和,即</p><p>$$ii(i,j) = \sum_{r\le i,\ c\le j}p(r,c)$$</p><p>式中,$p(r,c)$表示图像中点$(r,c)$的灰度值,$ii(i,j)$可以用下面两式迭代计算得到</p><p>$$S(i,j) = S(i,j-1)+p(i,j)$$</p><p>$$ii(i,j)=ii(i-1,j)+S(i,j)$$</p><p>式中,$S(i,j)$表示一列的积分,且$S(i,-1)=0,ii(-1,j)=0$。求积分图像,只需要对原图像所有像素进行一遍扫描。</p><p>OpenCV中提供了用于计算积分图像的接口</p><span style="color: green;">/*<br/>* src :输入图像,大小为M*N<br/>* sum: 输出的积分图像,大小为(M+1)*(N+1)<br/>* sdepth:用于指定sum的类型,-1表示与src类型一致<br/>*/<br/></span><span style="color: blue;">void </span><span style="color: black;">integral(</span><span style="color: #2b91af;">InputArray </span><span style="color: black;">src, </span><span style="color: #2b91af;">OutputArray </span><span style="color: black;">sum, </span><span style="color: blue;">int </span><span style="color: black;">sdepth = -1);</span><p>值得注意的是OpenCV里的积分图大小比原图像多一行一列,那是因为OpenCV中积分图的计算公式为:</p><p>$$ii(i,j) = \sum_{r&lt; i,\ c&lt; j}p(r,c)$$</p><p align="center"><img style="display: inline; border-width: 0px;" title="image" src="http://images.cnitblog.com/blog/378920/201410/231613539968142.png" alt="image" width="284" height="218" border="0" /></p><p>一旦积分图计算好了,计算图像内任何矩形区域的像素值的和只需要三个加法,如上图所示。</p><p><strong>2. DoH近似</strong></p><p>在<a href="http://www.cnblogs.com/ronny/p/3895883.html" target="_blank">斑点检测</a>这篇文章中已经提到过,我们可以利用Hessian矩阵行列式的极大值检测斑点。下面我们给出Hessian矩阵的定义。</p><p>给定图像$I$中的一个点$x(i,j)$,在点$x$处,尺度为$\sigma$的Hessian矩阵$H(x,\sigma)$定义如下:</p><p>$$H(x,\sigma) = \begin{bmatrix}L_{xx}(x,\sigma) &amp; L_{xy}(x,\sigma) \\ L_{xy}(x,\sigma) &amp; L_{yy}(x,\sigma) \end{bmatrix}$$</p><p>式中,$L_{xx}(x,\sigma)$是高斯二阶微分$\frac{\partial ^2g(\sigma)}{\partial x^2}$在点$x$处与图像$I$的卷积,$L_{x,y}(x,\sigma)$和$L_{yy}(x,\sigma)$具有类似的含义。</p><p>下面显示的是上面三种高斯微分算子的图形。</p><p><img style="float: none; margin-left: auto; display: block; margin-right: auto; border-width: 0px;" title="image" src="http://images.cnitblog.com/blog/378920/201410/231641596522431.png" alt="image" width="546" height="169" border="0" /></p><p>但是利用Hessian行列式进行图像斑点检测时,有一个缺点。由于二阶高斯微分被离散化和裁剪的原因,导致了图像在旋转奇数倍的$\pi/4$时,即转换到模板的对角线方向时,特征点检测的重复性降低(也就是说,原来特征点的地方,可能检测不到特征点了)。而在$\pi/2$时,特征点检测的重现率真最高。但这一小小的不足不影响我们使用Hessian矩阵进行特征点的检测。</p><p>为了将模板与图产像的卷积转换为盒子滤波运算,我们需要对高斯二阶微分模板进行简化,使得简化后的模板只是由几个矩形区域组成,矩形区域内填充同一值,如下图所示,在简化模板中白色区域的值为正数,黑色区域的值为负数,灰度区域的值为0。</p><p><img style="float: none; margin-left: auto; display: block; margin-right: auto; border-width: 0px;" title="image" src="http://images.cnitblog.com/blog/378920/201410/231642004654315.png" alt="image" width="620" height="154" border="0" /></p><p>对于$\sigma = 1.2$的高斯二阶微分滤波器,我们设定模板的尺寸为$9\times9$的大小,并用它作为最小尺度空间值对图像进行滤波和斑点检测。我们使用$D_{xx}、D_{xy}$和$D_{yy}$表示模板与图像进行卷积的结果。这样,便可以将Hessian矩阵的行列式作如下的简化。</p><p>$$Det(H) = L_{xx}L_{yy} &ndash; L_{xy}L_{xy} = D_{xx}\frac{L_{xx}}{D_{xx}}D_{yy}\frac{L_{yy}}{D_{yy}} - D_{xy}\frac{L_{xy}}{D_{xy}}D_{xy}\frac{L_{xy}}{D_{xy}}&nbsp; \approx D_{xx}D_{yy} &ndash; (wD_{xy})^2$$</p><p>滤波器响应的相关权重$w$是为了平衡Hessian行列式的表示式。这是为了保持高斯核与近似高斯核的一致性。</p><p>$$w = \frac{|L_{xy}(\sigma)|_F|D_{xx}(\sigma)_F|}{|L_{xx}(\sigma)|_F|D_{xy}(\sigma)_F|} = 0.912$$</p><p>其中$|X|_F$为Frobenius范数。理论上来说对于不同的$\sigma$的值和对应尺寸的模板尺寸,$w$值是不同的,但为了简化起见,可以认为它是同一个常数。</p><p>使用近似的Hessian矩阵行列式来表示图像中某一点$x$处的斑点响应值,遍历图像中所有的像元点,便形成了在某一尺度下琉璃点检测的响应图像。使用不同的模板尺寸,便形成了多尺度斑点响应的金字塔图像,利用这一金字塔图像,就可以进行斑点响应极值点的搜索,其过程完全与SIFT算法类同。</p><p><strong>3. 尺度空间表示</strong></p><p>通常想要获取不同尺度的斑点,必须建立图像的尺度空间金字塔。一般的方法是通过不同$\sigma$的高斯函数,对图像进行平滑滤波,然后重采样图像以获得更高一层的金字塔图像。SIFT特征检测算法中就是通过相邻两层图像金字塔相减得到DoG图像,然后再在DoG图像上进行斑点和边缘检测工作的。</p><p>由于采用了盒子滤波和积分图像,所以,我们并不需要像SIFT算法那样去直接建立图像金字塔,而是采用不断增大盒子滤波模板的尺寸的间接方法。通过不同尺寸盒子滤波模板与积分图像求取Hessian矩阵行列式的响应图像。然后在响应图像上采用3D非最大值抑制,求取各种不同尺度的斑点。</p><p>如前所述,我们使用$9\times9$的模板对图像进行滤波,其结果作为最初始的尺度空间层(此时,尺度值为s=1.2,近似$\sigma=1.2$的高斯微分),后续的层将通过逐步放大滤波模板尺寸,以及放大后的模板不断与图像进行滤波得到。由于采用盒子滤波和积分图像,滤波过程并不随着滤波模板尺寸的增加而使运算工作量增加。</p><p>与SIFT算法类似,我们需要将尺度空间划分为若干组(Octaves)。一个组代表了逐步放大的滤波模板对同一输入图像进行滤波的一系列响应图。每个组又由若干固定的层组成。由于积分图像离散化的原因,两个层之间的最小尺度变化量是由高斯二阶微分滤波器在微分方向上对正负斑点响应长度$l_0$决定的,它是盒子滤波器模板尺寸的$1/3$。对于$9\times9$的模板,它的$l_0=3$。一下层的响应长度至少应该在$l_0$的基础上增加2个像素,以保证一边一个像素,即$l_0 = 5$。这样模板的尺寸就为$15\times15$。以此类推,我们可以得到一个尺寸增大模板序列,它们的尺寸分别为:$9\times9,15\times15,21\times21,27\times27$,黑色、白色区域的长度增加偶数个像素,以保证一个中心像素的存在。</p><p align="center"><img style="margin-left: 0px; display: inline; margin-right: 0px; border-width: 0px;" title="image" src="http://images.cnitblog.com/blog/378920/201410/231723019806742.png" alt="image" width="390" height="192" border="0" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img style="display: inline; border-width: 0px;" title="image" src="http://images.cnitblog.com/blog/378920/201410/231723045585055.png" alt="image" width="405" height="193" border="0" /></p><p>采用类似的方法来处理其他几组的模板序列。其方法是将滤波器尺寸增加量翻倍(6,12,24,38)。这样,可以得到第二组的滤波器尺寸,它们分别为15,27,39,51。第三组的滤波器尺寸为27,51,75,99。如果原始图像的尺寸仍然大于对应的滤波器尺寸,尺度空间的分析还可以进行第四组,其对应的模板尺寸分别为51,99,147和195。下图显示了第一组至第三组的滤波器尺寸变化。</p><p align="center"><img style="margin-left: 0px; display: inline; margin-right: 0px; border-width: 0px;" title="image" src="http://images.cnitblog.com/blog/378920/201410/231723083715124.png" alt="image" width="399" height="209" border="0" /></p><p>在通常尺度分析情况下,随着尺度的增大,被检测到的斑点数量迅速衰减。所以一般进行3-4组就可以了,与此同时,为了减少运算量,提高计算的速度,可以考虑在滤波时,将采样间隔设为2。</p><p>对于尺寸为L的模板,当用它与积分图运算来近似二维高斯核的滤波时,对应的二维高斯核的参数$\sigma = 1.2 \times \frac{L}{9}$,这一点至关重要,尤其是在后面计算描述子时,用于计算邻域的半径时。</p><p><strong>4. 兴趣点的定位</strong></p><p>为了在图像及不同尺寸中定位兴趣点,我们用了$3\times3\times3$邻域非最大值抑制。具体的步骤基本与SIFT一致,而且Hessian矩阵行列式的最大值在尺度和图像空间被插值。</p><p>下面显示了我们用的快速Hessian检测子检测到的兴趣点。</p><p><strong>5. SURF源码解析</strong></p><p>这份源码来自OpenCV nonfree模块。</p><p>这里先介绍SURF特征点定位这一块,关于特征点的描述下一篇文章再介绍。</p><p><strong>5.1 主干函数 fastHessianDetector</strong></p><p>特征点定位的主干函数为fastHessianDetector,该函数接受一个积分图像,以及尺寸相关的参数,组数与每组的层数,检测到的特征点保存在vector&lt;KeyPoint&gt;类型的结构中。</p><span style="color: blue;">static void </span><span style="color: black;">fastHessianDetector(</span><span style="color: blue;">const </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">sum</span><span style="color: black;">, </span><span style="color: blue;">const </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">msum</span><span style="color: black;">, </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: #2b91af;">KeyPoint</span><span style="color: black;">&gt;&amp; </span><span style="color: gray;">keypoints</span><span style="color: black;">,<br/> </span><span style="color: blue;">int </span><span style="color: gray;">nOctaves</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">nOctaveLayers</span><span style="color: black;">, </span><span style="color: blue;">float </span><span style="color: gray;">hessianThreshold</span><span style="color: black;">)<br/>{<br/> </span><span style="color: green;">/*first Octave图像采样的步长,第二组的时候加倍,以此内推<br/> 增加这个值,将会加快特征点检测的速度,但是会让特征点的提取变得不稳定*/<br/> </span><span style="color: blue;">const int </span><span style="color: black;">SAMPLE_STEP0 = 1;<br/><br/> </span><span style="color: blue;">int </span><span style="color: black;">nTotalLayers = (</span><span style="color: gray;">nOctaveLayers </span><span style="color: black;">+ 2)*</span><span style="color: gray;">nOctaves</span><span style="color: black;">; </span><span style="color: green;">// 尺度空间的总图像数<br/> </span><span style="color: blue;">int </span><span style="color: black;">nMiddleLayers = </span><span style="color: gray;">nOctaveLayers</span><span style="color: black;">*</span><span style="color: gray;">nOctaves</span><span style="color: black;">; </span><span style="color: green;">// 用于检测特征点的层的 总数,也就是中间层的总数<br/><br/> </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: #2b91af;">Mat</span><span style="color: black;">&gt; dets(nTotalLayers); </span><span style="color: green;">// 每一层图像 对应的 Hessian行列式的值<br/> </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: #2b91af;">Mat</span><span style="color: black;">&gt; traces(nTotalLayers); </span><span style="color: green;">// 每一层图像 对应的 Hessian矩阵的迹的值<br/> </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: blue;">int</span><span style="color: black;">&gt; sizes(nTotalLayers); </span><span style="color: green;">// 每一层用的 Harr模板的大小<br/> </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: blue;">int</span><span style="color: black;">&gt; sampleSteps(nTotalLayers); </span><span style="color: green;">// 每一层用的采样步长 <br/> </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: blue;">int</span><span style="color: black;">&gt; middleIndices(nMiddleLayers); </span><span style="color: green;">// 中间层的索引值<br/><br/> </span><span style="color: gray;">keypoints</span><span style="color: black;">.clear();<br/><br/> </span><span style="color: green;">// 为上面的对象分配空间,并赋予合适的值<br/> </span><span style="color: blue;">int </span><span style="color: black;">index = 0, middleIndex = 0, step = SAMPLE_STEP0;<br/><br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">octave = 0; octave &lt; </span><span style="color: gray;">nOctaves</span><span style="color: black;">; octave++)<br/> {<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">layer = 0; layer &lt; </span><span style="color: gray;">nOctaveLayers </span><span style="color: black;">+ 2; layer++)<br/> {<br/> </span><span style="color: green;">/*这里sum.rows - 1是因为 sum是积分图,它的大小是原图像大小加1*/<br/> </span><span style="color: black;">dets[index].create((</span><span style="color: gray;">sum</span><span style="color: black;">.rows - 1) / step, (</span><span style="color: gray;">sum</span><span style="color: black;">.cols - 1) / step, </span><span style="color: #6f008a;">CV_32F</span><span style="color: black;">); </span><span style="color: green;">// 这里面有除以遍历图像用的步长<br/> </span><span style="color: black;">traces[index].create((</span><span style="color: gray;">sum</span><span style="color: black;">.rows - 1) / step, (</span><span style="color: gray;">sum</span><span style="color: black;">.cols - 1) / step, </span><span style="color: #6f008a;">CV_32F</span><span style="color: black;">);<br/> sizes[index] = (SURF_HAAR_SIZE0 + SURF_HAAR_SIZE_INC*layer) &lt;&lt; octave;<br/> sampleSteps[index] = step;<br/><br/> </span><span style="color: blue;">if </span><span style="color: black;">(0 &lt; layer &amp;&amp; layer &lt;= </span><span style="color: gray;">nOctaveLayers</span><span style="color: black;">)<br/> middleIndices[middleIndex++] = index;<br/> index++;<br/> }<br/> step *= 2;<br/> }<br/> </span><span style="color: green;">// Calculate hessian determinant and trace samples in each layer<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">i = 0; i &lt; nTotalLayers; i++)<br/> {<br/> calcLayerDetAndTrace(</span><span style="color: gray;">sum</span><span style="color: black;">, sizes[i], sampleSteps[i], dets[i], traces[i]);<br/> }<br/><br/> </span><span style="color: green;">// Find maxima in the determinant of the hessian<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">i = 0; i &lt; nMiddleLayers; i++)<br/> {<br/> </span><span style="color: blue;">int </span><span style="color: black;">layer = middleIndices[i];<br/> </span><span style="color: blue;">int </span><span style="color: black;">octave = i / </span><span style="color: gray;">nOctaveLayers</span><span style="color: black;">;<br/> findMaximaInLayer(</span><span style="color: gray;">sum</span><span style="color: black;">, </span><span style="color: gray;">msum</span><span style="color: black;">, dets, traces, sizes, </span><span style="color: gray;">keypoints</span><span style="color: black;">, octave, layer, </span><span style="color: gray;">hessianThreshold</span><span style="color: black;">, sampleSteps[layer]);<br/> }<br/><br/> std::sort(</span><span style="color: gray;">keypoints</span><span style="color: black;">.begin(), </span><span style="color: gray;">keypoints</span><span style="color: black;">.end(), </span><span style="color: #2b91af;">KeypointGreater</span><span style="color: black;">());<br/>}</span><p><strong>5.2 计算Hessian矩阵的行列式与迹calcLayerDetAndTrace</strong></p><p>这个函数首先定义了尺寸为9的第一层图像的三个模板。模板分别为一个$3\times5$、$3\times5$、$4\times5$的二维数组表示,数组的每一行表示一个黑白块的位置参数。函数里只初始化了第一层图像的模板参数,后面其他组其他层的Harr模板参数都是用resizeHaarPattern这个函数来计算的。这个函数返回的是一个SurfHF的结构体,这个结构体由两个点及一个权重构成。</p><span style="color: blue;">struct </span><span style="color: #2b91af;">SurfHF<br/></span><span style="color: black;">{<br/> </span><span style="color: blue;">int </span><span style="color: black;">p0, p1, p2, p3;<br/> </span><span style="color: blue;">float </span><span style="color: black;">w;<br/><br/> SurfHF() : p0(0), p1(0), p2(0), p3(0), w(0) {}<br/>};</span><p>resizeHaarPattern这个函数非常的巧妙,它把模板中的点坐标。转换到在积分图中的相对(模板左上角点)坐标。</p><span style="color: blue;">static void<br/></span><span style="color: black;">resizeHaarPattern(</span><span style="color: blue;">const int </span><span style="color: gray;">src</span><span style="color: black;">[][5], </span><span style="color: #2b91af;">SurfHF</span><span style="color: black;">* </span><span style="color: gray;">dst</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">n</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">oldSize</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">newSize</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">widthStep</span><span style="color: black;">)<br/>{<br/> </span><span style="color: blue;">float </span><span style="color: black;">ratio = (</span><span style="color: blue;">float</span><span style="color: black;">)</span><span style="color: gray;">newSize </span><span style="color: black;">/ </span><span style="color: gray;">oldSize</span><span style="color: black;">;<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">k = 0; k &lt; </span><span style="color: gray;">n</span><span style="color: black;">; k++)<br/> {<br/> </span><span style="color: blue;">int </span><span style="color: black;">dx1 = cvRound(ratio*</span><span style="color: gray;">src</span><span style="color: black;">[k][0]);<br/> </span><span style="color: blue;">int </span><span style="color: black;">dy1 = cvRound(ratio*</span><span style="color: gray;">src</span><span style="color: black;">[k][1]);<br/> </span><span style="color: blue;">int </span><span style="color: black;">dx2 = cvRound(ratio*</span><span style="color: gray;">src</span><span style="color: black;">[k][2]);<br/> </span><span style="color: blue;">int </span><span style="color: black;">dy2 = cvRound(ratio*</span><span style="color: gray;">src</span><span style="color: black;">[k][3]);<br/> </span><span style="color: green;">/*巧妙的坐标转换*/<br/> </span><span style="color: gray;">dst</span><span style="color: black;">[k].p0 = dy1*</span><span style="color: gray;">widthStep </span><span style="color: black;">+ dx1; </span><span style="color: green;">// 转换为一个相对距离,距离模板左上角点的 在积分图中的距离 !!important!!<br/> </span><span style="color: gray;">dst</span><span style="color: black;">[k].p1 = dy2*</span><span style="color: gray;">widthStep </span><span style="color: black;">+ dx1; <br/> </span><span style="color: gray;">dst</span><span style="color: black;">[k].p2 = dy1*</span><span style="color: gray;">widthStep </span><span style="color: black;">+ dx2;<br/> </span><span style="color: gray;">dst</span><span style="color: black;">[k].p3 = dy2*</span><span style="color: gray;">widthStep </span><span style="color: black;">+ dx2;<br/> </span><span style="color: gray;">dst</span><span style="color: black;">[k].w = </span><span style="color: gray;">src</span><span style="color: black;">[k][4] / ((</span><span style="color: blue;">float</span><span style="color: black;">)(dx2 - dx1)*(dy2 - dy1));</span><span style="color: green;">// 原来的+1,+2用 覆盖的所有像素点平均。<br/> </span><span style="color: black;">}<br/>}</span><p>在用积分图计算近似卷积时,用的是calcHaarPattern函数。这个函数比较简单,只用知道左上与右下角坐标即可。</p><span style="color: blue;">inline float </span><span style="color: black;">calcHaarPattern(</span><span style="color: blue;">const int</span><span style="color: black;">* </span><span style="color: gray;">origin</span><span style="color: black;">, </span><span style="color: blue;">const </span><span style="color: #2b91af;">SurfHF</span><span style="color: black;">* </span><span style="color: gray;">f</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">n</span><span style="color: black;">)<br/>{<br/> </span><span style="color: green;">/*orgin即为积分图,n为模板中 黑白 块的个数 */<br/> </span><span style="color: blue;">double </span><span style="color: black;">d = 0;<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">k = 0; k &lt; </span><span style="color: gray;">n</span><span style="color: black;">; k++)<br/> d += (</span><span style="color: gray;">origin</span><span style="color: black;">[</span><span style="color: gray;">f</span><span style="color: black;">[k].p0] + </span><span style="color: gray;">origin</span><span style="color: black;">[</span><span style="color: gray;">f</span><span style="color: black;">[k].p3] - </span><span style="color: gray;">origin</span><span style="color: black;">[</span><span style="color: gray;">f</span><span style="color: black;">[k].p1] - </span><span style="color: gray;">origin</span><span style="color: black;">[</span><span style="color: gray;">f</span><span style="color: black;">[k].p2])*</span><span style="color: gray;">f</span><span style="color: black;">[k].w;<br/> </span><span style="color: blue;">return </span><span style="color: black;">(</span><span style="color: blue;">float</span><span style="color: black;">)d;<br/>}</span><p>最终我们可以看到了整个calcLayerDetAndTrack的代码</p><span style="color: blue;">static void </span><span style="color: black;">calcLayerDetAndTrace(</span><span style="color: blue;">const </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">sum</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">size</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">sampleStep</span><span style="color: black;">,<br/> </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">det</span><span style="color: black;">, </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">trace</span><span style="color: black;">)<br/>{<br/> </span><span style="color: blue;">const int </span><span style="color: black;">NX = 3, NY = 3, NXY = 4;<br/> </span><span style="color: blue;">const int </span><span style="color: black;">dx_s[NX][5] = { { 0, 2, 3, 7, 1 }, { 3, 2, 6, 7, -2 }, { 6, 2, 9, 7, 1 } };<br/> </span><span style="color: blue;">const int </span><span style="color: black;">dy_s[NY][5] = { { 2, 0, 7, 3, 1 }, { 2, 3, 7, 6, -2 }, { 2, 6, 7, 9, 1 } };<br/> </span><span style="color: blue;">const int </span><span style="color: black;">dxy_s[NXY][5] = { { 1, 1, 4, 4, 1 }, { 5, 1, 8, 4, -1 }, { 1, 5, 4, 8, -1 }, { 5, 5, 8, 8, 1 } };<br/><br/> </span><span style="color: #2b91af;">SurfHF </span><span style="color: black;">Dx[NX], Dy[NY], Dxy[NXY];<br/><br/> </span><span style="color: blue;">if </span><span style="color: black;">(</span><span style="color: gray;">size </span><span style="color: black;">&gt; </span><span style="color: gray;">sum</span><span style="color: black;">.rows - 1 || </span><span style="color: gray;">size </span><span style="color: black;">&gt; </span><span style="color: gray;">sum</span><span style="color: black;">.cols - 1)<br/> </span><span style="color: blue;">return</span><span style="color: black;">;<br/> resizeHaarPattern(dx_s, Dx, NX, 9, </span><span style="color: gray;">size</span><span style="color: black;">, </span><span style="color: gray;">sum</span><span style="color: black;">.cols);<br/> resizeHaarPattern(dy_s, Dy, NY, 9, </span><span style="color: gray;">size</span><span style="color: black;">, </span><span style="color: gray;">sum</span><span style="color: black;">.cols);<br/> resizeHaarPattern(dxy_s, Dxy, NXY, 9, </span><span style="color: gray;">size</span><span style="color: black;">, </span><span style="color: gray;">sum</span><span style="color: black;">.cols);<br/><br/> </span><span style="color: green;">/* The integral image 'sum' is one pixel bigger than the source image */<br/> </span><span style="color: blue;">int </span><span style="color: black;">samples_i = 1 + (</span><span style="color: gray;">sum</span><span style="color: black;">.rows - 1 - </span><span style="color: gray;">size</span><span style="color: black;">) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">; </span><span style="color: green;">// 最大能遍历到的 行坐标,因为要减掉一个模板的尺寸<br/> </span><span style="color: blue;">int </span><span style="color: black;">samples_j = 1 + (</span><span style="color: gray;">sum</span><span style="color: black;">.cols - 1 - </span><span style="color: gray;">size</span><span style="color: black;">) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">; </span><span style="color: green;">// 最大能遍历到的 列坐标<br/><br/> /* Ignore pixels where some of the kernel is outside the image */<br/> </span><span style="color: blue;">int </span><span style="color: black;">margin = (</span><span style="color: gray;">size </span><span style="color: black;">/ 2) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">;<br/><br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">i = 0; i &lt; samples_i; i++)<br/> {<br/> </span><span style="color: green;">/*坐标为(i,j)的点是模板左上角的点,所以实际现在模板分析是的i+margin,j+margin点处的响应*/<br/> </span><span style="color: blue;">const int</span><span style="color: black;">* sum_ptr = </span><span style="color: gray;">sum</span><span style="color: black;">.ptr&lt;</span><span style="color: blue;">int</span><span style="color: black;">&gt;(i*</span><span style="color: gray;">sampleStep</span><span style="color: black;">);<br/> </span><span style="color: blue;">float</span><span style="color: black;">* det_ptr = &amp;</span><span style="color: gray;">det</span><span style="color: black;">.at&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i + margin, margin); </span><span style="color: green;">// 左边空隙为 margin<br/> </span><span style="color: blue;">float</span><span style="color: black;">* trace_ptr = &amp;</span><span style="color: gray;">trace</span><span style="color: black;">.at&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i + margin, margin);<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">j = 0; j &lt; samples_j; j++)<br/> {<br/> </span><span style="color: blue;">float </span><span style="color: black;">dx = calcHaarPattern(sum_ptr, Dx, 3);<br/> </span><span style="color: blue;">float </span><span style="color: black;">dy = calcHaarPattern(sum_ptr, Dy, 3);<br/> </span><span style="color: blue;">float </span><span style="color: black;">dxy = calcHaarPattern(sum_ptr, Dxy, 4);<br/> sum_ptr += </span><span style="color: gray;">sampleStep</span><span style="color: black;">;<br/> det_ptr[j] = dx*dy - 0.81f*dxy*dxy;<br/> trace_ptr[j] = dx + dy;<br/> }<br/> }<br/>}</span><p><strong>5.3 局部最大值搜索findMaximaInLayer</strong></p><p>这里算法思路很简单,值得注意的是里面的一些坐标的转换很巧妙,里面比较重的函数就是interpolateKeypoint函数,通过插值计算最大值点。</p><span style="color: green;">/*<br/>* Maxima location interpolation as described in "Invariant Features from<br/>* Interest Point Groups" by Matthew Brown and David Lowe. This is performed by<br/>* fitting a 3D quadratic to a set of neighbouring samples.<br/>*<br/>* The gradient vector and Hessian matrix at the initial keypoint location are<br/>* approximated using central differences. The linear system Ax = b is then<br/>* solved, where A is the Hessian, b is the negative gradient, and x is the<br/>* offset of the interpolated maxima coordinates from the initial estimate.<br/>* This is equivalent to an iteration of Netwon's optimisation algorithm.<br/>*<br/>* N9 contains the samples in the 3x3x3 neighbourhood of the maxima<br/>* dx is the sampling step in x<br/>* dy is the sampling step in y<br/>* ds is the sampling step in size<br/>* point contains the keypoint coordinates and scale to be modified<br/>*<br/>* Return value is 1 if interpolation was successful, 0 on failure.<br/>*/<br/><br/></span><span style="color: blue;">static int<br/></span><span style="color: black;">interpolateKeypoint(</span><span style="color: blue;">float </span><span style="color: gray;">N9</span><span style="color: black;">[3][9], </span><span style="color: blue;">int </span><span style="color: gray;">dx</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">dy</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">ds</span><span style="color: black;">, </span><span style="color: #2b91af;">KeyPoint</span><span style="color: black;">&amp; </span><span style="color: gray;">kpt</span><span style="color: black;">)<br/>{<br/> </span><span style="color: #2b91af;">Vec3f </span><span style="color: black;">b(-(</span><span style="color: gray;">N9</span><span style="color: black;">[1][5] - </span><span style="color: gray;">N9</span><span style="color: black;">[1][3]) / 2, </span><span style="color: green;">// Negative 1st deriv with respect to x<br/> </span><span style="color: black;">-(</span><span style="color: gray;">N9</span><span style="color: black;">[1][7] - </span><span style="color: gray;">N9</span><span style="color: black;">[1][1]) / 2, </span><span style="color: green;">// Negative 1st deriv with respect to y<br/> </span><span style="color: black;">-(</span><span style="color: gray;">N9</span><span style="color: black;">[2][4] - </span><span style="color: gray;">N9</span><span style="color: black;">[0][4]) / 2); </span><span style="color: green;">// Negative 1st deriv with respect to s<br/><br/> </span><span style="color: #2b91af;">Matx33f </span><span style="color: black;">A(<br/> </span><span style="color: gray;">N9</span><span style="color: black;">[1][3] - 2 * </span><span style="color: gray;">N9</span><span style="color: black;">[1][4] + </span><span style="color: gray;">N9</span><span style="color: black;">[1][5], </span><span style="color: green;">// 2nd deriv x, x<br/> </span><span style="color: black;">(</span><span style="color: gray;">N9</span><span style="color: black;">[1][8] - </span><span style="color: gray;">N9</span><span style="color: black;">[1][6] - </span><span style="color: gray;">N9</span><span style="color: black;">[1][2] + </span><span style="color: gray;">N9</span><span style="color: black;">[1][0]) / 4, </span><span style="color: green;">// 2nd deriv x, y<br/> </span><span style="color: black;">(</span><span style="color: gray;">N9</span><span style="color: black;">[2][5] - </span><span style="color: gray;">N9</span><span style="color: black;">[2][3] - </span><span style="color: gray;">N9</span><span style="color: black;">[0][5] + </span><span style="color: gray;">N9</span><span style="color: black;">[0][3]) / 4, </span><span style="color: green;">// 2nd deriv x, s<br/> </span><span style="color: black;">(</span><span style="color: gray;">N9</span><span style="color: black;">[1][8] - </span><span style="color: gray;">N9</span><span style="color: black;">[1][6] - </span><span style="color: gray;">N9</span><span style="color: black;">[1][2] + </span><span style="color: gray;">N9</span><span style="color: black;">[1][0]) / 4, </span><span style="color: green;">// 2nd deriv x, y<br/> </span><span style="color: gray;">N9</span><span style="color: black;">[1][1] - 2 * </span><span style="color: gray;">N9</span><span style="color: black;">[1][4] + </span><span style="color: gray;">N9</span><span style="color: black;">[1][7], </span><span style="color: green;">// 2nd deriv y, y<br/> </span><span style="color: black;">(</span><span style="color: gray;">N9</span><span style="color: black;">[2][7] - </span><span style="color: gray;">N9</span><span style="color: black;">[2][1] - </span><span style="color: gray;">N9</span><span style="color: black;">[0][7] + </span><span style="color: gray;">N9</span><span style="color: black;">[0][1]) / 4, </span><span style="color: green;">// 2nd deriv y, s<br/> </span><span style="color: black;">(</span><span style="color: gray;">N9</span><span style="color: black;">[2][5] - </span><span style="color: gray;">N9</span><span style="color: black;">[2][3] - </span><span style="color: gray;">N9</span><span style="color: black;">[0][5] + </span><span style="color: gray;">N9</span><span style="color: black;">[0][3]) / 4, </span><span style="color: green;">// 2nd deriv x, s<br/> </span><span style="color: black;">(</span><span style="color: gray;">N9</span><span style="color: black;">[2][7] - </span><span style="color: gray;">N9</span><span style="color: black;">[2][1] - </span><span style="color: gray;">N9</span><span style="color: black;">[0][7] + </span><span style="color: gray;">N9</span><span style="color: black;">[0][1]) / 4, </span><span style="color: green;">// 2nd deriv y, s<br/> </span><span style="color: gray;">N9</span><span style="color: black;">[0][4] - 2 * </span><span style="color: gray;">N9</span><span style="color: black;">[1][4] + </span><span style="color: gray;">N9</span><span style="color: black;">[2][4]); </span><span style="color: green;">// 2nd deriv s, s<br/><br/> </span><span style="color: #2b91af;">Vec3f </span><span style="color: black;">x = A.solve(b, </span><span style="color: #2f4f4f;">DECOMP_LU</span><span style="color: black;">);<br/><br/> </span><span style="color: blue;">bool </span><span style="color: black;">ok = (x[0] != 0 || x[1] != 0 || x[2] != 0) &amp;&amp;<br/> std::abs(x[0]) &lt;= 1 &amp;&amp; std::abs(x[1]) &lt;= 1 &amp;&amp; std::abs(x[2]) &lt;= 1;<br/><br/> </span><span style="color: blue;">if </span><span style="color: black;">(ok)<br/> {<br/> </span><span style="color: gray;">kpt</span><span style="color: black;">.pt.x += x[0] * </span><span style="color: gray;">dx</span><span style="color: black;">;<br/> </span><span style="color: gray;">kpt</span><span style="color: black;">.pt.y += x[1] * </span><span style="color: gray;">dy</span><span style="color: black;">;<br/> </span><span style="color: gray;">kpt</span><span style="color: black;">.size = (</span><span style="color: blue;">float</span><span style="color: black;">)cvRound(</span><span style="color: gray;">kpt</span><span style="color: black;">.size + x[2] * </span><span style="color: gray;">ds</span><span style="color: black;">);<br/> }<br/> </span><span style="color: blue;">return </span><span style="color: black;">ok;<br/>}<br/><br/></span><span style="color: blue;">static void </span><span style="color: black;">findMaximaInLayer(</span><span style="color: blue;">const </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">sum</span><span style="color: black;">, </span><span style="color: blue;">const </span><span style="color: #2b91af;">Mat</span><span style="color: black;">&amp; </span><span style="color: gray;">mask_sum</span><span style="color: black;">,<br/> </span><span style="color: blue;">const </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: #2b91af;">Mat</span><span style="color: black;">&gt;&amp; </span><span style="color: gray;">dets</span><span style="color: black;">, </span><span style="color: blue;">const </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: #2b91af;">Mat</span><span style="color: black;">&gt;&amp; </span><span style="color: gray;">traces</span><span style="color: black;">,<br/> </span><span style="color: blue;">const </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: blue;">int</span><span style="color: black;">&gt;&amp; </span><span style="color: gray;">sizes</span><span style="color: black;">, </span><span style="color: #2b91af;">vector</span><span style="color: black;">&lt;</span><span style="color: #2b91af;">KeyPoint</span><span style="color: black;">&gt;&amp; </span><span style="color: gray;">keypoints</span><span style="color: black;">,<br/> </span><span style="color: blue;">int </span><span style="color: gray;">octave</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">layer</span><span style="color: black;">, </span><span style="color: blue;">float </span><span style="color: gray;">hessianThreshold</span><span style="color: black;">, </span><span style="color: blue;">int </span><span style="color: gray;">sampleStep</span><span style="color: black;">)<br/>{<br/> </span><span style="color: green;">// Wavelet Data<br/> </span><span style="color: blue;">const int </span><span style="color: black;">NM = 1;<br/> </span><span style="color: blue;">const int </span><span style="color: black;">dm[NM][5] = { { 0, 0, 9, 9, 1 } };<br/> </span><span style="color: #2b91af;">SurfHF </span><span style="color: black;">Dm;<br/><br/> </span><span style="color: blue;">int </span><span style="color: black;">size = </span><span style="color: gray;">sizes</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">];<br/><br/> </span><span style="color: green;">// 当前层图像的大小<br/> </span><span style="color: blue;">int </span><span style="color: black;">layer_rows = (</span><span style="color: gray;">sum</span><span style="color: black;">.rows - 1) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">;<br/> </span><span style="color: blue;">int </span><span style="color: black;">layer_cols = (</span><span style="color: gray;">sum</span><span style="color: black;">.cols - 1) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">;<br/><br/> </span><span style="color: green;">// 边界区域大小,考虑的下一层的模板大小<br/> </span><span style="color: blue;">int </span><span style="color: black;">margin = (</span><span style="color: gray;">sizes</span><span style="color: black;">[</span><span style="color: gray;">layer </span><span style="color: black;">+ 1] / 2) / </span><span style="color: gray;">sampleStep </span><span style="color: black;">+ 1;<br/><br/> </span><span style="color: blue;">if </span><span style="color: black;">(!</span><span style="color: gray;">mask_sum</span><span style="color: black;">.empty())<br/> resizeHaarPattern(dm, &amp;Dm, NM, 9, size, </span><span style="color: gray;">mask_sum</span><span style="color: black;">.cols);<br/><br/> </span><span style="color: blue;">int </span><span style="color: black;">step = (</span><span style="color: blue;">int</span><span style="color: black;">)(</span><span style="color: gray;">dets</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">].step / </span><span style="color: gray;">dets</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">].elemSize());<br/><br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">i = margin; i &lt; layer_rows - margin; i++)<br/> {<br/> </span><span style="color: blue;">const float</span><span style="color: black;">* det_ptr = </span><span style="color: gray;">dets</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">].ptr&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i);<br/> </span><span style="color: blue;">const float</span><span style="color: black;">* trace_ptr = </span><span style="color: gray;">traces</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">].ptr&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i);<br/> </span><span style="color: blue;">for </span><span style="color: black;">(</span><span style="color: blue;">int </span><span style="color: black;">j = margin; j &lt; layer_cols - margin; j++)<br/> {<br/> </span><span style="color: blue;">float </span><span style="color: black;">val0 = det_ptr[j]; </span><span style="color: green;">// 中心点的值<br/> </span><span style="color: blue;">if </span><span style="color: black;">(val0 &gt; </span><span style="color: gray;">hessianThreshold</span><span style="color: black;">)<br/> {<br/> </span><span style="color: green;">// 模板左上角的坐标<br/> </span><span style="color: blue;">int </span><span style="color: black;">sum_i = </span><span style="color: gray;">sampleStep</span><span style="color: black;">*(i - (size / 2) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">);<br/> </span><span style="color: blue;">int </span><span style="color: black;">sum_j = </span><span style="color: gray;">sampleStep</span><span style="color: black;">*(j - (size / 2) / </span><span style="color: gray;">sampleStep</span><span style="color: black;">);<br/><br/> </span><span style="color: green;">/* The 3x3x3 neighbouring samples around the maxima.<br/> The maxima is included at N9[1][4] */<br/><br/> </span><span style="color: blue;">const float </span><span style="color: black;">*det1 = &amp;</span><span style="color: gray;">dets</span><span style="color: black;">[</span><span style="color: gray;">layer </span><span style="color: black;">- 1].at&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i, j);<br/> </span><span style="color: blue;">const float </span><span style="color: black;">*det2 = &amp;</span><span style="color: gray;">dets</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">].at&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i, j);<br/> </span><span style="color: blue;">const float </span><span style="color: black;">*det3 = &amp;</span><span style="color: gray;">dets</span><span style="color: black;">[</span><span style="color: gray;">layer </span><span style="color: black;">+ 1].at&lt;</span><span style="color: blue;">float</span><span style="color: black;">&gt;(i, j);<br/> </span><span style="color: blue;">float </span><span style="color: black;">N9[3][9] = { { det1[-step - 1], det1[-step], det1[-step + 1],<br/> det1[-1], det1[0], det1[1],<br/> det1[step - 1], det1[step], det1[step + 1] },<br/> { det2[-step - 1], det2[-step], det2[-step + 1],<br/> det2[-1], det2[0], det2[1],<br/> det2[step - 1], det2[step], det2[step + 1] },<br/> { det3[-step - 1], det3[-step], det3[-step + 1],<br/> det3[-1], det3[0], det3[1],<br/> det3[step - 1], det3[step], det3[step + 1] } };<br/><br/> </span><span style="color: green;">/* Check the mask - why not just check the mask at the center of the wavelet? */<br/> </span><span style="color: blue;">if </span><span style="color: black;">(!</span><span style="color: gray;">mask_sum</span><span style="color: black;">.empty())<br/> {<br/> </span><span style="color: blue;">const int</span><span style="color: black;">* mask_ptr = &amp;</span><span style="color: gray;">mask_sum</span><span style="color: black;">.at&lt;</span><span style="color: blue;">int</span><span style="color: black;">&gt;(sum_i, sum_j);<br/> </span><span style="color: blue;">float </span><span style="color: black;">mval = calcHaarPattern(mask_ptr, &amp;Dm, 1);<br/> </span><span style="color: blue;">if </span><span style="color: black;">(mval &lt; 0.5)<br/> </span><span style="color: blue;">continue</span><span style="color: black;">;<br/> }<br/><br/> </span><span style="color: green;">/* 检测val0,是否在N9里极大值,??为什么不检测极小值呢*/<br/> </span><span style="color: blue;">if </span><span style="color: black;">(val0 &gt; N9[0][0] &amp;&amp; val0 &gt; N9[0][1] &amp;&amp; val0 &gt; N9[0][2] &amp;&amp;<br/> val0 &gt; N9[0][3] &amp;&amp; val0 &gt; N9[0][4] &amp;&amp; val0 &gt; N9[0][5] &amp;&amp;<br/> val0 &gt; N9[0][6] &amp;&amp; val0 &gt; N9[0][7] &amp;&amp; val0 &gt; N9[0][8] &amp;&amp;<br/> val0 &gt; N9[1][0] &amp;&amp; val0 &gt; N9[1][1] &amp;&amp; val0 &gt; N9[1][2] &amp;&amp;<br/> val0 &gt; N9[1][3] &amp;&amp; val0 &gt; N9[1][5] &amp;&amp;<br/> val0 &gt; N9[1][6] &amp;&amp; val0 &gt; N9[1][7] &amp;&amp; val0 &gt; N9[1][8] &amp;&amp;<br/> val0 &gt; N9[2][0] &amp;&amp; val0 &gt; N9[2][1] &amp;&amp; val0 &gt; N9[2][2] &amp;&amp;<br/> val0 &gt; N9[2][3] &amp;&amp; val0 &gt; N9[2][4] &amp;&amp; val0 &gt; N9[2][5] &amp;&amp;<br/> val0 &gt; N9[2][6] &amp;&amp; val0 &gt; N9[2][7] &amp;&amp; val0 &gt; N9[2][8])<br/> {<br/> </span><span style="color: green;">/* Calculate the wavelet center coordinates for the maxima */<br/> </span><span style="color: blue;">float </span><span style="color: black;">center_i = sum_i + (size - 1)*0.5f;<br/> </span><span style="color: blue;">float </span><span style="color: black;">center_j = sum_j + (size - 1)*0.5f;<br/><br/> </span><span style="color: #2b91af;">KeyPoint </span><span style="color: black;">kpt(center_j, center_i, (</span><span style="color: blue;">float</span><span style="color: black;">)</span><span style="color: gray;">sizes</span><span style="color: black;">[</span><span style="color: gray;">layer</span><span style="color: black;">],<br/> -1, val0, </span><span style="color: gray;">octave</span><span style="color: black;">, </span><span style="color: #6f008a;">CV_SIGN</span><span style="color: black;">(trace_ptr[j]));<br/><br/> </span><span style="color: green;">/* 局部极大值插值,用Hessian,类似于SIFT里的插值,里面没有迭代5次,只进行了一次查找,why? */<br/> </span><span style="color: blue;">int </span><span style="color: black;">ds = size - </span><span style="color: gray;">sizes</span><span style="color: black;">[</span><span style="color: gray;">layer </span><span style="color: black;">- 1];<br/> </span><span style="color: blue;">int </span><span style="color: black;">interp_ok = interpolateKeypoint(N9, </span><span style="color: gray;">sampleStep</span><span style="color: black;">, </span><span style="color: gray;">sampleStep</span><span style="color: black;">, ds, kpt);<br/><br/> </span><span style="color: green;">/* Sometimes the interpolation step gives a negative size etc. */<br/> </span><span style="color: blue;">if </span><span style="color: black;">(interp_ok)<br/> {<br/> </span><span style="color: green;">/*printf( "KeyPoint %f %f %d\n", point.pt.x, point.pt.y, point.size );*/<br/> </span><span style="color: gray;">keypoints</span><span style="color: black;">.push_back(kpt);<br/> }<br/> }<br/> }<br/> }<br/> }<br/>}</span><p><strong>6. 总结</strong></p><p>总体来说,如果理解了SIFT算法,再来看SURF算法会发现思路非常简单。尤其是局部最大值查找方面,基本一致。关键还是一个用积分图来简化卷积的思路,以及怎么用不同的模板来近似原来尺度空间中的高斯滤波器。</p><p>这一篇主要讨论分析的是SURF的定位问题,下面还有SURF特征点的方向计算与描述子的生成,将在下一篇文章中详细描述。</p><img src="http://counter.cnblogs.com/blog/rss/4045979" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/ronny/p/4045979.html" target="_blank">SURF算法与源码分析、上</a>,转载请注明。</p>http://www.cnblogs.com/wjcnet/p/4046278.html近期解决问题经历和感悟 - 王金才上周四发表了一篇日志《一定要写的日志》,里面写了我遇到问题与解决问题痛苦经历,但具体遇到的问题没有细说。因为项目一直很忙,分身乏术,直到今天中午我终于完成了项目,解决了所有的技术问题,现在才有时间具体说一下所遇到的问题。但是既然写了,就把这两周遇到的所有难题和解决问题的经历和感受都说一下。 先说一下...2014-10-23T09:04:00Z2014-10-23T09:04:00Z王金才http://www.cnblogs.com/wjcnet/<p>&nbsp;上周四发表了一篇日志《一定要写的日志》,里面写了我遇到问题与解决问题痛苦经历,但具体遇到的问题没有细说。因为项目一直很忙,分身乏术,直到今天中午我终于完成了项目,解决了所有的技术问题,现在才有时间具体说一下所遇到的问题。但是既然写了,就把这两周遇到的所有难题和解决问题的经历和感受都说一下。</p><p>&nbsp; 先说一下项目背景。</p><p>&nbsp; 我们公司做了一套网上在线学习平台,是用c# .net开发的,用iis7部署在windows平台上,但是,领导层感觉这种方式代价太大,所以决定改用php开发,部署采用一键安装式部署,但是我们公司没有一个人用过php,我们都是用c# .net 开发。</p><p>&nbsp; 经过领导们商议,将任务交给了本人,项目时间截止点是10月底。我是上月(也就是9月份)23号接到的任务,接到任务后,大概用了三四天的时间将手头工作交接,在27,28号的时候,全身心研究php。</p><p>&nbsp; &nbsp;很快就放假了,我本来想在放假期间好好研究php的,但是,但是你们知道的,放假在家根本没有心思研究技术,痛痛快快的玩了7天。</p><p>&nbsp; &nbsp;放假回来了,前三天还是没有上手写程序,搭建开发环境,了解开发框架用了大概用了三四天,又用两天时间用php写了一个单表的增删改,分页,这才开始真正进行我的项目。</p><p>&nbsp; &nbsp;真正的做项目,简单的部分完成后,很快就遇到难题了。我大致把问题划分为以下几个。</p><p>&nbsp; &nbsp;<strong>①服务转换</strong>,服务转换的作用是为了把用户上传的文件,可以用flash直接播放,用的技术主要是rabbitmq,服务转换程序我们的.net版本已经做好了,并且很成熟。我要做的就是部分更改.net程序,然后用php程序向.net服务发请求,具体过程是将请求放入到rabbitmq队列中,然后由rabbitmq和.net进行通信。</p><p>&nbsp; &nbsp;<strong>②转换后的资源的预览问题</strong>,资源转换后有jpg、png、doc、docx、ppt、pptx、pdf、txt....类型,这些类型都需要预览。我们有.net版本的预览程序,我要做的就是要把.Net</p><p>程序翻译为php程序。</p><p>&nbsp; &nbsp;<strong>③在线学习flash接口实现。</strong></p><p>&nbsp; &nbsp;在线学习flash接口实现主要是和flash端人员进行协同开发,整个过程还算顺利。</p><p>&nbsp; &nbsp;服务转换遇到了种种难题。</p><p>&nbsp; &nbsp; 首先是安装rabbitmq,安装rabbitmq非常顺利,一百度一大把。</p><p>&nbsp; &nbsp; 第二步利用rabbitmq向.net转换服务发送请求。</p><p>&nbsp; &nbsp;&nbsp;<img src="http://images.cnitblog.com/blog/484140/201410/231518054025689.png" alt="" width="766" height="378" /></p><p>&nbsp; 进入官方网站查看文档,以上是导航页。这么多种请求方式,看了下,第一种就是我所需要的,果断点进去查看。</p><p>&nbsp; 重要内容如下:</p><p>&nbsp; &nbsp;<strong>&nbsp;&nbsp;1.介绍wamp原理以及重要术语<em>Producing,<em>queue,<em>Consuming</em></em></em></strong></p><p><em>&nbsp; &nbsp;<img src="http://images.cnitblog.com/blog/484140/201410/231530415274256.png" alt="" width="845" height="398" /></em></p><p>&nbsp; 英文介绍这么多,实际上就是 生产者-队列-消费者原理,在这里,我知道,我的php程序发送请求是生产者,发送的内容是消息队列,.net服务处理程序是消费者。</p><p><strong>2.发送一个消息的具体过程</strong></p><p>&nbsp;</p><p>&nbsp;<img src="http://images.cnitblog.com/blog/484140/201410/231603463404550.png" alt="" width="788" height="353" />这段文字是叙述如何在写发送实例之前,必须要安装composer和amqplib。</p><p><strong>下面一段php代码是发送实例。</strong></p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><div><div id="highlighter_847251" class="syntaxhighlighter php"><table style="height: 322px; width: 1010px;" border="0" cellspacing="0" cellpadding="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div><div class="line number18 index17 alt1">18</div><div class="line number19 index18 alt2">19</div><div class="line number20 index19 alt1">20</div><div class="line number21 index20 alt2">21</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="php plain">&lt;?php</code></div><div class="line number2 index1 alt1">&nbsp;</div><div class="line number3 index2 alt2"><code class="php keyword">require_once</code>&nbsp;<code class="php plain">__DIR__ . </code><code class="php string">'/vendor/autoload.php'</code><code class="php plain">;</code></div><div class="line number4 index3 alt1"><code class="php keyword">use</code>&nbsp;<code class="php plain">PhpAmqpLib\Connection\AMQPConnection;</code></div><div class="line number5 index4 alt2"><code class="php keyword">use</code>&nbsp;<code class="php plain">PhpAmqpLib\Message\AMQPMessage;</code></div><div class="line number6 index5 alt1">&nbsp;</div><div class="line number7 index6 alt2"><code class="php variable">$connection</code>&nbsp;<code class="php plain">= </code><code class="php keyword">new</code>&nbsp;<code class="php plain">AMQPConnection(</code><code class="php string">'localhost'</code><code class="php plain">, 5672, </code><code class="php string">'guest'</code><code class="php plain">, </code><code class="php string">'guest'</code><code class="php plain">);</code></div><div class="line number8 index7 alt1"><code class="php variable">$channel</code>&nbsp;<code class="php plain">= </code><code class="php variable">$connection</code><code class="php plain">-&gt;channel();</code></div><div class="line number9 index8 alt2">&nbsp;</div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="php variable">$channel</code><code class="php plain">-&gt;queue_declare(</code><code class="php string">'hello'</code><code class="php plain">, false, false, false, false);</code></div><div class="line number12 index11 alt1">&nbsp;</div><div class="line number13 index12 alt2"><code class="php variable">$msg</code>&nbsp;<code class="php plain">= </code><code class="php keyword">new</code>&nbsp;<code class="php plain">AMQPMessage(</code><code class="php string">'Hello World!'</code><code class="php plain">);</code></div><div class="line number14 index13 alt1"><code class="php variable">$channel</code><code class="php plain">-&gt;basic_publish(</code><code class="php variable">$msg</code><code class="php plain">, </code><code class="php string">''</code><code class="php plain">, </code><code class="php string">'hello'</code><code class="php plain">);</code></div><div class="line number15 index14 alt2">&nbsp;</div><div class="line number16 index15 alt1"><code class="php functions">echo</code>&nbsp;<code class="php string">" [x] Sent 'Hello World!'\n"</code><code class="php plain">;</code></div><div class="line number17 index16 alt2">&nbsp;</div><div class="line number18 index17 alt1"><code class="php variable">$channel</code><code class="php plain">-&gt;close();</code></div><div class="line number19 index18 alt2"><code class="php variable">$connection</code><code class="php plain">-&gt;close();</code></div><div class="line number20 index19 alt1">&nbsp;</div><div class="line number21 index20 alt2"><code class="php plain">?&gt;</code></div></div></td></tr></tbody></table></div></div></div><p> 问题就出现了安装composer和amqplib上。官方文档一点不详细,并且直接运行官方文档的&nbsp;<span class="nv">$ composer.phar install 语句还会报错。</span></p><p>&nbsp; &nbsp;安装这两个东西的注意事项我写下:</p><p>&nbsp;&nbsp;<strong>&nbsp;composer安装过程</strong></p><p>&nbsp; &nbsp;①到https://getcomposer.org/ &nbsp;网站下载composer安装包</p><p>&nbsp; &nbsp;②把php.ini文件中;extension=php_openssl.dll的分号去掉</p><p>&nbsp; &nbsp;③安装文件。</p><p>如果上述第②步没有做的话,必然报错。</p><p>&nbsp;<strong> ampqlib安装过程</strong></p><p>&nbsp; ①到https://github.com/videlalvaro/php-amqplib/archive/master.zip 下载amqplib压缩包</p><p>&nbsp; ②将压缩包解压到网站根目录,注意是根目录</p><p>&nbsp; ③创建composer.json文件到根目录内容为:</p><p>{<br />"require": {<br />"videlalvaro/php-amqplib": "2.2.*"<br />}<br />}</p><p>&nbsp;④在cmd下,将目录指向项目根目录(用cd命令),执行&nbsp;php composer.phar &nbsp; &nbsp;</p><p>执行成功后会有如下提示:</p><p>&nbsp; &nbsp;- Installing videlalvaro/php-amqplib (v2.2.6)</p><p>&nbsp; &nbsp; Downloading: 100%</p><p>&nbsp;</p><p><strong>向.net程序发指令</strong></p><p>一直失败,最后反编译.Net发送代码,写出如下php代码才成功</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><div><div id="highlighter_888714" class="syntaxhighlighter php"><table style="height: 217px; width: 948px;" border="0" cellspacing="0" cellpadding="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="php variable">$exchange</code>&nbsp;<code class="php plain">= </code><code class="php string">'router'</code><code class="php plain">;</code></div><div class="line number2 index1 alt1"><code class="php variable">$queue</code>&nbsp;<code class="php plain">= </code><code class="php string">'push_queue'</code><code class="php plain">;</code></div><div class="line number3 index2 alt2"><code class="php variable">$conn</code>&nbsp;<code class="php plain">= </code><code class="php keyword">new</code>&nbsp;<code class="php plain">AMQPConnection(</code><code class="php string">'localhost'</code><code class="php plain">, 5672, </code><code class="php string">'guest'</code><code class="php plain">, </code><code class="php string">'guest'</code><code class="php plain">,</code><code class="php string">'/'</code><code class="php plain">);</code></div><div class="line number4 index3 alt1"><code class="php variable">$ch</code>&nbsp;<code class="php plain">= </code><code class="php variable">$conn</code><code class="php plain">-&gt;channel();</code></div><div class="line number5 index4 alt2"><code class="php variable">$ch</code><code class="php plain">-&gt;queue_declare(</code><code class="php variable">$queue</code><code class="php plain">, false, true, false, false);</code></div><div class="line number6 index5 alt1"><code class="php variable">$ch</code><code class="php plain">-&gt;exchange_declare(</code><code class="php variable">$exchange</code><code class="php plain">, </code><code class="php string">'direct'</code><code class="php plain">, false, true, false);</code></div><div class="line number7 index6 alt2"><code class="php variable">$ch</code><code class="php plain">-&gt;queue_bind(</code><code class="php variable">$queue</code><code class="php plain">, </code><code class="php variable">$exchange</code><code class="php plain">);</code></div><div class="line number8 index7 alt1"><code class="php variable">$msg_body</code>&nbsp;<code class="php plain">= implode(</code><code class="php string">' '</code><code class="php plain">, </code><code class="php functions">array_slice</code><code class="php plain">(</code><code class="php variable">$argv</code><code class="php plain">, 1));</code></div><div class="line number9 index8 alt2"><code class="php variable">$arr</code><code class="php plain">=</code><code class="php keyword">array</code><code class="php plain">(</code><code class="php string">'Type'</code><code class="php plain">=&gt;</code><code class="php string">'Convert'</code><code class="php plain">,</code><code class="php string">'ID'</code><code class="php plain">=&gt;</code><code class="php variable">$docid</code><code class="php plain">);</code></div><div class="line number10 index9 alt1"><code class="php variable">$msg</code>&nbsp;<code class="php plain">= </code><code class="php keyword">new</code>&nbsp;<code class="php plain">AMQPMessage(json_encode(</code><code class="php variable">$arr</code><code class="php plain">),</code><code class="php keyword">array</code><code class="php plain">(</code><code class="php string">'content_type'</code>&nbsp;<code class="php plain">=&gt; </code><code class="php string">'text/plain'</code><code class="php plain">, </code><code class="php string">'delivery_mode'</code>&nbsp;<code class="php plain">=&gt; 2) );</code></div><div class="line number11 index10 alt2"><code class="php variable">$ch</code><code class="php plain">-&gt;basic_publish(</code><code class="php variable">$msg</code><code class="php plain">, </code><code class="php variable">$exchange</code><code class="php plain">);</code></div><div class="line number12 index11 alt1"><code class="php variable">$ch</code><code class="php plain">-&gt;close();</code></div><div class="line number13 index12 alt2"><code class="php variable">$conn</code><code class="php plain">-&gt;close();</code></div><div class="line number14 index13 alt1"><code class="php functions">echo</code>&nbsp;<code class="php string">'success'</code><code class="php plain">;</code></div></div></td></tr></tbody></table></div></div></div><p>经过多次调试,转换服务终于顺利运行。</p><p>&nbsp;</p><p><strong>资源预览问题。</strong></p><p>经过调试,png,txt,jpg,MP3,MP4等文件格式都已经可以预览,但是office文件和pdf文件不能预览。.预览office和pdf的c#代码是一致的,代码如下:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><div><div id="highlighter_495050" class="syntaxhighlighter csharp"><table border="0" cellspacing="0" cellpadding="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div><div class="line number18 index17 alt1">18</div><div class="line number19 index18 alt2">19</div><div class="line number20 index19 alt1">20</div><div class="line number21 index20 alt2">21</div><div class="line number22 index21 alt1">22</div><div class="line number23 index22 alt2">23</div><div class="line number24 index23 alt1">24</div><div class="line number25 index24 alt2">25</div><div class="line number26 index25 alt1">26</div><div class="line number27 index26 alt2">27</div><div class="line number28 index27 alt1">28</div><div class="line number29 index28 alt2">29</div><div class="line number30 index29 alt1">30</div><div class="line number31 index30 alt2">31</div><div class="line number32 index31 alt1">32</div><div class="line number33 index32 alt2">33</div><div class="line number34 index33 alt1">34</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp plain">context.Response.ContentType = </code><code class="csharp string">"application/x-shockwave-flash"</code><code class="csharp plain">;</code></div><div class="line number2 index1 alt1">&nbsp;</div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">dir = Path.Combine(dir, </code><code class="csharp string">"swf"</code><code class="csharp plain">);</code></div><div class="line number4 index3 alt1">&nbsp;</div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">int</code>&nbsp;<code class="csharp plain">pn = StringUtil.ToInt(context.Request.QueryString[</code><code class="csharp string">"pn"</code><code class="csharp plain">], 1);</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">int</code>&nbsp;<code class="csharp plain">rn = StringUtil.ToInt(context.Request.QueryString[</code><code class="csharp string">"rn"</code><code class="csharp plain">]);</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">int</code>&nbsp;<code class="csharp plain">totalPage = doc.ThumbCount;</code></div><div class="line number8 index7 alt1">&nbsp;</div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">if</code>&nbsp;<code class="csharp plain">(pn &lt; 1 || rn &lt; 1 || totalPage == 0)</code></div><div class="line number10 index9 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">dir = Path.Combine(dir, version_str + </code><code class="csharp string">".swf"</code><code class="csharp plain">);</code></div><div class="line number12 index11 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">else</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number15 index14 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">using</code>&nbsp;<code class="csharp plain">(MemoryStream ms = </code><code class="csharp keyword">new</code>&nbsp;<code class="csharp plain">MemoryStream())</code></div><div class="line number16 index15 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number17 index16 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">byte</code><code class="csharp plain">[] bytes = Encoding.UTF8.GetBytes(</code><code class="csharp string">"{\"totalPage\":\""</code>&nbsp;<code class="csharp plain">+ totalPage + </code><code class="csharp string">"\",\"fromPage\":\""</code>&nbsp;<code class="csharp plain">+ pn + </code><code class="csharp string">"\",\"toPage\":\""</code>&nbsp;<code class="csharp plain">+ (pn + rn) + </code><code class="csharp string">"\"}\r\n"</code><code class="csharp plain">);</code></div><div class="line number18 index17 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">ms.Write(bytes, 0, bytes.Length);</code></div><div class="line number19 index18 alt2">&nbsp;</div><div class="line number20 index19 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">for</code>&nbsp;<code class="csharp plain">(</code><code class="csharp keyword">int</code>&nbsp;<code class="csharp plain">i = pn; i &lt; pn + rn; i++)</code></div><div class="line number21 index20 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number22 index21 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">string</code>&nbsp;<code class="csharp plain">filename = Path.Combine(dir, version_str + </code><code class="csharp keyword">string</code><code class="csharp plain">.Format(</code><code class="csharp string">".{0}.swf"</code><code class="csharp plain">, i));</code></div><div class="line number23 index22 alt2">&nbsp;</div><div class="line number24 index23 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">if</code>&nbsp;<code class="csharp plain">(!File.Exists(filename)) </code><code class="csharp keyword">break</code><code class="csharp plain">;</code></div><div class="line number25 index24 alt2">&nbsp;</div><div class="line number26 index25 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">bytes = File.ReadAllBytes(filename);</code></div><div class="line number27 index26 alt2">&nbsp;</div><div class="line number28 index27 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">ms.Write(bytes, 0, bytes.Length);</code></div><div class="line number29 index28 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number30 index29 alt1">&nbsp;</div><div class="line number31 index30 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">context.Response.BinaryWrite(ms.ToArray());</code></div><div class="line number32 index31 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number33 index32 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">return</code><code class="csharp plain">;</code></div><div class="line number34 index33 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div></div><p>c#原理很简单,用json字符串记录 文件的分页信息,转化为字节数组并放入流中,然后循环文件并读取放入流中,最后输出流的字节数组形式。</p><p>&nbsp;</p><p>我的第一反应是:php肯定也有流的定义,于是研究php的api,发现的确有streams文档,但是我没有找到相应.net方法。文档研究了整整一天,的确没有解决方案(哪位php大神有解决方案请告之)。</p><p>第二种思路改为将json字符串读为字节数组,将文件也读为字节数组,然后合并字节数组,最后输出字节数组。</p><p>我对这个解决方案深信不疑。认为肯定可以。但是当我发现.net输出的字节数组内容和php输出的字节数组内容不一样时,顿时心灰意冷。又苦苦挣扎了近一个小时才放弃这种思路。</p><p>第三种思路,就是用php的header直接以二进制输出,这种思路是可行的,走通了,相应php代码如下:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"> $pn=$this-&gt;input-&gt;get("pn");<br/> $rn= $this-&gt;input-&gt;get("rn");<br/> $totalPage=$file_count;<br/> $json="{\"totalPage\":\"" . $totalPage . "\",\"fromPage\":\"" . $pn ."\",\"toPage\":\"" . ($pn + $rn) ."\"}\r\n";<br/> header('Content-Type: application/x-shockwave-flash'); <br/> header("Content-Transfer-Encoding: binary"); <br/> echo $json;for ($i = $pn; $i &lt; $pn + $rn; $i++)<br/> {<br/> $filename=ROOTPATH.$Dir.'/swf/'.$version.'.'.$i.'.swf';<br/> $handle=fopen($filename,"r");//使用打开模式为r<br/> $content=fread($handle,filesize($filename));//读为二进制<br/> //$filearr=file($filename);<br/> echo $content;<br/> <br/> }<br/> exit;</div><p>&nbsp;</p><p>展示一下预览office文件效果:</p><p><img src="http://images.cnitblog.com/blog/484140/201410/231647570433380.png" alt="" /></p><p><strong>&nbsp;&ldquo;当你为一个问题愁眉不解,苦苦思索,痛苦万分的时候,这个问题已经不是问题了,因为,你迟早会解决他!&rdquo;</strong></p><p>&nbsp;遇到难题,只要我们不投降,总有解决方案,因为,在技术上,没有解决不了的难题。</p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046278" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/wjcnet/p/4046278.html" target="_blank">近期解决问题经历和感悟</a>,转载请注明。</p>http://www.cnblogs.com/luoliang/p/4046131.htmlCentOS 6.5 下搭建shadowsocks达到越狱 - 求 败此文章已在本人的独立博客上了,链接。1.安装组建,其中openssl-devel已经存在系统中了。yum install build-essential autoconf libtool gcc -y #使用yum安装 2.安装gityum install git -ygit --version ....2014-10-23T08:27:00Z2014-10-23T08:27:00Z求 败http://www.cnblogs.com/luoliang/<p>此文章已在本人的独立博客上了,<a href="http://www.luoliang.me/index.php/archives/16/" target="_blank">链接</a>。</p><p>1.安装组建,其中openssl-devel已经存在系统中了。</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">yum install build-essential autoconf libtool gcc -y #使用yum安装<br/></div><p>  </p><p>2.安装git</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">yum install git -y<br/>git --version #安装完后查看版本<br/></div><p>  </p><p>3.下载shadowsocks-libev安装</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">git clone https://github.com/madeye/shadowsocks-libev.git #克隆到本地<br/>cd shadowsocks-libev <br/>./configure <br/>make <br/>make install</div><p>4.运行shadowsocks,并在后台执行</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">//注意x.x.x.x要换成自己的IP地址一般配置外网的IP<br/>nohup /usr/local/bin/ss-server -s x.x.x.x -p 8000 -k 密码 -m aes-256-cfb &amp;</div><p>5.加入开机启动</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">//把这个命令追加到开机启动文件中<br/>echo &ldquo;nohup /usr/local/bin/ss-server -s x.x.x.x -p 8000 -k 密码 -m aes-256-cfb &amp;&rdquo; &gt;&gt; /etc/rc.local<br/>//重启系统<br/>reboot</div><p>6.下载[windows版本的chrome越狱][2]<br /> 下载完直接运行,跟之前配置要一一对应好。设置如下:<br /><img src="http://www.luoliang.me/usr/uploads/2014/10/207476801.jpg" alt="" width="632" height="428" /></p><p>7.安装浏览器的插件网友放了一份在<a href="https://github.com/peimin/pic/blob/master/2014/SwitchySharp.crx" target="_blank">github</a>上 <br /> 这里的端口要注意是windows版本软件的端口,这个浏览器插件设置如下:<br /><img src="http://www.luoliang.me/usr/uploads/2014/10/839265604.jpg" alt="" width="852" height="693" /></p><p><br /><br /></p><img src="http://counter.cnblogs.com/blog/rss/4046131" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/luoliang/p/4046131.html" target="_blank">CentOS 6.5 下搭建shadowsocks达到越狱</a>,转载请注明。</p>http://www.cnblogs.com/fsjohnhuang/p/4046098.htmlJava魔法堂:打包知识点之jar - ^_^肥仔John一、前言 通过eclipse导出jar包十分方便快捷,但作为码农岂能满足GUI的便捷呢?所以一起来CLI吧!二、JAR包 JAR包是基于ZIP文件格式,用于将多个.java文件和...2014-10-23T08:19:00Z2014-10-23T08:19:00Z^_^肥仔Johnhttp://www.cnblogs.com/fsjohnhuang/<p><span style="font-size: 18px; background-color: #888888;"><strong>一、前言                               &nbsp;&nbsp;</strong></span></p><p>&nbsp; 通过eclipse导出jar包十分方便快捷,但作为码农岂能满足GUI的便捷呢?所以一起来CLI吧!</p><p>&nbsp;</p><p><span style="font-size: 18px; background-color: #888888;"><strong>二、JAR包                              </strong></span></p><p>&nbsp; JAR包是基于ZIP文件格式,用于将多个.java文件和各种资源文件,或将多个.class和各种资源打包为一个文件。用于发布,部署,封装库、组件和插件程序,从而被编译器和JVM使用。</p><p>&nbsp;</p><p><span style="font-size: 18px; background-color: #888888;"><strong>三、通过jar命令打包                         &nbsp;</strong></span></p><p><strong>&nbsp; 1. 格式&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">jar [option]* 文件名</span>&nbsp;</strong></p><p><strong>&nbsp; &nbsp; &nbsp;<em> 必选选项(并且仅能选用其中一个)</em></strong></p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-c</span>&nbsp;,创建一个jar包</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-t</span>&nbsp;,显示jar包中的内容列表</p><p>&nbsp;  &nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-x</span>&nbsp;,解压jar包</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-u</span>&nbsp;,添加文件到jar包</p><p>&nbsp; &nbsp;<em><strong> &nbsp; 可选选项</strong></em></p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-v</span>&nbsp;,生成详细报告,并输出到标准输出设备</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-m</span>&nbsp;,用于指定manifest.mf文件。(默认情况下会自动生成META-INF/MANIFEST.MF文件)</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-O</span>&nbsp;,创建jar包时不对内容进行压缩</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-M</span>&nbsp;,不自动产生manifest.mf文件</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-i</span>&nbsp;,创建jar包时创建META-INF/INDEX.LIST索引文件</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-C</span>&nbsp;,表示切换到指定目录来执行jar命令</p><p>&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">-f</span>&nbsp;,指定jar包的文件路径</p><p><strong>&nbsp; &nbsp;2. 常用示例</strong></p><p>&nbsp; &nbsp; &nbsp; &nbsp;示例的目录结构:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">/<br/>|--<span style="color: #000000;"> src<br/></span>| |-- test.<span style="color: #0000ff;">class</span><br/>|-- META-<span style="color: #000000;">INF<br/></span>| |--<span style="color: #000000;"> MAINFEST.MF<br/></span>|--<span style="color: #000000;"> MAINFEST.MF<br/></span>|--<span style="color: #000000;"> other<br/> </span>|--additional.<span style="color: #0000ff;">class</span></div><p>&nbsp; &nbsp; &nbsp; 命令:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #008000;">/*</span><span style="color: #008000;"> 1. 默认打包 </span><span style="color: #008000;">*/</span><br/><span style="color: #008000;">//</span><span style="color: #008000;"> 生成的src.jar中就含src目录和jar自动生成的META-INF目录(内含MAINFEST.MF清单文件)</span><br/>jar -<span style="color: #000000;">cvf src.jar src<br/><br/></span><span style="color: #008000;">/*</span><span style="color: #008000;"> 2. 查看包内容(jar过大时就无法查看) </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br/>jar </span>-<span style="color: #000000;">tvf src.jar<br/><br/></span><span style="color: #008000;">/*</span><span style="color: #008000;"> 3. 解压jar包 </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br/>jar </span>-<span style="color: #000000;">xvf src.jar<br/><br/></span><span style="color: #008000;">/*</span><span style="color: #008000;"> 4. 提取jar包部分内容 </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br/>jar </span>-xvf src.jar src\test.<span style="color: #0000ff;">class</span><br/><br/><span style="color: #008000;">/*</span><span style="color: #008000;"> 5. 追加内容到jar包 </span><span style="color: #008000;">*/</span><br/><span style="color: #008000;">//</span><span style="color: #008000;">追加MAINFEST.MF清单文件以外的文件,会追加整个目录结构</span><br/>jar -uvf src.jar other\additional.<span style="color: #0000ff;">class</span><br/><br/><span style="color: #008000;">//</span><span style="color: #008000;">追加清单文件,会追加整个目录结构(src.jar会包含META-INF目录)</span><br/>jar -uMvf src.jar META-<span style="color: #000000;">INF\MAINFEST.MF<br/><br/></span><span style="color: #008000;">/*</span><span style="color: #008000;"> 6. 创建自定义MAINFEST.MF的jar包 </span><span style="color: #008000;">*/</span><span style="color: #000000;"><br/>jar </span>-cMvf src.jar src META-<span style="color: #000000;">INF<br/><br/></span><span style="color: #008000;">//</span><span style="color: #008000;"> 通过-m选项配置自定义MAINFEST.MF文件时,自定义MAINFEST.MF文件必须在位于工作目录下才可以</span><br/>jar -cmvf MAINFEST.MF src.jar src</div><p>&nbsp;</p><p><span style="font-size: 18px; background-color: #888888;"><strong>三、通过Eclipse导出jar                            </strong></span></p><p>&nbsp; &nbsp;在需导出的包、类上鼠标右键点击&ldquo;Export&rdquo;,然后选择&ldquo;Java&rdquo;下的&ldquo;JAR file&rdquo;,然后就是各种下一步就OK了。</p><p><img src="http://images.cnitblog.com/blog/347002/201410/231611419659410.png" alt="" /></p><p>&nbsp;</p><p><span style="font-size: 18px; background-color: #888888;"><strong>&nbsp;四、可执行的JAR包                            </strong></span></p><p>&nbsp; &nbsp; 当jar包中包含可执行程序时,就可以通过&nbsp;<span style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">java -jar src.jar</span>&nbsp;命令来执行该可执行程序。打包的过程与上述操作无异,就是多了一步&mdash;&mdash;配置META-INF/MAINFEST.MF文件。</p><p>&nbsp; &nbsp; 关于META-INF目录以及META-INF/MAINFEST.MF清单文件的内容,将在《Java魔法堂:打包知识点之META-INF目录》中探讨。</p><p>&nbsp; &nbsp; 尊重原创,转载请注明来自:<a id="Editor_Edit_hlEntryLink" title="view: Java魔法堂:打包知识点之jar" href="http://www.cnblogs.com/fsjohnhuang/p/4046098.html" target="_blank">http://www.cnblogs.com/fsjohnhuang/p/4046098.html</a>&nbsp; ^_^肥仔John</p><p>&nbsp;</p><p><span style="font-size: 18px; background-color: #888888;"><strong>参考                                    </strong></span></p><p>http://blog.csdn.net/zhifeiyu2008/article/details/8829637</p><img src="http://counter.cnblogs.com/blog/rss/4046098" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/fsjohnhuang/p/4046098.html" target="_blank">Java魔法堂:打包知识点之jar</a>,转载请注明。</p>http://www.cnblogs.com/dreamfly2014/p/4046009.htmlhibernate+spring+mvc+Easyui框架模式下使用grid++report的总结 - guohao1989191hibernate+spring+mvc+Easyui框架模式下使用grid++report的总结2014-10-23T07:56:00Z2014-10-23T07:56:00Zguohao1989191http://www.cnblogs.com/dreamfly2014/<p>最近刚开始接触hibernate+spring+mvc+Easyui框架,也是刚开通了博客,希望能记录一下自己实践出来的东西,让其他人少走弯路。</p><p>&nbsp;&nbsp;&nbsp;&nbsp; 转让正题,以个人浅薄的认识hibernate对于开发人员的作用主要是节省了写sql连接数据库的时间,而grid++report内部提供的类来看,却是通过ajax直接连接数据库,还是需要写sql。感觉把grid++report用到这个框架里来的话,给人的感觉就是一匹快马,拉了一辆旧车,虽然速度上影响不了多少,但是审美感觉上很不爽。作为一个完美主义的程序员来说,这是不允许的。然后我就贱贱的尝试着怎么改掉它。关于hibernate+spring+mvc+Easyui框架的东西我就不说了,我只说一下grid++report的使用。</p><p>  </p><p>  </p><p>  1、打开grid++report客户端,连接数据库并绘制报表。</p><p><img src="http://images.cnitblog.com/blog/363282/201410/231534065439189.png" alt="" width="800" height="600" /></p><p>2.绘制完成后使用记事本打开.grf文件,把里面的数据库连接给清掉。</p><p><img src="http://images.cnitblog.com/blog/363282/201410/231537197773188.png" alt="" width="NaN" height="400" /></p><p>3.添加mvc的三个文件在html中载入.grf文件这个不细说,grid++的demo里多的是。</p><p>4.修改载入的数据源url</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #000000;"> ReportViewer.Stop();<br/> ReportViewer.DataURL </span>= <span style="color: #800000;">"</span><span style="color: #800000;">user/load</span><span style="color: #800000;">"</span><span style="color: #000000;">;<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;"> var BeginDate = document.getElementById("txtBeginDate").value;<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;"> var EndDate = document.getElementById("txtEndDate").value;<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;"> var DataURL = encodeURI("xmlSummary.aspx?BeginDate=" + BeginDate + "&amp;EndDate=" + EndDate);<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;"> ReportViewer.DataURL = DataURL;<br/><br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">更新查询参数更新报表付标题,设置对应静态框的&ldquo;Text&rdquo;属性<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">ReportViewer.Report.ControlByName("SubTitle").AsStaticBox.Text = "日期范围:" + BeginDate + "至" + EndDate;</span><br/><span style="color: #000000;"><br/> ReportViewer.Start();</span></div><p><br />5.在control中编写load方法获取数据源,由于框架中使用hibernate获得的数据源格式为IList&lt;T&gt;格式,而grid++中接收的是xml格式。所以需要方法把这给转换一下。</p><p>度娘告诉我是这样转</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">using</span><span style="color: #000000;"> System;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Collections.Generic;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Linq;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Text;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Xml;<br/><br/></span><span style="color: #0000ff;">namespace</span><span style="color: #000000;"> Common.ToolsHelper<br/>{<br/> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> XMLHelperToList&lt;T&gt; <span style="color: #0000ff;">where</span> T : <span style="color: #0000ff;">new</span><span style="color: #000000;">()<br/> {<br/> </span><span style="color: #0000ff;">#region</span> 实体类转成Xml<br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;summary&gt;</span><br/> <span style="color: #808080;">///</span><span style="color: #008000;"> 对象实例转成xml<br/> </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;/summary&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;param name="item"&gt;</span><span style="color: #008000;">对象实例</span><span style="color: #808080;">&lt;/param&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;returns&gt;&lt;/returns&gt;</span><br/> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> EntityToXml(T item)<br/> {<br/> IList</span>&lt;T&gt; items = <span style="color: #0000ff;">new</span> List&lt;T&gt;<span style="color: #000000;">();<br/> items.Add(item);<br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> EntityToXml(items);<br/> }<br/><br/> </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;summary&gt;</span><br/> <span style="color: #808080;">///</span><span style="color: #008000;"> 对象实例集转成xml<br/> </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;/summary&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;param name="items"&gt;</span><span style="color: #008000;">对象实例集</span><span style="color: #808080;">&lt;/param&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;returns&gt;&lt;/returns&gt;</span><br/> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span> EntityToXml(IList&lt;T&gt;<span style="color: #000000;"> items)<br/> {<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">创建XmlDocument文档</span><br/> XmlDocument doc = <span style="color: #0000ff;">new</span><span style="color: #000000;"> XmlDocument();<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">创建根元素</span><br/> XmlElement root = doc.CreateElement(<span style="color: #0000ff;">typeof</span>(T).Name + <span style="color: #800000;">"</span><span style="color: #800000;">s</span><span style="color: #800000;">"</span><span style="color: #000000;">);<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">添加根元素的子元素集</span><br/> <span style="color: #0000ff;">foreach</span> (T item <span style="color: #0000ff;">in</span><span style="color: #000000;"> items)<br/> {<br/> EntityToXml(doc, root, item);<br/> }<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">向XmlDocument文档添加根元素</span><br/><span style="color: #000000;"> doc.AppendChild(root);<br/><br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> doc.InnerXml;<br/> }<br/><br/> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> EntityToXml(XmlDocument doc, XmlElement root, T item)<br/> {<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">创建元素</span><br/> XmlElement xmlItem = doc.CreateElement(<span style="color: #0000ff;">typeof</span><span style="color: #000000;">(T).Name);<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">对象的属性集</span><br/> System.Reflection.PropertyInfo[] propertyInfo = <span style="color: #0000ff;">typeof</span>(T).GetProperties(System.Reflection.BindingFlags.Public |<span style="color: #000000;"> System.Reflection.BindingFlags.Instance);<br/><br/> </span><span style="color: #0000ff;">foreach</span> (System.Reflection.PropertyInfo pinfo <span style="color: #0000ff;">in</span><span style="color: #000000;"> propertyInfo)<br/> {<br/> </span><span style="color: #0000ff;">if</span> (pinfo != <span style="color: #0000ff;">null</span><span style="color: #000000;">)<br/> {<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">对象属性名称</span><br/> <span style="color: #0000ff;">string</span> name =<span style="color: #000000;"> pinfo.Name;<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">对象属性值</span><br/> <span style="color: #0000ff;">string</span> value =<span style="color: #000000;"> String.Empty;<br/><br/> </span><span style="color: #0000ff;">if</span> (pinfo.GetValue(item, <span style="color: #0000ff;">null</span>) != <span style="color: #0000ff;">null</span><span style="color: #000000;">)<br/> value </span>= pinfo.GetValue(item, <span style="color: #0000ff;">null</span>).ToString();<span style="color: #008000;">//</span><span style="color: #008000;">获取对象属性值<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">设置元素的属性值</span><br/><span style="color: #000000;"> xmlItem.SetAttribute(name, value);<br/> }<br/> }<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">向根添加子元素</span><br/><span style="color: #000000;"> root.AppendChild(xmlItem);<br/> }<br/><br/><br/> </span><span style="color: #0000ff;">#endregion</span><br/><br/> <span style="color: #0000ff;">#region</span> Xml转成实体类<br/><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;summary&gt;</span><br/> <span style="color: #808080;">///</span><span style="color: #008000;"> Xml转成对象实例<br/> </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;/summary&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;param name="xml"&gt;</span><span style="color: #008000;">xml</span><span style="color: #808080;">&lt;/param&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;returns&gt;&lt;/returns&gt;</span><br/> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> T XmlToEntity(<span style="color: #0000ff;">string</span><span style="color: #000000;"> xml)<br/> {<br/> IList</span>&lt;T&gt; items =<span style="color: #000000;"> XmlToEntityList(xml);<br/> </span><span style="color: #0000ff;">if</span> (items != <span style="color: #0000ff;">null</span> &amp;&amp; items.Count &gt; <span style="color: #800080;">0</span><span style="color: #000000;">)<br/> </span><span style="color: #0000ff;">return</span> items[<span style="color: #800080;">0</span><span style="color: #000000;">];<br/> </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">default</span><span style="color: #000000;">(T);<br/> }<br/><br/> </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;summary&gt;</span><br/> <span style="color: #808080;">///</span><span style="color: #008000;"> Xml转成对象实例集<br/> </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;/summary&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;param name="xml"&gt;</span><span style="color: #008000;">xml</span><span style="color: #808080;">&lt;/param&gt;</span><br/> <span style="color: #808080;">///</span> <span style="color: #808080;">&lt;returns&gt;&lt;/returns&gt;</span><br/> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> IList&lt;T&gt; XmlToEntityList(<span style="color: #0000ff;">string</span><span style="color: #000000;"> xml)<br/> {<br/> XmlDocument doc </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> XmlDocument();<br/> </span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br/> {<br/> doc.LoadXml(xml);<br/> }<br/> </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"><br/> {<br/> </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> }<br/> </span><span style="color: #0000ff;">if</span> (doc.ChildNodes.Count != <span style="color: #800080;">1</span><span style="color: #000000;">)<br/> </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">if</span> (doc.ChildNodes[<span style="color: #800080;">0</span>].Name.ToLower() != <span style="color: #0000ff;">typeof</span>(T).Name.ToLower() + <span style="color: #800000;">"</span><span style="color: #800000;">s</span><span style="color: #800000;">"</span><span style="color: #000000;">)<br/> </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;<br/><br/> XmlNode node </span>= doc.ChildNodes[<span style="color: #800080;">0</span><span style="color: #000000;">];<br/><br/> IList</span>&lt;T&gt; items = <span style="color: #0000ff;">new</span> List&lt;T&gt;<span style="color: #000000;">();<br/><br/> </span><span style="color: #0000ff;">foreach</span> (XmlNode child <span style="color: #0000ff;">in</span><span style="color: #000000;"> node.ChildNodes)<br/> {<br/> </span><span style="color: #0000ff;">if</span> (child.Name.ToLower() == <span style="color: #0000ff;">typeof</span><span style="color: #000000;">(T).Name.ToLower())<br/> items.Add(XmlNodeToEntity(child));<br/> }<br/><br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> items;<br/> }<br/><br/> </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span><span style="color: #000000;"> T XmlNodeToEntity(XmlNode node)<br/> {<br/> T item </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> T();<br/><br/> </span><span style="color: #0000ff;">if</span> (node.NodeType ==<span style="color: #000000;"> XmlNodeType.Element)<br/> {<br/> XmlElement element </span>=<span style="color: #000000;"> (XmlElement)node;<br/><br/> System.Reflection.PropertyInfo[] propertyInfo </span>= <span style="color: #0000ff;">typeof</span>(T).GetProperties(System.Reflection.BindingFlags.Public |<span style="color: #000000;"> System.Reflection.BindingFlags.Instance);<br/><br/> </span><span style="color: #0000ff;">foreach</span> (XmlAttribute attr <span style="color: #0000ff;">in</span><span style="color: #000000;"> element.Attributes)<br/> {<br/> </span><span style="color: #0000ff;">string</span> attrName =<span style="color: #000000;"> attr.Name.ToLower();<br/> </span><span style="color: #0000ff;">string</span> attrValue =<span style="color: #000000;"> attr.Value.ToString();<br/> </span><span style="color: #0000ff;">foreach</span> (System.Reflection.PropertyInfo pinfo <span style="color: #0000ff;">in</span><span style="color: #000000;"> propertyInfo)<br/> {<br/> </span><span style="color: #0000ff;">if</span> (pinfo != <span style="color: #0000ff;">null</span><span style="color: #000000;">)<br/> {<br/> </span><span style="color: #0000ff;">string</span> name =<span style="color: #000000;"> pinfo.Name.ToLower();<br/> Type dbType </span>=<span style="color: #000000;"> pinfo.PropertyType;<br/> </span><span style="color: #0000ff;">if</span> (name ==<span style="color: #000000;"> attrName)<br/> {<br/> </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (String.IsNullOrEmpty(attrValue))<br/> </span><span style="color: #0000ff;">continue</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (dbType.ToString())<br/> {<br/> </span><span style="color: #0000ff;">case</span> <span style="color: #800000;">"</span><span style="color: #800000;">System.Int32</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br/> pinfo.SetValue(item, Convert.ToInt32(attrValue), </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">case</span> <span style="color: #800000;">"</span><span style="color: #800000;">System.Boolean</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br/> pinfo.SetValue(item, Convert.ToBoolean(attrValue), </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">case</span> <span style="color: #800000;">"</span><span style="color: #800000;">System.DateTime</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br/> pinfo.SetValue(item, Convert.ToDateTime(attrValue), </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">case</span> <span style="color: #800000;">"</span><span style="color: #800000;">System.Decimal</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br/> pinfo.SetValue(item, Convert.ToDecimal(attrValue), </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">case</span> <span style="color: #800000;">"</span><span style="color: #800000;">System.Double</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br/> pinfo.SetValue(item, Convert.ToDouble(attrValue), </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> </span><span style="color: #0000ff;">default</span><span style="color: #000000;">:<br/> pinfo.SetValue(item, attrValue, </span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br/> </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br/> }<br/> </span><span style="color: #0000ff;">continue</span><span style="color: #000000;">;<br/> }<br/> }<br/> }<br/> }<br/> }<br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> item;<br/> }<br/> </span><span style="color: #0000ff;">#endregion</span><span style="color: #000000;"><br/> }<br/>}</span></div><p>&nbsp;</p><p>然后自己获取数据并Response到页面上</p><p>方法如下。</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #0000ff;">using</span><span style="color: #000000;"> System;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Collections.Generic;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Linq;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Web;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Web.Mvc;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.IO;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> CLGL.Web.Controllers;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Text;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> Wat.Common;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> Domain;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.IO.Compression;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> Newtonsoft.Json;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> System.Globalization;<br/></span><span style="color: #0000ff;">using</span><span style="color: #000000;"> Common.ToolsHelper;<br/><br/></span><span style="color: #0000ff;">namespace</span><span style="color: #000000;"> CLGL.Web.Areas.GrfDemo.Controllers<br/>{<br/> </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> UserController : Controller<br/> {<br/> </span><span style="color: #008000;">//</span><br/> <span style="color: #008000;">//</span><span style="color: #008000;"> GET: /GrfDemo/User/</span><br/> Service.IUserManager userManage { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }<br/> </span><span style="color: #008000;">//</span><span style="color: #008000;">User user = new User();</span><br/> <span style="color: #0000ff;">public</span><span style="color: #000000;"> ActionResult Index()<br/> {<br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> View();<br/> }<br/><br/> </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ActionResult Load()<br/> {<br/> IList</span>&lt;User&gt; list =<span style="color: #000000;"> userManage.LoadAll();<br/> </span><span style="color: #0000ff;">string</span> str = XMLHelperToList&lt;User&gt;<span style="color: #000000;">.EntityToXml(list);<br/> Response.Write(str);<br/> Response.End();<br/> </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> View();<br/> }<br/> }<br/>}</span></div><p>运行后,结果:</p><p><img src="http://images.cnitblog.com/blog/363282/201410/231552202773147.png" alt="" width="NaN" height="400" /></p><p>&nbsp;</p><img src="http://counter.cnblogs.com/blog/rss/4046009" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/dreamfly2014/p/4046009.html" target="_blank">hibernate+spring+mvc+Easyui框架模式下使用grid++report的总结</a>,转载请注明。</p>http://www.cnblogs.com/javaee6/p/4045861.htmllinux中inode、软链接、硬链接 - 天魂地煞1 软链接 linux中软链接理解成window中的快捷方式。创建软链接的命令 ln -s 源文文件或目录 目标文件或目录 2 硬链接 创建硬链接的命令如下 ln 源文文件或目录 目标文件或目录 3软链接和硬链接的区别 1:软链接就相当于快捷方式,删除源文件,快捷方式就没有意义了。 2:硬链接相当于...2014-10-23T07:05:00Z2014-10-23T07:05:00Z天魂地煞http://www.cnblogs.com/javaee6/<p><strong>1 软链接</strong></p> <p>linux中软链接理解成window中的快捷方式。创建软链接的命令</p> <blockquote> <p align="center"><strong>ln -s 源文文件或目录 目标文件或目录</strong></p> <p align="center"><a href="http://www.cnblogs.com/javaee6/int(15)int(15)"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://images.cnitblog.com/blog/292443/201410/231505179655345.png" width="774" height="363" /></a></p> </blockquote> <p><strong>2 硬链接</strong></p> <p>创建硬链接的命令如下</p> <blockquote> <p align="center"><strong>ln  源文文件或目录 目标文件或目录</strong></p> <p align="center"><a href="http://images.cnitblog.com/blog/292443/201410/231505186375973.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://images.cnitblog.com/blog/292443/201410/231505224654570.png" width="589" height="237" /></a></p> </blockquote> <p><strong>3软链接和硬链接的区别</strong></p> <blockquote> <p>1:软链接就相当于快捷方式,删除源文件,快捷方式就没有意义了。</p> <p>2:硬链接相当于备份了文件,但是还可以和源文件内容同步,删除源文件,硬链接文件任然有效。</p> <p>3:软链接可以跨文件系统,但是硬链接不能</p> <p>4:软链接的源文件的inode不相同,但是硬链接文件和源文件inode相同</p> </blockquote> <p> </p> <p>关于软链接和硬链接还可以看看这篇文章<a title="http://www.cnblogs.com/itech/archive/2009/04/10/1433052.html" href="http://www.cnblogs.com/itech/archive/2009/04/10/1433052.html">http://www.cnblogs.com/itech/archive/2009/04/10/1433052.html</a>。要想从底层理解软链接和硬链接则要看看关于linux中inode的知识。继续看下面。。。</p> <p><strong>4 inode</strong></p> <p align="left">网上有篇文章,对inode的理解写的非常好,猛击下面的地址,你看了之后绝对有种醍醐灌顶的感觉。</p> <p><a title="http://www.ruanyifeng.com/blog/2011/12/inode.html" href="http://www.ruanyifeng.com/blog/2011/12/inode.html">http://www.ruanyifeng.com/blog/2011/12/inode.html</a></p><img src="http://counter.cnblogs.com/blog/rss/4045861" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/javaee6/p/4045861.html" target="_blank">linux中inode、软链接、硬链接</a>,转载请注明。</p>http://www.cnblogs.com/samuelwnb/p/4045832.html我与ARM的那些事儿2JINLK烧录nor flash - samuel.wang前言 最近在研究mini2440的友善之臂,但是我拿着的是实验室早期买的开发板,在做裸机开发的过程中老是不能很好地使用最新版的minitools进行烧录,因而各种不爽,因为生成了bin文件不能很好地传到mini2440中,作为一个对开发有着强迫症的我,去各大网站上找烧录的方法,但是我找到的都是老的一...2014-10-23T06:58:00Z2014-10-23T06:58:00Zsamuel.wanghttp://www.cnblogs.com/samuelwnb/<p><span style="font-family: 微软雅黑; font-size: 14pt; background-color: #d9d9d9;">前言 </span></p><p>最近在研究mini2440的友善之臂,但是我拿着的是实验室早期买的开发板,在做裸机开发的过程中老是不能很好地使用最新版的minitools进行烧录,因而各种不爽,因为生成了bin文件不能很好地传到mini2440中,作为一个对开发有着强迫症的我,去各大网站上找烧录的方法,但是我找到的都是老的一个烧录方式的确是有些帮助,但是无法帮助我完成烧录nor flash。于是我找到了参考了一些网站的方法!</p><p><span style="font-family: 微软雅黑; font-size: 14pt; background-color: #d9d9d9;">Jlink驱动 </span></p><p>首先你得有一个jlink v8的协调器,如果没有的话,你可以在淘宝上直接买一个!</p><p>如果你有,但是你缺少驱动,OK,我从CSDN上下好了驱动!</p><p>地址:<a href="http://url.cn/QUfkrS">http://url.cn/QUfkrS</a></p><p><span style="font-family: 微软雅黑; font-size: 14pt; background-color: #d9d9d9;">Jlink for arm软件 </span></p><p>在完成你的驱动安装后,你就可以去下载jlink for arm软件来刷洗nor flash了,当然如果你没有找到这款软件,我有非常有爱地给你提供一个下载的地址。</p><p>地址:<a href="http://url.cn/QVzHBE">http://url.cn/QVzHBE</a></p><p><span style="font-family: 微软雅黑; font-size: 14pt; background-color: #d9d9d9;">Jlink for arm的配置 </span></p><p>首先,打开这款软件!</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504001213962.png" alt="" /></p><p>当然我这个是已经打开过的项目,那么我们来看看如何来开始设置jlink来与mini2440刷录!</p><p>Opions-&gt;Project settings</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504008879859.png" alt="" /></p><p>到达这一页!</p><p>选择CPU,我们先来设置CPU:</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504032627701.png" alt="" /></p><p style="margin-left: 11pt;">如图对mini2440进行相应的设置!当然不同芯片它的core ID是不同的,因此大家一定要针对自己特定的芯片进行修改,百度就是最靠谱的,网上有大量的设配!</p><p>下面就是重点了,既然你要刷写norFlash 那么你一定要选对flash芯片,那么你可以到自己的开发板看自己的flash芯片型号!</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504035743373.png" alt="" /></p><p>然后找到图中的<img src="http://images.cnitblog.com/blog/597612/201410/231504040582058.png" alt="" /></p><p>按钮!找到自己的flash芯片!</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504045583972.png" alt="" align="left" /></p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p><span style="font-family: 微软雅黑; font-size: 14pt; background-color: #d9d9d9;">下载使用norflash </span></p><p>首先,先把开发板调到norflash启动,上电!连接好jlink。</p><p>Target-&gt;connect</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504052467829.png" alt="" /></p><p>在LOG中看到Connected successfully表示你的jlink与开发板已经连接成功!</p><p>选择target-&gt;read back-&gt;entire chip ok,jinlk会直接把你的mini2440中开发板原来的flash里面保存的数据读出!</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504062937643.png" alt="" /></p><p>然后你可以将这个数据保存起来!</p><p>那么我们主要的目标是刷录flash</p><p>打开File-&gt;Open data file</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504131055494.png" alt="" /></p><p>找到Superboot2440.bin加载!</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504166689106.png" alt="" /></p><p>然后Target-&gt;Program&amp;Verify</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504177773434.png" alt="" /></p><p>因为你的flash中,本来就有bin文件,询问你是否清空烧录,点是!</p><p><img src="http://images.cnitblog.com/blog/597612/201410/231504180581648.png" alt="" /></p><p>最后会显示完成了!</p><img src="http://counter.cnblogs.com/blog/rss/4045832" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/samuelwnb/p/4045832.html" target="_blank">我与ARM的那些事儿2JINLK烧录nor flash</a>,转载请注明。</p>http://www.cnblogs.com/metoy/p/4045814.html关于中文翻译版书籍的一点小吐槽 - 永志作为一个“高大上”的软件工程师(通俗点就是屌丝程序员,^_^),时刻保持学习的斗志,才能有朝一日“出人头地”,成为他人口中的大牛。所以LZ也不敢落后,想利用工作闲暇之余多读一些书。但是备受推崇的书籍大都是英文版,好在有好多“大师们”的中文翻译版。这真是满足了像我这种英语差,而又想学高大上技术的渴.....2014-10-23T06:50:00Z2014-10-23T06:50:00Z永志http://www.cnblogs.com/metoy/<p>  作为一个&ldquo;高大上&rdquo;的软件工程师(通俗点就是屌丝程序员,^_^),时刻保持学习的斗志,才能有朝一日&ldquo;出人头地&rdquo;,成为他人口中的大牛。所以LZ也不敢落后,想利用工作闲暇之余多读一些书。但是备受推崇的书籍大都是英文版,好在有好多&ldquo;大师们&rdquo;的中文翻译版。这真是满足了像我这种英语差,而又想学高大上技术的渴望。于是找来翻译版书籍爽快的学一场。可是读着读着总是会遇到一些晦涩难懂的句子,甚至一句话连续读上几遍也还是搞不清其本意(不知道广大园友有没有过这种感触),坚持读下去真的感觉痛苦至极啊。心里不免想,是自己阅读能力差到连中文都读不懂?还是这么书作者的表达方式不适合我?还是翻译的有问题?(也许三样都有吧)</p><p>  但我不能因此就放弃学习那些&ldquo;高大上&rdquo;的知识吧,一想到比自己优秀的人比自己还努力就感到害怕。于是就试着像大神说的那样直接读英文原版书籍,虽然LZ英文很烂,但是相信咱们程序员的学习力一定可以把英语再补回来。所以这段时间一直在读英语原版书籍,当然也会时而看看中文翻译版参考一下,看看自己理解的有没有问题。就在刚刚我又读到了那种让我感觉读好几遍都不解其意的句子,然后中英对照了一下。在这里拿出,仅作吐槽娱乐,大神勿喷哦^_^。</p><p>  <img src="http://images.cnitblog.com/blog/569491/201410/231414340902166.png" alt="" /></p><p>  为了方便理解上下文,我把整段话截图贴出来。划红线部分就是最让我痛苦难受难以理解的句子。不知道广大园友们会不会像我一样读起来感觉费解,反正我是乱了。尤其是&ldquo;其他方法就必须检查这个域&rdquo;中的&ldquo;其他方法&rdquo;,实在不理解它指的什么方法。</p><p>  接下来看看英文原版,会不会更好理解呢?</p><p>  <img src="http://images.cnitblog.com/blog/569491/201410/231426471374950.png" alt="" /></p><p>  不知道英文下你有没有觉着更好理解,但我觉着这比上边的中文版好多了。这里的&ldquo;they are called ...&rdquo;中的they就是指的上文中的&ldquo;ohters methods&rdquo;,所以我可以这么理解:如果一个方法是在对象销毁后被调用,那么这个方法就必须检查对象的这个域,并...。</p><p>   如果将上面中文版中的&ldquo;其他的方法&rdquo;改成&ldquo;这些方法&rdquo;,是否更容易理解些呢?</p><p>  </p><p>&nbsp;</p><p>   简单吐槽到这,(*^__^*) 嘻嘻&hellip;&hellip;,也欢迎大家吐槽娱乐,能激起大家强化英语直接学习英语资料的斗志更好。</p><p>  </p><p>  </p><img src="http://counter.cnblogs.com/blog/rss/4045814" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/metoy/p/4045814.html" target="_blank">关于中文翻译版书籍的一点小吐槽</a>,转载请注明。</p>http://www.cnblogs.com/dosboy/p/4045773.html关于如何在Android、Java等非微软平台上建立高信任的SharePoint应用程序 - dosboy详细说明了在非微软技术平台上建立基于SharePoint 2013的provider-hosted 的APP,无论是低信任或是高信任验证方式应用程序,都是是非常可行的(PS:也是非常痛苦的),如何使用Java或是PHP代码,建立SharePoint APP,有很多技术细节,您必须要了解,1、使用Az...2014-10-23T06:32:00Z2014-10-23T06:32:00Zdosboyhttp://www.cnblogs.com/dosboy/<div class="full-post"><h1 class="post-name">关于如何在非微软平台上建立高信任的SharePoint应用程序</strong></p><p>原文 :http://blogs.msdn.com/b/kaevans/archive/2014/07/14/high-trust-sharepoint-apps-on-non-microsoft-platforms.aspx</p><p><strong><span style="color: #ffffff; background-color: #ff0000;">1.前言</span></strong></p></div><div class="full-post">&nbsp;</div><div class="full-post"><span style="color: #ffff00; font-size: 16px; background-color: #003300;">开篇明之,哥无代码发布,也不提供解决方案。 </span>我只是说明在非微软技术平台上建立低信任或是高信任应用程序是非常自由的(<span style="background-color: #ffff99;">PS:也是非常痛苦的</span>)。 作为一个微软技术的研发者,我也长时间没有写Java或是PHP代码了,文中吾力所不及给每一种平台建立示例代码,抛砖以引玉吧。<br /><p>当你去建立一个SharePoint 2013应用程序时,Visual Studio 2013,会让你选择:</p><p><span style="background-color: #ff6600; color: #ffffff;">1、使用Azure ACS </span></p><p><span style="background-color: #ff6600; color: #ffffff;">2、使用一个证书</span></p><p>&nbsp;</p><p><img src="http://images.cnitblog.com/blog/21583/201410/230934338244676.jpg" alt="" /><br /> </p><p>这个选项就意味着在问,目标 SharePoint 服务器场如何定义信任设置,并把相关设置保存在Web.config文件中。要么你使用低信任ACS设置&ldquo;client ID&rdquo;和"client secret"或是使用高信任来设置"client ID" 、"证书路径"和&ldquo;证书密码&rdquo;。</p><p><strong><span style="color: #ffffff; background-color: #ff0000;">2.理解OAuth和信任</span></strong></p><p>通过这个PodCast, <a href="http://blogs.office.com/2014/06/12/office-365-developer-podcast-episode-002-with-radi-atanassov/">Office 365 Developer Podcast: Episode 002 with Radi Atanassov</a>, Radi 详述了SharePoint 使用OAuth ,并且把它形象地称为 &ldquo;三角验证&rdquo; ,当把应用设置成使用Azure ACS的时候,应用需要去与ACS通信,提供一个&ldquo;Refresh Token&rdquo;,并且获得一个Access Token, &ldquo;Refresh Token&rdquo; 是应用程序从SharePoint 的服务器取得的,但这个"Refresh Token" 也是Azure ACS 之前发给SharePoint的。在这个模式下, 应用程序和SharePoint服务器, 不直接相信对方,而是通过Azure ACS 建立两两信任关系, 所以我们叫这&ldquo;低信任&rdquo;.&nbsp; 如果要更进一步理解这种&ldquo;OAuth舞步&rdquo;, 去这个URL 看我们的2013 session, <a title="http://channel9.msdn.com/Events/Build/2013/3-603" href="http://channel9.msdn.com/Events/Build/2013/3-603">Understanding Authentication and Permissions with Apps for SharePoint and Office</a>,&nbsp; </p><p><img src="http://images.cnitblog.com/blog/21583/201410/230954376051681.png" alt="" /><br /> </p><p>低信任模型既可以被Office 365使用也可以被独立的SharePoint 2013服务器使用。</p><p><span style="background-color: #000000; color: #ffffff;">可残酷的现实,总是发生!</span>很多客户根本没有办法去设置企业内部的SharePoint 2013与Azure ACS通信,因为Azure ACS是微软的服务器,(<span style="background-color: #ffff99;">企业内部的SharePoint 2013不允许连接外网,就算SharePoint 2013可以连外网有些国家也有防火墙不允许访问国外某些网站</span>)。很好!产品团队于是可以不选择Azure ACS,作为专业人士的我们也要清楚,对于OAuth 2.0来说,Azure ACS实现了S2S协议那可是微软王国标准的OAuth 2.0作法,那是有国际范的。在&ldquo;高信任&rdquo;的认证方案里, 因为我们考虑到SharePoint 服务器与APP 是2个非常铁的哥们,不需要第三方去保证什么。APP 使用X.509证书去给&ldquo;TOKEN&rdquo;签名,然后SharePoint 再对这个签字进行信任。</p>&ldquo;高信任&rdquo;,并不代表&ldquo;高授权&rdquo;,不是说APP可以直接去删除或是干掉服务器里的东西,&ldquo;授权&rdquo;还是通过使用APP的这个人来决定的。 只不过APP可以操纵<strong>OAuth2 access token</strong>创建的过程,不需要微软的ACS服务器来搞定。SharePoint 场的管理员使用公钥注册一个&ldquo;<strong>信任的安全TOKEN颁发者</strong>&rdquo; SPTrustedSecurityTokenIssuer, 然后App 使用这个证书的私钥 签名,正因为私钥的特性,所以 SharePoint 会信任这个APP。 <img src="http://images.cnitblog.com/blog/21583/201410/231104266835193.png" alt="" /><br /><p>可喜的是独立的服务器可以选择2者,而Office 365的APP是没有办法使用&ldquo;高信任&rdquo; 模式的, 因为作为一个微软开发者的你,黑不到OFFICE 365的服务器里去创建证书!.</p><p><em>再说了:人家微软的Office 365不信任微软的ACS服务,难道信任你的APP不成。<br /></em></p><p><strong><span style="background-color: #ff0000; color: #ffffff;">3.低信任APP与非微软平台</span></strong></p>&nbsp;如果你开发基于Office 365的程序上,哥劝你就直接使用&ldquo;低信任APP&rdquo;,这也简单,对于APP开发者的你也不管签名发证书的事情,在网页上申请Client ID和 Client Secret后,在你的代码里就是写几个程序保存一Token之类,就行了。网上这种文章,多如牛毛,例如:1. Todd Baginski 对于Node.js 上开发SharePoint 作了非常精彩的演讲。也发布了示例PHP操纵SharePoint 2013 <a href="http://code.msdn.microsoft.com/office/SharePoint-2013-Perform-8a78b8ef">SharePoint 2013: Perform operations on SharePoint Document Library from PHP site</a>.&nbsp;在这个模型里,要用到 JWT library 库去解析 由 SharePoint 发给你的context token ,过程就是得到 ACS URL, 把Refresh token 提交去得到access token.<p>2. 同样,对于你自主的SharePoint网站创建一个低信任APP也是很有可能的,下面的文章真是大拿之作:如何使用Office 365去验证一个自主SharePoint 网站的提供商承APP。</p><p><a title="http://msdn.microsoft.com/en-us/library/office/dn155905(v=office.15).aspx" href="http://msdn.microsoft.com/en-us/library/office/dn155905%28v=office.15%29.aspx">How to: Use an Office 365 SharePoint site to authorize provider-hosted apps on an on-premises SharePoint site</a>.&nbsp; </p><p>在这个模型里,你创建一个Office365的tenant,然后创建一个信任从你的服务器到Office 365的服务器,你不需要对于Office 365做任何配置,你只是需要它去读取Azure ACS给你预备的命名空间。一但配置好,无论它是不是微软平台,你就可以使用Client ID和Client Secret. 在自主的SharePoint服务场配置完毕后,你不需要担心管理X.509证书或是证书颁发者的问题,你也不需要担心开发人员有X.509密码,可能引起的安全问题,看了这篇文章,你就有点怀疑我们为啥非要搞出一个&ldquo;高信任&rdquo;模式呢??&nbsp; </p><p><img src="http://images.cnitblog.com/blog/21583/201410/231135356997632.png" alt="" /><br />&nbsp;</p><ol><li><p>&nbsp; 创建一个ACS代理(在你的独立SharePoint 服务器场)</p> </li><li><p>&nbsp;安装你的SharePoint的签字证书到你Office 365的tenancy.</p> </li><li><p>&nbsp;把合格的域名加入到你SharePoint 2013场(这个场你想去运行APP),在你的Office 365 tenancy服务的princels名称.</p> </li><li><p>&nbsp;在你的服务器场,创建一个APP管理代理。</p> </li></ol>你可以看见你的APP和其中所有的数据都存在你自己的SharePoint服务器上,你只是使用Azure ACS用来进行APP注册和验证,从开发者的角度来看,你只是简简单单地使用了一个 client ID 和client secret, 而让你可以无压力或是根本不需要自义就使用 JWT libraries .&nbsp; 这就是为什么我想:&ldquo;低信任&rdquo; 对于&ldquo;高信任&rdquo;来说,减少管理的复杂性真是无可比拟的优势。<span style="background-color: #ff0000; color: #ffffff;">4.配置高信任APP</span><p>无论你用什么样的技术建立APP,Visual Studio 、ASP.NET MVC running on IIS 或是 Azure Web Sites,或是使用Eclipse 或是 Tomcat (Apache and Linux), 这个注册的步骤,是完全一样的,如下的命令必须由管理员在控制台的界面中完成,主要的目的就是完成X.509证书的信任配置:</p><div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:4d4cbcbc-5efd-4f68-a706-52e23b7a57d5" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">PowerShell for High Trust Apps</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #008000;">#Tell SharePoint to trust the certificate</span></li><li><span style="background: #ffffff; color: #bd63c5;">$publicCertPath<span style="background: #ffffff; color: #000000;"> = <span style="background: #ffffff; color: #a31515;">"C:\HighTrust.cer"</span></span></span></li><li><span style="background: #ffffff; color: #bd63c5;">$certificate<span style="background: #ffffff; color: #000000;"> = <span style="background: #ffffff; color: #ff8c00;">Get-PfxCertificate<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #bd63c5;">$publicCertPath</span></span></span></span></span></li><li><span style="background: #ffffff; color: #ff8c00;">New-SPTrustedRootAuthority<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">-Name<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #a31515;">"HighTrust"<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">-Certificate<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #bd63c5;">$certificate</span></span></span></span></span></span></span></span></span></li><li>&nbsp;</li><li><span style="background: #ffffff; color: #008000;">#Get the tenant ID.&nbsp;&nbsp;For on-premises default installations,</span></li><li><span style="background: #ffffff; color: #008000;">#this will be the same as the SharePoint farm ID</span></li><li><span style="background: #ffffff; color: #bd63c5;">$spweb<span style="background: #ffffff; color: #000000;"> = <span style="background: #ffffff; color: #ff8c00;">Get-SPWeb<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #a31515;">"https://mysite.contoso.com"</span></span></span></span></span></li><li><span style="background: #ffffff; color: #bd63c5;">$realm<span style="background: #ffffff; color: #000000;"> = <span style="background: #ffffff; color: #ff8c00;">Get-SPAuthenticationRealm<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">-ServiceContext<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #bd63c5;">$spweb<span style="background: #ffffff; color: #000000;">.Site</span></span></span></span></span></span></span></span></li><li>&nbsp;</li><li><span style="background: #ffffff; color: #008000;">#Specify the issuer ID</span></li><li><span style="background: #ffffff; color: #bd63c5;">$issuerID<span style="background: #ffffff; color: #000000;"> = <span style="background: #ffffff; color: #a31515;">"b77a601b-3133-4567-bb37-f147f61dd332"</span></span></span></li><li><span style="background: #ffffff; color: #bd63c5;">$fullIssuerIdentifier<span style="background: #ffffff; color: #000000;"> = <span style="background: #ffffff; color: #bd63c5;">$issuerId<span style="background: #ffffff; color: #000000;"> + <span style="background: #ffffff; color: #a31515;">'@'<span style="background: #ffffff; color: #000000;"> + <span style="background: #ffffff; color: #bd63c5;">$realm</span></span></span></span></span></span></span></li><li>&nbsp;</li><li><span style="background: #ffffff; color: #008000;">#Create a trusted security token issuer based on the certificate</span></li><li><span style="background: #ffffff; color: #ff8c00;">New-SPTrustedSecurityTokenIssuer<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">-Name<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #a31515;">"Contoso S2S HighTrust Apps"<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">-Certificate<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #bd63c5;">$certificate<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">-RegisteredIssuerName<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #bd63c5;">$fullIssuerIdentifier<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #008080;">IsTrustBroker</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></li><li>&nbsp;</li><li><span style="background: #ffffff; color: #008000;">#IISRESET is needed, otherwise settings won't be applied for 24 hours</span></li><li><span style="background: #ffffff; color: #ff8c00;">iisreset</span></li></ol> </div> </div> </div><p>&nbsp;</p><p>完全的配置步骤,可以参考如下的文章:</p>&nbsp;&ldquo;<a title="http://msdn.microsoft.com/en-us/library/office/fp179901(v=office.15).aspx" href="http://msdn.microsoft.com/en-us/library/office/fp179901%28v=office.15%29.aspx">How to: Create high-trust apps for SharePoint 2013 (advanced topic)</a>&rdquo;.&nbsp;这个APP将会使用证书,证书密码和颁发的ID去得到一个ACCESS TOKEN, Visual Studio提供了这样的工具去完成这个。<p><img src="http://images.cnitblog.com/blog/21583/201410/231158173087719.png" alt="" /></p><p>&nbsp;</p><p><span style="color: #ffffff; background-color: #ff0000;">可悲呀! </span>非微软的程序,必须要去管理这些值,以去得到Access Token。</p><p><strong><span style="background-color: #ff0000; color: #ffffff;">4. JWT Tokens</span></strong></p><p>SharePoint使用JWT tokens 来进行OAuth认证。可别让这个英文&ldquo;token&rdquo; 吓坏你这个好基友了,你就把这个东东当成非常非常非常(此处省略127字) 复杂的加密方式.&nbsp; JWT tokens 是 JSON 对象, 这意味着它就是name-value pairs这种形式,感兴趣你可以读读 The <a href="http://openid.net/specs/draft-jones-json-web-token-07.html">JWT specification draft</a> 。</p><p>给SharePoint 的 access token 再介绍一次好了!再说一次! 她就是JWT token,&nbsp;</p><p>如何你还想了解它, 可以读读这个哦! &ldquo;<a title="http://blogs.msdn.com/b/kaevans/archive/2013/08/25/creating-a-fiddler-extension-for-sharepoint-2013-app-tokens.aspx" href="http://blogs.msdn.com/b/kaevans/archive/2013/08/25/creating-a-fiddler-extension-for-sharepoint-2013-app-tokens.aspx">Creating a Fiddler Extension for SharePoint 2013 App Tokens</a>&rdquo;.&nbsp; </p><p><img src="http://images.cnitblog.com/blog/21583/201410/231208445744453.png" alt="" /><br /> </p><p>上面可以看到其明文就是一对对键-值,它有12小时的有效期,取得后你就可以&ldquo;为所欲为&rdquo;哦。。。。。。具体内容 如下表所示:</p><table border="1" cellspacing="0" cellpadding="2"><tbody><tr><td valign="top">aud</td><td valign="top">Audience.&nbsp; The value is 00000003-0000-0ff1-ce00-00000000/<strong>&lt;hostname&gt;</strong>@<strong>&lt;realm*&gt;</strong>&nbsp; .&nbsp;&nbsp;&nbsp; The hostname is the FQDN of the web application root or the host-header site collection root.&nbsp; The realm is the GUID that represents the SharePoint tenant.</td> </tr><tr><td valign="top">iss</td><td valign="top">Issuer. <strong>&lt;IssuerID&gt;</strong>@<strong>&lt;realm*&gt;</strong>. The issuer ID is obtained when you register the SPTrustedIdentityTokenIssuer. The realm is the GUID that represents the SharePoint tenant.</td> </tr><tr><td valign="top">nbf</td><td valign="top">Not before. The Unix epoch time upon which the token started being valid.</td> </tr><tr><td valign="top">exp</td><td valign="top">Expires. The Unix epoch time upon which the token expires.</td> </tr><tr><td valign="top">nameid</td><td valign="top">The identifier for the user (more info below)</td> </tr><tr><td valign="top">nii</td><td valign="top">The identity provider used to rehydrate the user.&nbsp; One of the values: <br />urn:office:idp:activedirectory <br />urn:office:idp:forms:membershipprovidername <br />trusted:samlprovidername (as noted in Steve Peschka&rsquo;s example below, this is what is actually configured as opposed to the documentation)</td> </tr><tr><td valign="top">actortoken</td><td valign="top">The token for the application. </td> </tr> </tbody></table><p><em>* 现实又是可爱的,当你安装了SharePoint 2013, 只有一个tenant ID, realm与SharePoint farm ID又一样,可以通过PowerShell的命令:</em></p><p><em>Get -SPFarm | select ID 得到。</em></p><p>下面我们再搞定:actortoken.&nbsp; 这与outer token相反,actortoken 标识的是APP.</p><table border="1" cellspacing="0" cellpadding="2"><tbody><tr><td valign="top">aud</td><td valign="top">Audience.&nbsp; The value is 00000003-0000-0ff1-ce00-00000000/<strong>&lt;hostname&gt;</strong>@<strong>&lt;realm*&gt;</strong>&nbsp; .&nbsp;&nbsp;&nbsp; The hostname is the FQDN of the web application root or the host-header site collection root.&nbsp; The realm is the GUID that represents the SharePoint tenant.</td> </tr><tr><td valign="top">iss</td><td valign="top">Issuer.&nbsp; <strong>&lt;IssuerID&gt;</strong>@<strong>&lt;realm*&gt;</strong>.&nbsp; The issuer ID is obtained when you register the SPTrustedIdentityTokenIssuer.&nbsp; The realm is the GUID that represents the SharePoint tenant.</td> </tr><tr><td valign="top">nbf</td><td valign="top">Not before.&nbsp; The Unix epoch time upon which the token started being valid.</td> </tr><tr><td valign="top">exp</td><td valign="top">Expires. The Unix epoch time upon which the token expires.</td> </tr><tr><td valign="top">nameid</td><td valign="top">Identifier for the app.&nbsp; <strong>&lt;Client ID&gt;@&lt;realm&gt;</strong>.&nbsp; The client ID uniquely identifies your app, this is provided by using AppRegNew.aspx or provided when registering an app in the Office Marketplace.</td> </tr> </tbody></table><p>Inner token, outer token&hellip;太奇怪了,哥就不翻译了,以免又错了, 看例子! 我们我假定使用这些值,这样容易理解一点,同样我们上例中的示例值,也是一样的:</p><table border="1" cellspacing="0" cellpadding="2"><tbody><tr><td style="text-align: left;" valign="top">SharePoint site</td><td valign="top">mysite.contoso.com</td> </tr><tr><td style="text-align: left;" valign="top">SharePoint realm ID</td><td valign="top">6305dc22-8cb8-4da3-8e76-8d0bbc0499a5</td> </tr><tr><td valign="top">SPTrustedSecurityTokenIssuer issuer ID</td><td valign="top">b77a601b-3133-4567-bb37-f147f61dd332</td> </tr><tr><td valign="top">Client ID</td><td valign="top">06d847ca-011f-4965-ac1f-5ad14740ad89</td> </tr> </tbody></table><p>最后, 解码TOKEN的代码我们使用了上例的示例值:</p><div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:806e1f7e-2583-40d0-b00c-61d57c1eb7a5" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Sample Access Token Body</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li>{</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">aud:&nbsp;&nbsp;&nbsp;&nbsp;00000003-0000-0ff1-ce00-000000000000/mysite.contoso.com@6305dc22-8cb8-4da3-8e76-8d0bbc0499a5,</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">iss:&nbsp;&nbsp;&nbsp;&nbsp;b77a601b-3133-4567-bb37-f147f61dd332@6305dc22-8cb8-4da3-8e76-8d0bbc0499a5,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">nameid: s-1-5-21-3304015898-3601453682-3711364722-500,</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">nii:&nbsp;&nbsp;&nbsp;&nbsp;urn:office:idp:activedirectory,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">nbf:&nbsp;&nbsp;&nbsp;&nbsp;1320176785,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">exp:&nbsp;&nbsp;&nbsp;&nbsp;1320219985,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">actortoken:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">aud:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00000003-0000-0ff1-ce00-000000000000/mysite.contoso.com@6305dc22-8cb8-4da3-8e76-8d0bbc0499a5,</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">iss:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b77a601b-3133-4567-bb37-f147f61dd332@6305dc22-8cb8-4da3-8e76-8d0bbc0499a5,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">nameid:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;06d847ca-011f-4965-ac1f-5ad14740ad89@6305dc22-8cb8-4da3-8e76-8d0bbc0499a5,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">nbf:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1320176785,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">exp:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1320219985,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;trustedfordelegation: <span style="background: #ffffff; color: #0000ff;">true</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li><span style="background: #ffffff; color: #000000;">}</span></li></ol> </div> </div> </div><p>看看你就会明白,拆开内容里面没有多少变量。</p><p>ACS模式的 S2S 协议号称是标准的 OAuth 2.0 模型,你也可以参考学习下: <a title="http://msdn.microsoft.com/en-us/library/hh631177(v=office.12).aspx" href="http://msdn.microsoft.com/en-us/library/hh631177%28v=office.12%29.aspx">[MS-SPS2SAUTH]: OAuth 2.0 Authentication Protocol: SharePoint Profile</a>. </p><p><strong><span style="background-color: #ff0000; color: #ffffff;">5."高信任"APP 与非微软平台 </span></strong></p><p>好吧,兄弟是我误导你了,你如果这样还在坚持使用&ldquo;高信任&rdquo;APP,有些事情我还得和你交待清楚。 如果你不在微软平台下开发这种APP,你会发现找遍MSDN你都没有没有办法找到一个不使用<span style="background-color: #ff0000; color: #ffffff; font-size: 18px;">TokenHelper.cs</span>,的例子。而文件中的类,有巨长的代码,你根本无法把这个东东改造成非微软的一平台的代码。</p><p><span style="color: #ffffff; font-size: 18px; background-color: #ff0000;">TokenHelper.cs,真正的作用在于帮助你去解码和加密Jwt TOKEN。</span></p><p>当你创建一个新的APP,如果你使用Visual Studio ,它会自动很容易地自动化地帮你填上所有相关的 OAuth 对象和值的什么的。</p><p>这个类就是TokenHelper.cs,它即有方法可以让你通过Azure ACS 来使用&ldquo;低信任&rdquo; apps,也有方法去实现&ldquo;高信任&rdquo;</p><div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:7ca39c62-e763-4ee7-8850-8f21f6e09c87" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Windows Identity</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #0000ff;">public<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> GetS2SAccessTokenWithWindowsIdentity(</span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">Uri<span style="background: #ffffff; color: #000000;"> targetApplicationUri,</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">WindowsIdentity<span style="background: #ffffff; color: #000000;"> identity)</span></span></span></li><li><span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> realm = <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.IsNullOrEmpty(Realm) ? GetRealmFromTargetUrl(targetApplicationUri) : Realm;</span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">JsonWebTokenClaim<span style="background: #ffffff; color: #000000;">[] claims = identity != <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;"> ? GetClaimsWithWindowsIdentity(identity) : <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> GetS2SAccessTokenWithClaims(targetApplicationUri.Authority, realm, claims);</span></span></span></li><li><span style="background: #ffffff; color: #000000;">}</span></li></ol> </div> </div> </div>上面的方法接受一个WindowsIdentity,然后创建一个Access token。 因为这个方法是接收WindowsIdentity的,它看起来不像可以被非微软技术平台所用,但是我们看看其中所用的这个方法:GetClaimsWithWindowsIdentity, 没有什么特别之和呀!!!<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:07ed154e-751f-4473-9cfa-fa782ab12e04" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Claims Identity</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">private<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">JsonWebTokenClaim<span style="background: #ffffff; color: #000000;">[] GetClaimsWithWindowsIdentity(<span style="background: #ffffff; color: #2b91af;">WindowsIdentity<span style="background: #ffffff; color: #000000;"> identity)</span></span></span></span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">JsonWebTokenClaim<span style="background: #ffffff; color: #000000;">[] claims = <span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">JsonWebTokenClaim<span style="background: #ffffff; color: #000000;">[]</span></span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">JsonWebTokenClaim<span style="background: #ffffff; color: #000000;">(NameIdentifierClaimType, identity.User.Value.ToLower()),</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">JsonWebTokenClaim<span style="background: #ffffff; color: #000000;">(<span style="background: #ffffff; color: #a31515;">"nii"<span style="background: #ffffff; color: #000000;">, <span style="background: #ffffff; color: #a31515;">"urn:office:idp:activedirectory"<span style="background: #ffffff; color: #000000;">)</span></span></span></span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">};</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> claims;</span></span></span></li><li><span style="background: #ffffff; color: #000000;">}</span></li></ol> </div> </div> </div><p>代码所做的,无非就是加了2个claim ,第1个叫nameid,它的值是sid,第2个叫nil, 告诉SharePoint如何去把nameid值映射到一个identity provider,在这个情况下,nil值就是&ldquo;urn:office:idp:activedirectory&rdquo;.&nbsp;&nbsp; 参数&ldquo;nameid&rdquo; 和&ldquo;nii&rdquo; 对SharePoint是特定的, 你可以把这2个声明(claim)加到 the JWT token.</p><p><strong><span style="background-color: #ff0000; color: #ffffff;">6.值从哪来</span></strong></p><p>TokenHelper.cs是Visual Studio生成的,如果你使用其它的平台,你就必须改造.&nbsp; 值到哪里去的问题我们上一节已经搞定,现在我们就搞定值从哪里来的问题。</p><p><strong>issuerid</strong></p><p>当你创建注册SPTrustedSecurityTokenIssuer时,issuer ID就生成了,这是 GUID 全部小写.</p><p><strong>Client ID</strong></p><p>你通过 AppRegNew.aspx 注册APP时填的或是自动生成的。</p><p><strong>realm</strong></p><p>访问SharePoint 网站的如下url: &ldquo;/_vti_bin/client.svc&rdquo; ,在访问的时候加上这个的HTTP head: <span style="background-color: #ff0000;"><span style="color: #ffffff;">"Authorization: Bearer "</span>.</span>&nbsp; 参考TokenHelper.cs中的方式:</p><div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:bac6af9e-045d-4685-bb09-9d4759ce4676" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Obtaining the Realm</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">public<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> GetRealmFromTargetUrl(<span style="background: #ffffff; color: #2b91af;">Uri<span style="background: #ffffff; color: #000000;"> targetApplicationUri)</span></span></span></span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">WebRequest<span style="background: #ffffff; color: #000000;"> request = <span style="background: #ffffff; color: #2b91af;">WebRequest<span style="background: #ffffff; color: #000000;">.Create(targetApplicationUri + <span style="background: #ffffff; color: #a31515;">"/_vti_bin/client.svc"<span style="background: #ffffff; color: #000000;">);</span></span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">request.Headers.Add(<span style="background: #ffffff; color: #a31515;">"Authorization: Bearer "<span style="background: #ffffff; color: #000000;">);</span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">try</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">using<span style="background: #ffffff; color: #000000;"> (request.GetResponse())</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">catch<span style="background: #ffffff; color: #000000;"> (<span style="background: #ffffff; color: #2b91af;">WebException<span style="background: #ffffff; color: #000000;"> e)</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (e.Response == <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">)</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> bearerResponseHeader = e.Response.Headers[<span style="background: #ffffff; color: #a31515;">"WWW-Authenticate"<span style="background: #ffffff; color: #000000;">];</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.IsNullOrEmpty(bearerResponseHeader))</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">const<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> bearer = <span style="background: #ffffff; color: #a31515;">"Bearer realm=\""<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">int<span style="background: #ffffff; color: #000000;"> bearerIndex = bearerResponseHeader.IndexOf(bearer, <span style="background: #ffffff; color: #2b91af;">StringComparison<span style="background: #ffffff; color: #000000;">.Ordinal);</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (bearerIndex &lt; 0)</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">int<span style="background: #ffffff; color: #000000;"> realmIndex = bearerIndex + bearer.Length;</span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (bearerResponseHeader.Length &gt;= realmIndex + 36)</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> targetRealm = bearerResponseHeader.Substring(realmIndex, 36);</span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">Guid<span style="background: #ffffff; color: #000000;"> realmGuid;</span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (<span style="background: #ffffff; color: #2b91af;">Guid<span style="background: #ffffff; color: #000000;">.TryParse(targetRealm, <span style="background: #ffffff; color: #0000ff;">out<span style="background: #ffffff; color: #000000;"> realmGuid))</span></span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> targetRealm;</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></li><li><span style="background: #ffffff; color: #000000;">}</span></li></ol> </div> </div> </div><p>上述代码很简单,转成你的平台的代码就行了,对于O365来说,它设计就是给很多云用户使用的,realm对每一个云用户是不同的。&nbsp; </p><p><span style="background-color: #ffff99;"><em>有点意思: 如果你在&ldquo;低信任&rdquo;APP那节,配置了你的服务器与O365服务器之间的信任的话,realm的值是变化的哦。</em></span></p><p><strong><span style="background-color: #ff6600; color: #ffffff;">nameid and niia</span></strong></p><p>当配置&ldquo;高信任&rdquo; apps, MSDN 文档声明Web Application 必须使用 Windows Authentication.&nbsp; 记住在你的APP和SharePoint之间唯一的安全的通信就是JWT token在认证的头&ldquo;Bearer &rdquo;,这是通过SSl传送的。当在TokenHelper中的代码使用WindowsIdentity所做的唯一事情就是得到SID,没有别的目标。所以,唯一的理由APP的Web Application要求使用Windows 验证方式,就是因为如何让TokenHelper.cs使用WindowsIdentity 对象得到用户的SID.&nbsp; 你可以改变TokenHelper.cs具体做法使用其它方法得到用户的SID.</p><p>前一节 &ldquo;JWT Tokens&rdquo; 介绍了nameid (outer token) 它的值是 SID, 从一个 WindowsIdentity 对象得到.&nbsp; 作为非微软技术大拿的兄弟你怎样去做,得到使用者的SID 呢?</p><p>1. 使用LDAP 这个模型去从Active Directory得到信息.&nbsp;</p><p>一个哥们用PHP搞定他了,您可以看看: <a href="http://www.hotscripts.com/forums/php/54914-php-get-users-sid-active-directory-via-ldap.html">PHP - Get users SID from Active Directory via LDAP</a>.&nbsp;</p>2. 如果这个用户并不是AD中的怎么办? 我们可以使用 ADFS 或是 Ping 或是 其它一些 SAML provider,&nbsp; 我特别喜欢这个方式,你可以跟随我的做法,这用到 FBA 、SAML claims&nbsp; Steve Peschka 有文章, <a title="http://blogs.technet.com/b/speschka/archive/2012/12/07/using-sharepoint-apps-with-saml-and-fba-sites-in-sharepoint-2013.aspx" href="http://blogs.technet.com/b/speschka/archive/2012/12/07/using-sharepoint-apps-with-saml-and-fba-sites-in-sharepoint-2013.aspx">Using SharePoint Apps with SAML and FBA Sites in SharePoint 2013</a>,这是使用 SAML or FBA 用户的话,这个方法怎么写。<div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:00323b2e-53d2-4a49-9553-e9bfac9f64a7" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Assert the user identity</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">private<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> JsonWebTokenClaim[] GetClaimsWithClaimsIdentity(</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">System.Security.Principal.<span style="background: #ffffff; color: #2b91af;">IPrincipal<span style="background: #ffffff; color: #000000;"> UserPrincipal,</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">IdentityClaimType SamlIdentityClaimType, TokenHelper.ClaimsUserIdClaim id,</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">ClaimProviderType IdentityClaimProviderType)</span></li><li><span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #008000;">//if an identity claim was not found, then exit</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.IsNullOrEmpty(id.ClaimsIdClaimValue))</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">;</span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">Hashtable<span style="background: #ffffff; color: #000000;"> claimSet = <span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">Hashtable<span style="background: #ffffff; color: #000000;">();</span></span></span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #008000;">//you always need nii claim, so add that</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">claimSet.Add(<span style="background: #ffffff; color: #a31515;">"nii"<span style="background: #ffffff; color: #000000;">, <span style="background: #ffffff; color: #a31515;">"temp"<span style="background: #ffffff; color: #000000;">);</span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #008000;">//set up the nii claim and then add the smtp or sip claim separately</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (IdentityClaimProviderType == ClaimProviderType.SAML)</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">claimSet[<span style="background: #ffffff; color: #a31515;">"nii"<span style="background: #ffffff; color: #000000;">] = <span style="background: #ffffff; color: #a31515;">"trusted:"<span style="background: #ffffff; color: #000000;"> + TrustedProviderName.ToLower();&nbsp;&nbsp;<span style="background: #ffffff; color: #008000;">//was urn:office:idp:trusted:, but this does not seem to align with what SPIdentityClaimMapper uses</span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">else</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">claimSet[<span style="background: #ffffff; color: #a31515;">"nii"<span style="background: #ffffff; color: #000000;">] = <span style="background: #ffffff; color: #a31515;">"urn:office:idp:forms:"<span style="background: #ffffff; color: #000000;"> + MembershipProviderName.ToLower();</span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #008000;">//plug in UPN claim if we're using that</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">if<span style="background: #ffffff; color: #000000;"> (id.ClaimsIdClaimType == CLAIMS_ID_TYPE_UPN)</span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">claimSet.Add(<span style="background: #ffffff; color: #a31515;">"upn"<span style="background: #ffffff; color: #000000;">, id.ClaimsIdClaimValue.ToLower());</span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #008000;">//now create the JsonWebTokenClaim array</span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #2b91af;">List<span style="background: #ffffff; color: #000000;">&lt;JsonWebTokenClaim&gt; claimList = <span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">List<span style="background: #ffffff; color: #000000;">&lt;JsonWebTokenClaim&gt;();</span></span></span></span></span></span></span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">foreach<span style="background: #ffffff; color: #000000;"> (<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> key <span style="background: #ffffff; color: #0000ff;">in<span style="background: #ffffff; color: #000000;"> claimSet.Keys)</span></span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">{</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">claimList.Add(<span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> JsonWebTokenClaim(key, (<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">)claimSet[key]));</span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;">}</span></li><li>&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span style="background: #ffffff; color: #000000;"><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> claimList.ToArray();</span></span></span></li><li><span style="background: #ffffff; color: #000000;">}</span></li></ol> </div> </div> </div><p><strong>&nbsp;</strong></p>上例中,它加入了 nameid 和nii 2个声明, nameid 被映射到了 UPN, email, 或是SIP.&nbsp; 在文章中,它解释也这3个属性的详细作用. 如何你的SharePoint 服务器使用 FBA 或是 SAML 来声明用户, 这个资源对你将非常有用! 最重要的是,这会加深你对&ldquo;高信任&rdquo;模式APP中如何使用用户配置文件服务的重要理解。 User Profile Service Application也很重要哦,兄弟你有兴趣多多研究下面2篇吧!<p><a title="http://blogs.msdn.com/b/kaevans/archive/2013/05/23/sharepoint-2013-user-profile-sync-for-claims-users.aspx" href="http://blogs.msdn.com/b/kaevans/archive/2013/05/23/sharepoint-2013-user-profile-sync-for-claims-users.aspx">SharePoint 2013 User Profile Sync for Claims Users</a></p><p><a href="http://blogs.technet.com/b/speschka/archive/2012/08/15/oauth-and-the-rehydrated-user-in-sharepoint-2013-how-d-they-do-that-and-what-do-i-need-to-know.aspx">OAuth and the Rehydrated User in SharePoint 2013 &ndash; How&rsquo;d They do That and What do I Need to Know</a></p><p>正因为我们的APP运行在各种不用的平台上,甚至使用不用的验证架构所有很难保证用户都是使用AD的,既然SharePoint可以使用不同的用户那么你的程序也应该兼容,不是嘛?</p><p>&nbsp;</p><p><strong><span style="background-color: #ff0000; color: #ffffff;">7. X.509证书</span></strong></p><p>当你创建一个&ldquo;高信任&rdquo;APP,如果你使用Visual Studio ,你必须提供一个路径去生成一个证书和证书密码,X.509 证书用于对Access Token进行签名。这个签名就像Oauth2的客户密码(client secret)的作用一样,在很高级别Json对象序列化成一个字串,这个字串是base64 Url编码的,然后再应用签名。 同样的步骤,在我们使用ACS 验证方式时也发生,不过这时用于签名的是client secret,所以你应该可以找到一个库用来形成JWT token然后还能进行签名的操作(当然是X.509)。</p>Visual Stdio 程序会在创建APP时,自动地引用 Microsoft.IdentityModel.Extensions. 我使用反编工具Telerik JustDecompile 反编了 Microsoft.IdentityModel.Extensions 我使用Visual Studio 2013 创建使用证书的SharePoint APP 的项目, 移除Microsoft.IdentityModel.Extensions, 添加上我自己的 Microsoft.IdentityModel.Extensions项目.&nbsp; 下面就 JWT token 创建和签名再进行一点扩展. <br /><p>步骤似乎是这样:</p><ol><li>JWT token 有2个部分:头、正文.&nbsp; 头指示了它的类型 (JWT) 和算法, 正文就像我们之前说的 access token那样 之间用点分隔 &ldquo;.&rdquo; </li><li>头被编码成JSON, 编码方式:base64UrlEncoded. </li><li>正文被编码成JSON, 编码方式:base64UrlEncoded. </li><li>2个base64UrlEncoded 值使用点连接 &ldquo;.&rdquo; </li><li>结果使用 X.509 证书,使用RSA SHA256 签名算法,和SHA256 数字算法. </li><li>上一步结果继续进行base64URLEncoded编码 </li><li>第 4 步结果排在第6步结果前, 用点连接 &ldquo;.&rdquo; </li></ol><p>这有点代码,让你可以理解这个过程:</p><div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:f65d09cc-5170-4b0c-bcad-40c09c74164c" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Code Snippet</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #2b91af;">IDictionary<span style="background: #ffffff; color: #000000;">&lt;<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">, <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">&gt; headerClaims = jwt.CreateHeaderClaims();</span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #2b91af;">IDictionary<span style="background: #ffffff; color: #000000;">&lt;<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">, <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">&gt; payloadClaims = jwt.CreatePayloadClaims();</span></span></span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> encodedHeader = <span style="background: #ffffff; color: #2b91af;">Base64UrlEncoder<span style="background: #ffffff; color: #000000;">.Encode(headerClaims.EncodeToJson());</span></span></span></span></li><li><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> encodedBody = <span style="background: #ffffff; color: #2b91af;">Base64UrlEncoder<span style="background: #ffffff; color: #000000;">.Encode(payloadClaims.EncodeToJson());</span></span></span></span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> formattedClaims = <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.Format(<span style="background: #ffffff; color: #2b91af;">CultureInfo<span style="background: #ffffff; color: #000000;">.InvariantCulture, <span style="background: #ffffff; color: #a31515;">"{0}.{1}"<span style="background: #ffffff; color: #000000;">, encodedHeader, encodedBody);</span></span></span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> encodedSignature = <span style="background: #ffffff; color: #0000ff;">this<span style="background: #ffffff; color: #000000;">.Sign(formattedClaims, jwt.SigningCredentials);</span></span></span></span></li><li>&nbsp;</li><li><span style="background: #ffffff; color: #0000ff;">return<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.Format(<span style="background: #ffffff; color: #2b91af;">CultureInfo<span style="background: #ffffff; color: #000000;">.InvariantCulture, <span style="background: #ffffff; color: #a31515;">"{0}.{1}.{2}"<span style="background: #ffffff; color: #000000;">, encodedHeader, encodedBody, encodedSignature);</span></span></span></span></span></span></span></span></li></ol> </div> </div> </div><p>这边的&ldquo;jwt.SigningCredentials&rdquo; 是什么?&nbsp; 你看看 TokenHelper.cs,就知道这就是&nbsp; X.509 证书. 在你的平台上, 你需要一个密码和私钥去生成结果。&nbsp; </p><div id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:da5de3d2-347a-4c7d-8892-117bd2e0e089" class="wlWriterEditableSmartContent" style="float: none; margin: 0px; display: inline; padding: 0px;"><div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt;"><div style="background: #000080; color: #fff; font-family: Verdana, Tahoma, Arial, sans-serif; font-weight: bold; padding: 2px 5px;">Code Snippet</div><div style="background: #ddd; overflow: auto;"><ol style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;" start="1"><li><span style="background: #ffffff; color: #0000ff;">private<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">readonly<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> ClientSigningCertificatePath = <span style="background: #ffffff; color: #2b91af;">WebConfigurationManager<span style="background: #ffffff; color: #000000;">.AppSettings.Get(<span style="background: #ffffff; color: #a31515;">"ClientSigningCertificatePath"<span style="background: #ffffff; color: #000000;">);</span></span></span></span></span></span></span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #0000ff;">private<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">readonly<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;"> ClientSigningCertificatePassword = <span style="background: #ffffff; color: #2b91af;">WebConfigurationManager<span style="background: #ffffff; color: #000000;">.AppSettings.Get(<span style="background: #ffffff; color: #a31515;">"ClientSigningCertificatePassword"<span style="background: #ffffff; color: #000000;">);</span></span></span></span></span></span></span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #0000ff;">private<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">readonly<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">X509Certificate2<span style="background: #ffffff; color: #000000;"> ClientCertificate = (<span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.IsNullOrEmpty(ClientSigningCertificatePath) || <span style="background: #ffffff; color: #0000ff;">string<span style="background: #ffffff; color: #000000;">.IsNullOrEmpty(ClientSigningCertificatePassword)) ? <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;"> : <span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">X509Certificate2<span style="background: #ffffff; color: #000000;">(ClientSigningCertificatePath, ClientSigningCertificatePassword);</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></li><li><span style="background: #ffffff; color: #0000ff;">private<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">static<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #0000ff;">readonly<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">X509SigningCredentials<span style="background: #ffffff; color: #000000;"> SigningCredentials = (ClientCertificate == <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;">) ? <span style="background: #ffffff; color: #0000ff;">null<span style="background: #ffffff; color: #000000;"> : <span style="background: #ffffff; color: #0000ff;">new<span style="background: #ffffff; color: #000000;"> <span style="background: #ffffff; color: #2b91af;">X509SigningCredentials<span style="background: #ffffff; color: #000000;">(ClientCertificate, <span style="background: #ffffff; color: #2b91af;">SecurityAlgorithms<span style="background: #ffffff; color: #000000;">.RsaSha256Signature, <span style="background: #ffffff; color: #2b91af;">SecurityAlgorithms<span style="background: #ffffff; color: #000000;">.Sha256Digest);</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></li></ol> </div> </div> </div><p>过程我们可以用图表指示如下:</p><p>&nbsp;</p><p><img src="http://images.cnitblog.com/blog/21583/201410/231348397153536.png" alt="" /><br /> </p><p>X.509 证书 ,在如一下地方一致: 注册token、创建APP、导出公钥到Sharepoint、SharePoint服务器管理注册SPTrustedSecurityTokenIssuer.&nbsp; 要让SharePoint和 非微软技术和谐共生&ldquo;high trust&rdquo; 模式下, 需要对JWT token 进行正确使用理解, 正确插入2个声明nii 和nameid, 对token 使用X.509 证书签名。</p><p><strong><span style="background-color: #ff0000; color: #ffffff;">8.其它平台的JWT Libraries</span></strong></p><p>想到提升开发效率,工具也是不可少的.&nbsp; 大量的JWT libraries可用.&nbsp; 试试看下面.</p><ul><li><a title="https://github.com/auth0/java-jwt" href="https://github.com/auth0/java-jwt">https://github.com/auth0/java-jwt</a> &ndash;&nbsp; Java </li><li><a title="https://github.com/firebase/php-jwt" href="https://github.com/firebase/php-jwt">https://github.com/firebase/php-jwt</a> &ndash; A PHP JWT library </li><li><a title="https://github.com/michaelrhanson/jwt-js" href="https://github.com/michaelrhanson/jwt-js">https://github.com/michaelrhanson/jwt-js</a> &ndash; JWT implemented in JavaScript, used with Node.js </li></ul><p>&nbsp;</p><p>在我搞东搞西的研究的时候, 我注意到没有针对ACS验证方式:S2S实现的库, 。。。。。。。</p><p>小手真疼,没人柔柔。。。。使用&ldquo;低信任&rdquo; 吧,别搞那么麻烦。</p><p><strong><span style="background-color: #ff0000; color: #ffffff;">9.Office 365 APIs</span></strong></p><p><span style="background-color: #ff0000;"><span style="color: #ffffff;">Office 365</span></span>,&nbsp; 挺好的O365 APIs,也不错,O365 API 有强大的能力去建立Web Site、本地程序、 iOS、 Android和其它使用O365数据的应用程序,都是通过REST APIs 和标准的 OAuth.&nbsp; 就像前面我们解释的&ldquo;低信任&rdquo; APP 很容易使用JWT library库一样, O365 APIs也是。</p><p>为改进验证的方式,现使用标准的OAuth 流.&nbsp; 同样 TokenHelper.cs,&nbsp; 微软推出了Active Directory Authentication Library (ADAL) 用来让 JWT 使用Azure Active Directory 更方便,ADAL 库提供很多方法,其中包括获得 access token, 这样就能在HTTP 头中添加 &ldquo;Authorization: Bearer &ldquo;.&nbsp; 使用时无需要考虑X.509 证书或是修改现有的库, 你可以配置你的APP使用 Azure Active Directory 然后调用 O365 API.&nbsp; </p><p>此文对些有很深的研究:, <a href="http://blogs.msdn.com/b/kaevans/archive/2014/04/23/call-multiple-services-with-one-login-prompt-using-adal.aspx">Call Multiple Services with One Login Prompt Using ADAL</a>,</p><p>通过使用Azure Active Directory,完成一个APP,这个APP就是一个REST 调用, 很容易转成你的平台代码。</p><p>微软的&ldquo;Microsoft Open Technologies group&lsquo;&nbsp; 已经建立了很多关于Active Directory Authentication Library (ADAL) 的非微软平台的库:&nbsp; </p><ul><li><a href="https://github.com/MSOpenTech/azure-activedirectory-library-for-java">ADAL library for Java</a> </li><li><a title="https://github.com/MSOpenTech/azure-activedirectory-library-for-android" href="https://github.com/MSOpenTech/azure-activedirectory-library-for-android">ADAL library for Android</a> </li><li><a title="https://github.com/MSOpenTech/azure-activedirectory-library-for-ios" href="https://github.com/MSOpenTech/azure-activedirectory-library-for-ios">ADAL library for iOS</a> </li><li><a title="https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs" href="https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs">ADAL library for Node.js</a> </li></ul><p>如果 O365 上开发APP, 直接用这些个API吧,简单地把一些ADAL示例转成以上的平台的APP,那是多美好的一天。</p><p><strong><span style="background-color: #ff0000; color: #ffffff;">10. 总结</span></strong></p><p>最重要的部分都已经给你讲了, 解码token,获得变量的值,还包括 X.509 签名如何工作,也告诉你了 nameid 和nii 声明是怎么回事,</p><p>包括如何使用FBA 和SAML 的用户我都讲到了。&nbsp; </p><p><strong>信息你就自己看看吧:</strong></p><p><a title="http://openid.net/specs/draft-jones-json-web-token-07.html" href="http://openid.net/specs/draft-jones-json-web-token-07.html">JWT Specification Draft</a></p><p><a title="http://channel9.msdn.com/Events/Build/2013/3-603" href="http://channel9.msdn.com/Events/Build/2013/3-603">Understanding Authentication and Permissions with Apps for SharePoint and Office</a></p><p><a title="http://blogs.msdn.com/b/kaevans/archive/2013/05/23/sharepoint-2013-user-profile-sync-for-claims-users.aspx" href="http://blogs.msdn.com/b/kaevans/archive/2013/05/23/sharepoint-2013-user-profile-sync-for-claims-users.aspx">SharePoint 2013 User Profile Sync for Claims Users</a></p><p><a href="http://blogs.technet.com/b/speschka/archive/2012/08/15/oauth-and-the-rehydrated-user-in-sharepoint-2013-how-d-they-do-that-and-what-do-i-need-to-know.aspx">OAuth and the Rehydrated User in SharePoint 2013 &ndash; How&rsquo;d They do That and What do I Need to Know</a></p><p><a href="http://www.hotscripts.com/forums/php/54914-php-get-users-sid-active-directory-via-ldap.html">PHP - Get users SID from Active Directory via LDAP</a></p><p><a href="http://code.msdn.microsoft.com/office/SharePoint-2013-Perform-8a78b8ef">SharePoint 2013: Perform operations on SharePoint Document Library from PHP site</a> </p><p><a title="http://blogs.technet.com/b/speschka/archive/2012/12/07/using-sharepoint-apps-with-saml-and-fba-sites-in-sharepoint-2013.aspx" href="http://blogs.technet.com/b/speschka/archive/2012/12/07/using-sharepoint-apps-with-saml-and-fba-sites-in-sharepoint-2013.aspx">Using SharePoint Apps with SAML and FBA Sites in SharePoint 2013</a></p><p><a title="https://github.com/auth0/java-jwt" href="https://github.com/auth0/java-jwt">https://github.com/auth0/java-jwt</a> &ndash; A Java JWT library </p><p><a title="https://github.com/firebase/php-jwt" href="https://github.com/firebase/php-jwt">https://github.com/firebase/php-jwt</a> &ndash; A PHP JWT library </p><p><a title="https://github.com/michaelrhanson/jwt-js" href="https://github.com/michaelrhanson/jwt-js">https://github.com/michaelrhanson/jwt-js</a> &ndash; JWT implemented in JavaScript, used with Node.js </p><p><a href="https://github.com/MSOpenTech/azure-activedirectory-library-for-java">ADAL library for Java</a> </p><p><a title="https://github.com/MSOpenTech/azure-activedirectory-library-for-android" href="https://github.com/MSOpenTech/azure-activedirectory-library-for-android">ADAL library for Android</a> </p><p><a title="https://github.com/MSOpenTech/azure-activedirectory-library-for-ios" href="https://github.com/MSOpenTech/azure-activedirectory-library-for-ios">ADAL library for iOS</a> </p><p><a title="https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs" href="https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs">ADAL library for Node.js</a></p></div><img src="http://counter.cnblogs.com/blog/rss/4045773" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/dosboy/p/4045773.html" target="_blank">关于如何在Android、Java等非微软平台上建立高信任的SharePoint应用程序</a>,转载请注明。</p>http://www.cnblogs.com/boota/p/4045320.htmlc++对象内存模型之虚析构函数篇(3) - fly1000经过前两篇的分析,说实话, 现在的我是比较晕的。但仍然坚持自己的学习方法,先自己“理所当然”的理解,再去求证官方说法。毕竟东西是别人定的,规则是别人的。1 http://www.cnblogs.com/boota/p/4040310.html2 http://www.cnblogs.com/boot...2014-10-23T06:07:00Z2014-10-23T06:07:00Zfly1000http://www.cnblogs.com/boota/<p>经过前两篇的分析,说实话, 现在的我是比较晕的。但仍然坚持自己的学习方法,先自己&ldquo;理所当然&rdquo;的理解,再去求证官方说法。毕竟东西是别人定的,规则是别人的。</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #008080;">1</span> http:<span style="color: #008000;">//</span><span style="color: #008000;">www.cnblogs.com/boota/p/4040310.html</span><br/><span style="color: #008080;">2</span> http:<span style="color: #008000;">//</span><span style="color: #008000;">www.cnblogs.com/boota/p/4043282.html</span></div><p>这次是讨论的情形是:有继承关系,单一继承,父类有虚析构函数。(子类有没有虚析构函数不影响,这个结论可以验证,就不另做讨论)</p><p>上代码:</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #008080;"> 1</span> #include &lt;iostream&gt;<br/><span style="color: #008080;"> 2</span> <span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span><span style="color: #000000;"> std;<br/></span><span style="color: #008080;"> 3</span> <br/><span style="color: #008080;"> 4</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> A<br/></span><span style="color: #008080;"> 5</span> <span style="color: #000000;">{<br/></span><span style="color: #008080;"> 6</span> <span style="color: #0000ff;">public</span><span style="color: #000000;">:<br/></span><span style="color: #008080;"> 7</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> ia;<br/></span><span style="color: #008080;"> 8</span> <br/><span style="color: #008080;"> 9</span> A ():ia(<span style="color: #800080;">15</span><span style="color: #000000;">)<br/></span><span style="color: #008080;">10</span> <span style="color: #000000;"> { <br/></span><span style="color: #008080;">11</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">12</span> <span style="color: #0000ff;">virtual</span> ~<span style="color: #000000;">A ()<br/></span><span style="color: #008080;">13</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">14</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">~A</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">15</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">16</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> f()<br/></span><span style="color: #008080;">17</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">18</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">A:f()</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;">endl;<br/></span><span style="color: #008080;">19</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">20</span> <span style="color: #000000;">};<br/></span><span style="color: #008080;">21</span> <br/><span style="color: #008080;">22</span> <span style="color: #0000ff;">class</span> B : <span style="color: #0000ff;">public</span><span style="color: #000000;"> A<br/></span><span style="color: #008080;">23</span> <span style="color: #000000;">{<br/></span><span style="color: #008080;">24</span> <span style="color: #0000ff;">public</span><span style="color: #000000;"> :<br/></span><span style="color: #008080;">25</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> ib;<br/></span><span style="color: #008080;">26</span> <br/><span style="color: #008080;">27</span> B():ib(<span style="color: #800080;">31</span><span style="color: #000000;">){}<br/></span><span style="color: #008080;">28</span> <span style="color: #0000ff;">virtual</span> ~<span style="color: #000000;">B()<br/></span><span style="color: #008080;">29</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">30</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">~B</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;"> endl; <br/></span><span style="color: #008080;">31</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">32</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> f()<br/></span><span style="color: #008080;">33</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">34</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">B:f()</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;"> endl; <br/></span><span style="color: #008080;">35</span> <span style="color: #000000;"> }<br/></span><span style="color: #008080;">36</span> <br/><span style="color: #008080;">37</span> <span style="color: #000000;">};<br/></span><span style="color: #008080;">38</span> <br/><span style="color: #008080;">39</span> typedef <span style="color: #0000ff;">void</span> (*<span style="color: #000000;">F)();<br/></span><span style="color: #008080;">40</span> <br/><span style="color: #008080;">41</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> main()<br/></span><span style="color: #008080;">42</span> <span style="color: #000000;">{<br/></span><span style="color: #008080;">43</span> <br/><span style="color: #008080;">44</span> F pf =<span style="color: #000000;"> NULL;<br/></span><span style="color: #008080;">45</span> B *b = <span style="color: #0000ff;">new</span><span style="color: #000000;"> B();<br/></span><span style="color: #008080;">46</span> <span style="color: #0000ff;">int</span> **p = (<span style="color: #0000ff;">int</span> **<span style="color: #000000;">)b;<br/></span><span style="color: #008080;">47</span> <br/><span style="color: #008080;">48</span> <span style="color: #0000ff;">int</span> flag = <span style="color: #800080;">2</span><span style="color: #000000;"> ;<br/></span><span style="color: #008080;">49</span> pf = (F)p[<span style="color: #800080;">0</span><span style="color: #000000;">][flag];<br/></span><span style="color: #008080;">50</span> <span style="color: #000000;"> pf();<br/></span><span style="color: #008080;">51</span> <br/><span style="color: #008080;">52</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">END</span><span style="color: #800000;">"</span>&lt;&lt;p[<span style="color: #800080;">0</span>][<span style="color: #800080;">3</span>] &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">53</span> cout &lt;&lt; b-&gt;ia &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">54</span> cout &lt;&lt; b-&gt;ib &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">55</span> <br/><span style="color: #008080;">56</span> cout &lt;&lt; <span style="color: #0000ff;">sizeof</span>(A) &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">57</span> cout &lt;&lt; <span style="color: #0000ff;">sizeof</span>(B) &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">58</span> }</div><p>&nbsp;程序输出 :</p><p>flag=0;</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">~B<br/>~A<br/>END0<br/>15<br/>31<br/>8<br/>12<br/></div><p>flag=1;</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">~B<br/>~A<br/>END0<br/>4069160<br/>31<br/>8<br/>12<br/></div><p>flag=2;</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">B:f()<br/>END0<br/>15<br/>31<br/>8<br/>12<br/></div><p>分析:</p><p>说实话,自己在这里真不知道该怎么分析了。于是在程序最后面加了一个delete b,貌似得见云开见明月,貌似。。。</p><p>见代码</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"><span style="color: #008080;"> 1</span> #include &lt;iostream&gt;<br/><span style="color: #008080;"> 2</span> <span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span><span style="color: #000000;"> std;<br/></span><span style="color: #008080;"> 3</span> <br/><span style="color: #008080;"> 4</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> A<br/></span><span style="color: #008080;"> 5</span> <span style="color: #000000;">{<br/></span><span style="color: #008080;"> 6</span> <span style="color: #0000ff;">public</span><span style="color: #000000;">:<br/></span><span style="color: #008080;"> 7</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> ia;<br/></span><span style="color: #008080;"> 8</span> <br/><span style="color: #008080;"> 9</span> A ():ia(<span style="color: #800080;">15</span><span style="color: #000000;">)<br/></span><span style="color: #008080;">10</span> <span style="color: #000000;"> { <br/></span><span style="color: #008080;">11</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">12</span> <span style="color: #0000ff;">virtual</span> ~<span style="color: #000000;">A ()<br/></span><span style="color: #008080;">13</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">14</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">~A</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">15</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">16</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> f()<br/></span><span style="color: #008080;">17</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">18</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">A:f()</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;">endl;<br/></span><span style="color: #008080;">19</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">20</span> <span style="color: #000000;">};<br/></span><span style="color: #008080;">21</span> <br/><span style="color: #008080;">22</span> <span style="color: #0000ff;">class</span> B : <span style="color: #0000ff;">public</span><span style="color: #000000;"> A<br/></span><span style="color: #008080;">23</span> <span style="color: #000000;">{<br/></span><span style="color: #008080;">24</span> <span style="color: #0000ff;">public</span><span style="color: #000000;"> :<br/></span><span style="color: #008080;">25</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> ib;<br/></span><span style="color: #008080;">26</span> <br/><span style="color: #008080;">27</span> B():ib(<span style="color: #800080;">31</span><span style="color: #000000;">){}<br/></span><span style="color: #008080;">28</span> <span style="color: #0000ff;">virtual</span> ~<span style="color: #000000;">B()<br/></span><span style="color: #008080;">29</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">30</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">~B</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;"> endl; <br/></span><span style="color: #008080;">31</span> <span style="color: #000000;"> } <br/></span><span style="color: #008080;">32</span> <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> f()<br/></span><span style="color: #008080;">33</span> <span style="color: #000000;"> {<br/></span><span style="color: #008080;">34</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">B:f()</span><span style="color: #800000;">"</span> &lt;&lt;<span style="color: #000000;"> endl; <br/></span><span style="color: #008080;">35</span> <span style="color: #000000;"> }<br/></span><span style="color: #008080;">36</span> <br/><span style="color: #008080;">37</span> <span style="color: #000000;">};<br/></span><span style="color: #008080;">38</span> <br/><span style="color: #008080;">39</span> typedef <span style="color: #0000ff;">void</span> (*<span style="color: #000000;">F)();<br/></span><span style="color: #008080;">40</span> <br/><span style="color: #008080;">41</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> main()<br/></span><span style="color: #008080;">42</span> <span style="color: #000000;">{<br/></span><span style="color: #008080;">43</span> <br/><span style="color: #008080;">44</span> F pf =<span style="color: #000000;"> NULL;<br/></span><span style="color: #008080;">45</span> B *b = <span style="color: #0000ff;">new</span><span style="color: #000000;"> B();<br/></span><span style="color: #008080;">46</span> <span style="color: #0000ff;">int</span> **p = (<span style="color: #0000ff;">int</span> **<span style="color: #000000;">)b;<br/></span><span style="color: #008080;">47</span> <br/><span style="color: #008080;">48</span> <span style="color: #0000ff;">int</span> flag = <span style="color: #800080;">2</span><span style="color: #000000;"> ;<br/></span><span style="color: #008080;">49</span> pf = (F)p[<span style="color: #800080;">0</span><span style="color: #000000;">][flag];<br/></span><span style="color: #008080;">50</span> <span style="color: #000000;"> pf();<br/></span><span style="color: #008080;">51</span> <br/><span style="color: #008080;">52</span> cout &lt;&lt; <span style="color: #800000;">"</span><span style="color: #800000;">END</span><span style="color: #800000;">"</span>&lt;&lt;p[<span style="color: #800080;">0</span>][<span style="color: #800080;">3</span>] &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">53</span> cout &lt;&lt; b-&gt;ia &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">54</span> cout &lt;&lt; b-&gt;ib &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">55</span> <br/><span style="color: #008080;">56</span> cout &lt;&lt; <span style="color: #0000ff;">sizeof</span>(A) &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">57</span> cout &lt;&lt; <span style="color: #0000ff;">sizeof</span>(B) &lt;&lt;<span style="color: #000000;"> endl;<br/></span><span style="color: #008080;">58</span> <span style="color: #000000;"> delete b;<br/></span><span style="color: #008080;">59</span> }</div><p>输出:</p><p>flag=0</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">~B<br/>~A<br/>END0<br/>15<br/>31<br/>8<br/>12<br/>~A<br/></div><p>flag=1</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">~B<br/>~A<br/>END0<br/>3807016<br/>31<br/>8<br/>12<br/>[段错误]<br/></div><p>调试发现段错误发生在代码的58行,即delete b这句。是不是有点感觉了。</p><p>flag=2;</p><div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;">B:f()<br/>END0<br/>15<br/>31<br/>8<br/>12<br/>~B<br/>~A<br/></div><p>这下可以写点分析了,不然冏死了。</p><p>flag=0时,先执行了虚函数表第一个元素指定的析构函数,对后面的影响是delete语句只执行了A的析构函数,这说明第一个元素是B的析构函数,尼玛,为什么数据ia,ib都没有变???理论上来说,A有虚析构函数,delete b这句是应该输出~B\n~A\n,此时由于先执行了虚函数表中第一个函数,delete只执行了A的析构函数,说明b已经退化成指向A的对象的指针。数据没变,不过数据是合法的,这个可以写个复杂点的类来验证。综上,是不是可以得出第一个析构函数,靠,不知道干嘛的,存疑。</p><p>flag=1时,就很正常了。段错误也有了,数据显示不正常,再加上输出也是执行B与A的析构函数的效果,充分说明虚函数表第二个元素就是B的析构函数。这里再猜一次,第一个是A的,或者只是一个效果,表明是A的子类,so还是不知道干嘛的。</p><p>flag=2时,这里就皆大欢喜了。没什么可说的。</p><p>所以,我们的结论就在这里停住了,貌似三个代码都表明,虚析构函数的第二个是本类的析构函数,其它等我再写个复杂点的代码,中间有指针申请空间的那种,这个在栈里玩的代码,估计是很难引起段错误。</p><p>照例内存图示画一个,如下:</p><p><img src="http://images.cnitblog.com/blog/609670/201410/231404479497803.jpg" alt="" /></p><p> </p><img src="http://counter.cnblogs.com/blog/rss/4045320" width="1" height="1" alt=""/><br/><p>本文链接:<a href="http://www.cnblogs.com/boota/p/4045320.html" target="_blank">c++对象内存模型之虚析构函数篇(3)</a>,转载请注明。</p>

高级...
微信扫一扫
关注无线梦工厂
返回主页 手机网推广 加入Timewe 关于我们 加入收藏

触屏版,3G,Wap,手机网站,浏览器,pc版,在线,嵌入式,Wap浏览器,电脑上的Wap浏览器 各主流搜索引擎收录Timewe
(R)2009-2019 Timewe 时维网络科技
简体/繁体