<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_熬夜的虫子</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/60674/rss</id><updated>2012-05-28T07:12:55Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/60674/rss"/><entry><id>http://www.cnblogs.com/dubing/archive/2012/03/31/2426588.html</id><title type="text">第一次技术总监岗位面试</title><summary type="text">准备是充分的 过程是激情的 结果是悲摧的留坑 后补</summary><published>2012-03-31T02:57:00Z</published><updated>2012-03-31T02:57:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2012/03/31/2426588.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2012/03/31/2426588.html"/><content type="html">&lt;p&gt;准备是充分的 过程是激情的 结果是悲摧的&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;留坑 后补&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2426588.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2012/03/31/2426588.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2012/02/22/2363206.html</id><title type="text">.Net 玩视频</title><summary type="text">由于平台的特点 用.net做视频网站的不多 作为兴趣研究下背景经常上土豆 youku的朋友可能会发现播放的视频格式大多是flv格式的 那么我们先来扫盲下flvFLV 是FLASH VIDEO的简称，FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快，使得网络观看视频文件成为可能，它的出现有效地解决了视频文件导入Flash后，使导出的SWF文件体积庞大，不能在网络上很好的使用等缺点。更多参考百科 http://baike.baidu.com/view/364757.htm但是用户手上的资源未必都是flv格式，所以需要格式转换。这里介绍2款工具FFm</summary><published>2012-02-22T07:16:00Z</published><updated>2012-02-22T07:16:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2012/02/22/2363206.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2012/02/22/2363206.html"/><content type="html">&lt;p&gt;由于平台的特点 用.net做视频网站的不多 作为兴趣研究下&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;经常上土豆 youku的朋友可能会发现播放的视频格式大多是flv格式的 那么我们先来扫盲下flv&lt;/p&gt;&lt;p&gt;FLV 是FLASH VIDEO的简称，FLV流媒体格式是随着Flash MX的推出发展而来的视频格式。由于它形成的文件极小、加载速度极快，使得网络观看视频文件成为可能，它的出现有效地解决了视频文件导入Flash后，使导出的SWF文件体积庞大，不能在网络上很好的使用等缺点。&lt;/p&gt;&lt;p&gt;更多参考百科 &lt;a href="http://baike.baidu.com/view/364757.htm"&gt;http://baike.baidu.com/view/364757.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;但是用户手上的资源未必都是flv格式，所以需要格式转换。这里介绍2款工具&lt;/p&gt;&lt;p&gt;FFmpeg是一个开源免费跨平台的视频和音频流方案，属于自由软件，采用LGPL或GPL许可证（依据你选择的组件）。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec，为了保证高可移植性和编解码质量，libavcodec里很多codec都是从头开发的。&lt;/p&gt;&lt;p&gt;更多参考百科 &lt;a href="http://baike.baidu.com/view/856526.htm"&gt;http://baike.baidu.com/view/856526.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;mencoder 是一款命令行方式的视频处理软件，mencoder支持几乎所有的格式的视频转换，可以将任意格式转换到任意格式，转换功能可以说是相当强大。目前市面上流行的格式转换器，都是基于mencoder开发的GUI，比如暴风转码，格式工厂等。可以说转换器能办到的，mencoder都能办到，但mencoder能办到的，转换器就不一定能办到了。&lt;/p&gt;&lt;p&gt;更多参考百科 &lt;a href="http://baike.baidu.com/view/3353694.htm"&gt;http://baike.baidu.com/view/3353694.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;不过FFmpeg和在mencoder在应用领域还是有些区别&lt;/p&gt;&lt;p&gt;网摘：&lt;/p&gt;&lt;p&gt;1，在实际的使用当中，ffmpeg 在 Redhat与Suse Linux 下面都运行正常，但是我在Suse Linux 10 上面压缩rm与 rmvb 视频时，压出来的片子声音不正常。在其他参数都完全一样的情况下使用Redhat 压缩，居然是正常的。看来 Suse 对企业应用比较好，但是对多媒体的应用（偏向个人方面）还是 Redhat 比较好一些。&lt;br /&gt;2，ffmpeg 也可以压缩视频，不过，效果可是比mencoder 差好些。所以，基本上我只使用 ffmpeg 来抓取视频中的图片。可以使用 ffmpeg-php 这个开源项目程序来抓取任何一帧的图片，这样，我们就可以很方便地大致了解这个视频的内容了。&lt;br /&gt;3，ffmpeg 压缩一个 wmv 文件，可能使用不到一分钟，但是 mencoder 却压缩了好几分钟，由于 mencoder 需要计算更多东西，所以，需要花更多的时间。&lt;br /&gt;4，mencoder 支持的视频格式非常多，如常见的 wmv,avi,mpg,rm,rmvb,mov,3gp,mp4 等，大约有上百种，不过，我还无法一一测试，估计也是没有问题的。而ffmpeg 不支持 rm与rmvb 格式。&lt;br /&gt;5，做为视频压缩，对机器的要求是比较高的，对系统资源的占用比较大，主要是对CPU与磁盘IO要求高。前两天压缩一个视频，使用 宝德 PR2700D 用了4分钟，使用宝德 PR4800 用了12分钟，使用一台 Dell 2950 上面的 Vmware 虚拟机使用了大约8分钟。综合来看，最好是CPU强一些，内存不要小于2GB，磁盘的IO要快一些。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;实践&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;上述2款工具都有对应的win平台版本 那么我们只需要用.net启动软件进程就可以了 很简单 需要花功夫的是对工具各种复杂参数的把握&lt;/p&gt;&lt;p&gt;先上个简单的demo&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022214510097.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;我们选举一个很简单的视频 windows自带的示例视频 可以在目录C:\WINDOWS\clock.avi找到&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022214540462.jpg" alt="" /&gt;&lt;br /&gt;每秒换一个数字&lt;/p&gt;&lt;p&gt;ffmpeg 压缩一个 视频 文件，可能使用不到一分钟，但是 mencoder 却压缩了好几分钟，由于 mencoder 需要计算更多东西，所以，需要花更多的时间。ffmpeg 也可以压缩视频，不过，效果可是比mencoder 差好些。并且ffmpeg对","wmv", "rmvb", "rm" 的效果不是很好，所以考虑的性能以及功能，"asf", "avi", "mpg", "3gp", "mov" 类型和截图功能使用ffmepg，"wmv", "rmvb", "rm"类型使用mencoder实现&lt;/p&gt;&lt;p&gt;所以我们这里用ffmpeg来转换&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022214560539.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;到输出目录中确认下我们转换的视频是否可用&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022214574423.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;我们再试试截图功能&lt;/p&gt;&lt;p&gt;我们截取2秒后和4秒后的 按照视频进度 应该截取到3和5 这2个数字&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022215000090.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022215004544.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022215011647.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012022215015190.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;OK 貌似很顺利&lt;/p&gt;&lt;p&gt;下面给出具体的参数配置&lt;/p&gt;&lt;p&gt;ffmpeng&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;使用: ffmpeg [[infile options] -i infile]... {[outfile options] outfile}...&lt;br/&gt;-L                  查看许可证&lt;br/&gt;-h                  显示说明&lt;br/&gt;-version            显示版本&lt;br/&gt;-formats            显示可用的格式，编解码器，协议... &lt;br/&gt;-f fmt              输出格式&lt;br/&gt;-i filename         输入文件名称&lt;br/&gt;-y                  覆盖输出文件&lt;br/&gt;-t duration         设定录音时间&lt;br/&gt;-fs limit_size      设置限制文件大小&lt;br/&gt;-ss time_off        设置开始时间偏移&lt;br/&gt;-itsoffset time_off 设置输入时间偏移&lt;br/&gt;-title string       设置标题&lt;br/&gt;-timestamp time     设定时间戳记&lt;br/&gt;-author string      设置作者&lt;br/&gt;-copyright string   设置版权&lt;br/&gt;-comment string     设置评论&lt;br/&gt;-album string       设置相册&lt;br/&gt;-v verbose          控制总额日志&lt;br/&gt;-target type        指定的目标文件类型 ("vcd", "svcd", "dvd", "dv", "dv50", "pal-vcd", "ntsc-svcd", ...)&lt;br/&gt;-dframes number     设置数据帧的记录&lt;br/&gt;-scodec codec       强制字幕编码器 ('copy' to copy stream)&lt;br/&gt;-newsubtitle   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;添加一个新的字幕流，以目前的输出流&lt;br/&gt;-slang code         设置ISO 639语言代码(3 字母)目前字幕高级视频设置:&lt;br/&gt;-vframes number     设置视频帧记录&lt;br/&gt;-r rate             设置帧比率(Hz value, fraction or abbreviation)&lt;br/&gt;-s size             设置帧大小 (WxH or abbreviation)&lt;br/&gt;-aspect aspect      设置的长宽比 (4:3, 16:9 or 1.3333, 1.7777)&lt;br/&gt;-croptop size       设置顶端作频率的大小 (in pixels)&lt;br/&gt;-cropbottom size    设置底端作频率的大小  (in pixels)&lt;br/&gt;-cropleft size      设置左端作频率的大小 (in pixels)&lt;br/&gt;-cropright size     设置右端作频率的大小(in pixels)&lt;br/&gt;-padtop size        设置顶端频率的大小 (in pixels)&lt;br/&gt;-padbottom size     设置底部频率的大小（以像素）&lt;br/&gt;-padleft size       设置左频率的大小（以像素）&lt;br/&gt;-padright size      设置右频率的大小（以像素）&lt;br/&gt;-padcolor color     设置颜色的频率（十六进制000000通过ffffff ）&lt;br/&gt;-vn                 禁用视频&lt;br/&gt;-vcodec codec       强制视频编码器 ('copy' to copy stream)&lt;br/&gt;-sameq              使用相同视频质量作为源(implies VBR)&lt;br/&gt;-pass n             选择通过数量(1 or 2)&lt;br/&gt;-passlogfile file   选择两个通过日志文件名称&lt;br/&gt;-newvideo           添加一个新的视频流，以目前的输出高级视频流选项：&lt;br/&gt;-pix_fmt format     设置像素格式&lt;br/&gt;-intra              使用内部帧&lt;br/&gt;-vdt n              放弃起增点&lt;br/&gt;-qscale q           使用固定的视频量化规模(VBR)&lt;br/&gt;-qdiff q &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最大值之间的差异量化表(VBR)&lt;br/&gt;-rc_eq equation     设置速率控制方程&lt;br/&gt;-rc_override override 速率控制特定间隔覆盖&lt;br/&gt;-me method          设置运动估计方法&lt;br/&gt;-me_threshold       运动估计起增点&lt;br/&gt;-strict strictness  如何严格按照标准&lt;br/&gt;-deinterlace        反交错图片&lt;br/&gt;-psnr               计算的PSNR压缩帧&lt;br/&gt;-vstats             转储视频编码统计文件&lt;br/&gt;-vhook module       插入视频处理模块&lt;br/&gt;-intra_matrix matrix 指定内部矩阵系数&lt;br/&gt;-inter_matrix matrix 指定跨矩阵系数&lt;br/&gt;-top                top=1/bottom=0/auto=-1 场首要&lt;br/&gt;-dc precision       内直流精度&lt;br/&gt;-vtag fourcc/tag    强制视频四字符代码/标记&lt;br/&gt;-qphist             显示 QP 柱形统计图&lt;br/&gt;-vbsf bitstream filter 流过滤器的音频选项：&lt;br/&gt;-aframes number     设置音频帧记录&lt;br/&gt;-ab bitrate         设置音频比特率（在kb的速率/秒）&lt;br/&gt;-aq quality         设定质量的音频质量（编解码器的具体）&lt;br/&gt;-ar rate            设定音频采样率（赫兹）&lt;br/&gt;-ac channels        指定数目的音频通道&lt;br/&gt;-an                 禁用音频&lt;br/&gt;-acodec codec       强制音频编码 ('copy' to copy stream)&lt;br/&gt;-vol volume         改变声音大小 (256=normal)&lt;br/&gt;-newaudio           增加一个新的音频流到当前输出流&lt;br/&gt;-alang code         设置ISO 639语言代码(3 字母)目前字幕高级音频设置: &lt;br/&gt;-atag fourcc/tag    强制音频四字符代码/标记&lt;br/&gt;-absf bitstream filter 过滤比特流子标题选项&lt;br/&gt;-scodec codec       强制子标题编码('copy' to copy stream)&lt;br/&gt;-newsubtitle        增加一个新的子标题流到当前输出流&lt;br/&gt;-slang code         设置ISO 639语言代码(3 字母)目前字幕音频流/视频抓取设置:&lt;br/&gt;-vd device          设置音频抓取设备&lt;br/&gt;-vc channel         设置视频抓取频道(DV1394 only)&lt;br/&gt;-tvstd standard     设置电视标准 (NTSC, PAL (SECAM))&lt;br/&gt;-ad device          设置音频设备&lt;br/&gt;-grab format        设置抓取用的格式&lt;br/&gt;-gd device          设置高级抓取设备选项:&lt;br/&gt;-map file:stream[:syncfile:syncstream] 设置输入数据流&lt;br/&gt;-map_meta_data outfile:infile 设置中继数据信息从输入文件到输出文件&lt;br/&gt;-benchmark          添加基准时间&lt;br/&gt;-dump               转储每个输入数据包&lt;br/&gt;-hex                当转储数据包时，也转储载重量&lt;br/&gt;-re                 在本帧读入。比率&lt;br/&gt;-loop_input         回路（目前只有工程与图片）&lt;br/&gt;-loop_output        多少次循环的输出格式，支持循环（ 0循环永远）&lt;br/&gt;-threads count      线程计数&lt;br/&gt;-vsync              视频同步方法&lt;br/&gt;-async              音频同步方式&lt;br/&gt;-vglobal            全球视频头存储类型&lt;br/&gt;-copyts             复制时间戳&lt;br/&gt;-shortest     &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最快完成输入编码&lt;br/&gt;-dts_delta_threshold转换过程中数据包的大小, 即数据缓冲区的大小按照本意, 数据缓冲区越大转换速度越快, 但这与系统的运行状态有关&lt;br/&gt;-ps size            设置数据包大小&lt;br/&gt;-muxdelay seconds   设定最高解复用器-解码延迟&lt;br/&gt;-muxpreload seconds 设置初始解复用器-解码延迟 &lt;br/&gt;&amp;nbsp;&lt;br/&gt;&amp;nbsp;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;Mencoder 参考&lt;a href="http://www.ylmf.net/ubuntu/qa/2010122918996.html"&gt;http://www.ylmf.net/ubuntu/qa/2010122918996.html&lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;附demo 随笔之作 不工整比较丑陋就不直接贴项目了 未加密 有兴趣的同学直接反编译看吧&lt;/p&gt;&lt;p&gt;demo下载&amp;nbsp;&lt;a href="http://files.cnblogs.com/dubing/MaoyaVideo.rar"&gt;http://files.cnblogs.com/dubing/MaoyaVideo.rar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;ffmpeng和mencoder的工具在网上搜一下 然后按照程序里的目录存放就可以了&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2363206.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2012/02/22/2363206.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2012/01/16/2323985.html</id><title type="text">【C#|.NET】分布式锁服务</title><summary type="text">背景 分布式锁服务在大家的项目中或许用的不多，因为大家都把排他放在数据库那一层来挡。当大量的行锁、表锁、事务充斥着数据库的时候，不如换个角度思考问题。一般web应用很多的瓶颈都在数据库上，这里给大家介绍的是减轻数据库锁负担的一种方案。简介 如果我们的需求很简单，例如对于用户的账户资金，要保证原子性操作。并且不同的客户端在同一时间内只能提交一个对象操作。lock、单例？！在单台上还可以，但是大型web项目上，负载均衡是常用的技术手段手段，同一意义的对象可能存在不同的副本，这时我们又如何保证排他操作。数据库的事务！除了这个，接下来我们引出本章的主题、分布式锁服务。 一个简单的锁服务实现起...</summary><published>2012-01-16T09:58:00Z</published><updated>2012-01-16T09:58:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2012/01/16/2323985.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2012/01/16/2323985.html"/><content type="html">&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;分布式锁服务在大家的项目中或许用的不多，因为大家都把排他放在数据库那一层来挡。当大量的行锁、表锁、事务充斥着数据库的时候，不如换个角度思考问题。一般web应用很多的瓶颈都在数据库上，这里给大家介绍的是减轻数据库锁负担的一种方案。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;简介&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;如果我们的需求很简单，例如对于用户的账户资金，要保证原子性操作。并且不同的客户端在同一时间内只能提交一个对象操作。lock、单例？！在单台上还可以，但是大型web项目上，负载均衡是常用的技术手段手段，同一意义的对象可能存在不同的副本，这时我们又如何保证排他操作。数据库的事务！除了这个，接下来我们引出本章的主题、分布式锁服务。&lt;/p&gt;&lt;p&gt;一个简单的锁服务实现起来并不难，甚至利用memcache很快就能构造一套分布式锁系统。我们只需要在操作对象时写入kv键值对，操作完毕时释放kv，在读取对象时判断kv中是否有数据就可以了，我们甚至还可以给它一个默认的释放时间。&lt;/p&gt;&lt;p&gt;这是一种解决方案，但是如果我们的要求更高一点，我们需要权限认证（例如只能来自xxx域名的请求）、需要上下级节点关联（例如一个用户的资金账户被锁住，同时锁住他的购物车、积分等）、需要监视器回调、甚至需要考虑单点故障问题。那么，虫子在这里推荐另一套方案----zookeeper。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;zookeeper&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;官方文档：&lt;a href="http://zookeeper.apache.org/doc/r3.3.2/zookeeperOver.html#ch_DesignOverview" target="_blank"&gt;http://zookeeper.apache.org/doc/r3.3.2/zookeeperOver.html#ch_DesignOverview&lt;/a&gt;&lt;/p&gt;&lt;p&gt;下载：&lt;a href="http://zookeeper.apache.org/releases.html" target="_blank"&gt;http://zookeeper.apache.org/releases.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Zookeeper是Hadoop中的一个模块。是一个分布式的，开源的分布式应用程序协调服务，用它可以来现同步服务，配置维护。&lt;/p&gt;&lt;p&gt;更多的内容大家看文档吧或者直接网上搜一下，理论性的内容写多了让人困。我们直接看实践。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;性能篇&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;服务器ubuntu （虚拟机一台）&lt;/p&gt;&lt;p&gt;客户端window2003&lt;/p&gt;&lt;p&gt;服务端安装好java环境 然后跟着官方的介绍部署&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011616311521.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;启动zkserver&lt;/p&gt;&lt;p&gt;我们测试下锁服务相关的操作&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011616420695.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;ps：试下本机的windows2003&amp;nbsp; 因为是本地环境 不于上面做对比 仅看看zookeeper本身的数据处理效率&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011616483253.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011616500949.jpg" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;功能篇&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一&lt;/strong&gt;张图就可以介绍完普通功能&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011617011996.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;再看下watcher&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public class MyWatch : IWatcher&lt;br/&gt;    {&lt;br/&gt;        public void Process(WatchedEvent qevent)&lt;br/&gt;        {&lt;br/&gt;            Console.WriteLine("this is MyWatch");&lt;br/&gt;        }     &lt;br/&gt;    }&lt;br/&gt;public class MyWatch2 : IWatcher&lt;br/&gt;    {&lt;br/&gt;        public void Process(WatchedEvent qevent)&lt;br/&gt;        {&lt;br/&gt;            Console.WriteLine("this is MyWatch2");&lt;br/&gt;        }   &lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;创建连接时&amp;nbsp;new ZooKeeper("192.168.206.129:2181", new TimeSpan(0, 0, 0, 4000), new MyWatch());&lt;/p&gt;&lt;p&gt;检查是否存在时zk.Exists(Dir, new MyWatch2());&lt;/p&gt;&lt;p&gt;获取数据时zk.GetData(Dir, new MyWatch2(), stat);&lt;/p&gt;&lt;p&gt;我们再运行一遍之前的demo&amp;nbsp; 去掉delete操作&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011617313491.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;加上delete操作&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012011617324037.jpg" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;浅析&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;　&lt;span style="color: #ff0000;"&gt;　创建连接：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;1.获取服务主机列表&lt;/p&gt;&lt;p&gt;2.设置超时时间&lt;/p&gt;&lt;p&gt;3.注册客户端事件&lt;/p&gt;&lt;p&gt;4.以线程安全的方式创建请求连接（启动客户端请求队列，循环队列基于socket通信、根据请求类型执行不同的请求动作）&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;请求流程：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;构造请求头、构造request,reponse、构造响应头、构造Packet对象,packet对象准备好后，把整个对象放入一个outgoingQueue &lt;br /&gt;packet被放入outgoingQueue中，等待SendThread把packet对应的内容发送给server。server处理分3步在doio方法中ReadLength ReadConnectResult ReadResponse，直到ReadResponse方法中确定packet请求结束。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;响应流程：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;针对心跳的ping请求的resp，针对auth请求的resp，一般接口请求的resp，如果接口请求要求了watcher，当watcher关注的内容有变化时的notification&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;锁相关部分API方法：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;创建节点：&lt;span style="color: #000000;"&gt;create&lt;/span&gt;&lt;/p&gt;&lt;p&gt;demo：zk.Create(Dir, severname.GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);&lt;/p&gt;&lt;p&gt;其中CreateMode分为4类Persistent、PersistentSequential、Ephemeral、EphemeralSequential&lt;/p&gt;&lt;p&gt;PERSISTENT 创建持久化节点，对应机器关闭连接后节点/数据不会消失&lt;/p&gt;&lt;p&gt;PERSISTENT_SEQUENTIAL 如果PATH是以&amp;rsquo;/&amp;rsquo;结尾则以这个PATH作为父节点，创建一个子节点，其子节点名字是一个按先后顺序排列的数值；否则创建一个名字是&amp;lsquo;/&amp;rsquo;后面字符加上先后顺序排列的数值字符串的节点，同样创建持久节点&lt;/p&gt;&lt;p&gt;EPHEMERAL 创建瞬时节点，Zookeeper在感知连接机器宕机后会清除它创建的瞬时节点&lt;/p&gt;&lt;p&gt;EPHEMERAL_SEQUENTIAL 穿件瞬时顺序节点，和PERSISTENT_SEQUENTIAL一样，区别在于它是瞬时的&lt;/p&gt;&lt;p&gt;删除节点 delete&lt;/p&gt;&lt;p&gt;demo ：zk.Delete(Dir, -1);&lt;/p&gt;&lt;p&gt;前一个参数代表节点名称（一般用作路径），后一个是版本号 -1表示全匹配&lt;/p&gt;&lt;p&gt;查看节点 exists&lt;/p&gt;&lt;p&gt;demo ： zk.Exists(Dir, new MyWatch2());&lt;/p&gt;&lt;p&gt;获取数据 getData&amp;nbsp;&lt;/p&gt;&lt;p&gt;demo ：zk.GetData(Dir, new MyWatch2(), stat);&lt;/p&gt;&lt;p&gt;获取一个节点的数据，可注入watcher&amp;nbsp;&lt;/p&gt;&lt;p&gt;设置数据 setData&amp;nbsp;&lt;/p&gt;&lt;p&gt;demo ：&amp;nbsp;zk.SetData(Dir, new byte[1], 1);&lt;/p&gt;&lt;p&gt;获取下级节点集合 GetChildren&lt;/p&gt;&lt;p&gt;demo ：zk.GetChildren(Dir, true);&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;存储&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;znodes类似文件和目录。但它不是一个典型的文件系统，zookeeper数据保存在内存中，这意味着zookeeper可以实现高吞吐量和低延迟。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;span style="color: #ff0000;"&gt;watcher&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Zookeeper有两种watches，一种是data watches，另一种是child watches。其中，getData()和exists()以及create()等会添加data watches，getChildren()会添加child watches。而delete()涉及到删除数据和子节点，会同时触发data watches和child watches。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 详细可以参考：&lt;a href="http://www.geminikwok.com/2011/09/08/%E6%B5%85%E8%B0%88zookeeper-watch%E4%BA%8B%E4%BB%B6/" target="_blank"&gt;http://www.geminikwok.com/2011/09/08/%E6%B5%85%E8%B0%88zookeeper-watch%E4%BA%8B%E4%BB%B6/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;算法&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Paoxs算法 本篇中仅用单台server做demo 改个时间详细介绍下Paoxs&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;本篇先到此 希望对大家有帮助&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;　&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2323985.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2012/01/16/2323985.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2012/01/09/2316903.html</id><title type="text">【C#|.NET】利用FastDFS打造分布式文件系统</title><summary type="text">关于分布式文件系统 之前已经写过一些随笔 不过没怎么用心 本篇详细的整理一下背景 海量存储、系统负载的迁移、服务器吞吐的瓶颈等等 让文件系统独立于业务系统 提高整个项目的扩展性以及可维护性 目前主流的方案 MFS FASTDFS GFS LUSTRE HADOOP等等 我选择的是FASTDFS 用一句广告语来说 “免费、快速、找得到”。FASTDFS的作者是淘宝的资深架构师余庆，很诙谐、很有爱！！！其他方案还没玩过 暂不评论。简介 FastDFS是一款开源的轻量级分布式文件系统纯C实现，支持Linux、FreeBSD等UNIX系统类google FS，不是通用的文件系统，只能通过专有...</summary><published>2012-01-09T03:17:00Z</published><updated>2012-01-09T03:17:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2012/01/09/2316903.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2012/01/09/2316903.html"/><content type="html">&lt;p&gt;关于分布式文件系统 之前已经写过一些随笔 不过没怎么用心 本篇详细的整理一下&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;海量存储、系统负载的迁移、服务器吞吐的瓶颈等等 让文件系统独立于业务系统 提高整个项目的扩展性以及可维护性&lt;/p&gt;&lt;p&gt;目前主流的方案 MFS FASTDFS GFS LUSTRE HADOOP等等&lt;/p&gt;&lt;p&gt;我选择的是FASTDFS 用一句广告语来说 &amp;ldquo;免费、快速、找得到&amp;rdquo;。FASTDFS的作者是淘宝的资深架构师余庆，很诙谐、很有爱！！！其他方案还没玩过 暂不评论。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;简介&lt;/strong&gt;&lt;strong&gt;　&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;FastDFS是一款开源的轻量级分布式文件系统纯C实现，支持Linux、FreeBSD等UNIX系统类google FS，不是通用的文件系统，只能通过专有API访问，目前官方提供了C、Java和PHP API为互联网应用量身定做，追求高性能和高扩展性,FastDFS可以看做是基于文件的key value pair存储系统，称作分布式文件存储服务更为合适。&lt;/p&gt;&lt;p&gt;特点：&lt;/p&gt;&lt;p&gt;分组存储，灵活简洁&lt;br /&gt;对等结构，不存在单点&lt;br /&gt;文件ID由FastDFS生成，作为文件访问凭证。FastDFS不需要传统的name server&lt;br /&gt;和流行的web server无缝衔接，FastDFS已提供apache和nginx扩展模块&lt;br /&gt;大中小文件均可以很好支持，支持海量小文件存储&lt;br /&gt;存储服务器上可以保存文件附加属性&lt;/p&gt;&lt;p&gt;名词解释：&lt;/p&gt;&lt;p&gt;Tracker Server：跟踪服务器，主要做调度工作，在访问上起负载均衡的作用。在内存中记录集群中group和storage server的状态信息，是连接Client和Storage server的枢纽。 因为相关信息全部在内存中，Tracker server的性能非常高，一个较大的集群（比如上百个group）中有3台就足够了。&lt;br /&gt;&amp;nbsp;Storage Server：存储服务器，文件和文件属性（meta data）都保存到存储服务器上。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;实践-服务端&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;系统：ubuntu&lt;/p&gt;&lt;p&gt;开发工具：vim&lt;/p&gt;&lt;p&gt;web服务：nginx&lt;/p&gt;&lt;p&gt;基于socket自定义通信协议&lt;/p&gt;&lt;p&gt;服务端的安装参考官方文档 有不懂的可以联系虫子 这里说下问题比较多的2个地方 一个是libevent的版本问题 另一个是ubuntu最新版本中对于libpthread等库文件的存放位置问题&lt;/p&gt;&lt;p&gt;安装完fastdfs以后 假设你的服务端程序安装在/usr/local目录&amp;nbsp;&lt;/p&gt;&lt;p&gt;我们会在bin目录下找到以下文件&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010910322438.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;storage服务器启动命令&amp;nbsp;/usr/local/bin/fdfs_storaged /FastDFS/conf/storage.conf&lt;/p&gt;&lt;p&gt;tracker服务器启动命令&amp;nbsp;/usr/local/bin/fdfs_trackerd /FastDFS/conf/tracker.conf&lt;/p&gt;&lt;p&gt;我们运行monitor查看下配置信息&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;group count: 1&lt;br/&gt;&lt;br/&gt;Group 1:&lt;br/&gt;group name = test&lt;br/&gt;free space = 5 GB&lt;br/&gt;storage server count = 2&lt;br/&gt;active server count = 2&lt;br/&gt;storage_port = 23000&lt;br/&gt;storage_http_port = 0&lt;br/&gt;store path count = 1&lt;br/&gt;subdir count per path= 3&lt;br/&gt;current write server index = 0&lt;br/&gt;&lt;br/&gt;Host 1:&lt;br/&gt;ip_addr = 192.168.234.139 (ubuntu)  ACTIVE&lt;br/&gt;total storage = 9GB&lt;br/&gt;free storage = 5GB&lt;br/&gt;total_upload_count = 2&lt;br/&gt;success_upload_count = 2&lt;br/&gt;total_set_meta_count = 0&lt;br/&gt;success_set_meta_count = 0&lt;br/&gt;total_delete_count = 0&lt;br/&gt;success_delete_count = 0&lt;br/&gt;total_download_count = 0&lt;br/&gt;success_download_count = 0&lt;br/&gt;total_get_meta_count = 0&lt;br/&gt;success_get_meta_count = 0&lt;br/&gt;total_create_link_count = 0&lt;br/&gt;success_create_link_count = 0&lt;br/&gt;total_delete_link_count = 0&lt;br/&gt;success_delete_link_count = 0&lt;br/&gt;last_heart_beat_time = 2012-01-05 18:45:50&lt;br/&gt;last_source_update = 2012-01-05 01:20:28&lt;br/&gt;last_sync_update = 1969-12-31 16:00:00&lt;br/&gt;last_synced_timestamp= 1969-12-31 16:00:00&lt;br/&gt;Host 2:&lt;br/&gt;ip_addr = 192.168.234.140  ACTIVE&lt;br/&gt;total storage = 18GB&lt;br/&gt;free storage = 12GB&lt;br/&gt;total_upload_count = 16&lt;br/&gt;success_upload_count = 16&lt;br/&gt;total_set_meta_count = 0&lt;br/&gt;success_set_meta_count = 0&lt;br/&gt;total_delete_count = 0&lt;br/&gt;success_delete_count = 0&lt;br/&gt;total_download_count = 0&lt;br/&gt;success_download_count = 0&lt;br/&gt;total_get_meta_count = 0&lt;br/&gt;success_get_meta_count = 0&lt;br/&gt;total_create_link_count = 0&lt;br/&gt;success_create_link_count = 0&lt;br/&gt;total_delete_link_count = 0&lt;br/&gt;success_delete_link_count = 0&lt;br/&gt;last_heart_beat_time = 2012-01-05 18:45:50&lt;br/&gt;last_source_update = 2012-01-05 01:54:02&lt;br/&gt;last_sync_update = 1969-12-31 16:00:00&lt;br/&gt;last_synced_timestamp= 1969-12-31 16:00:00&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;storage.conf整理汉化版&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;disabled=false&lt;br/&gt;#配置是否生效&lt;br/&gt;group_name=g1&lt;br/&gt;#storage所在组(卷)&lt;br/&gt;bind_addr=&lt;br/&gt;# 绑定IP，另一太 storage IP为 192.168.6.101&lt;br/&gt;client_bind=true&lt;br/&gt;#bind_addr通常是针对server的。当指定bind_addr时，本参数才有效。&lt;br/&gt;port=13334&lt;br/&gt;# 是storage 服务端口&lt;br/&gt;connect_timeout=30&lt;br/&gt;# 连接超时时间，针对socket套接字函数connect&lt;br/&gt;network_timeout=60&lt;br/&gt;# storage server 网络超时时间，单位为秒。&lt;br/&gt;heart_beat_interval=30&lt;br/&gt;# 心跳间隔时间，单位为秒&lt;br/&gt;stat_report_interval=60&lt;br/&gt;# storage server向tracker server报告磁盘剩余空间的时间间隔，单位为秒。&lt;br/&gt;base_path=/opt/fastdfs/storage&lt;br/&gt;# base_path 目录地址,根目录必须存在  子目录会自动生成&lt;br/&gt;# 会产生data（数据存储地方）、 logs日志文件&lt;br/&gt;max_connections=256&lt;br/&gt;# 最大连接数&lt;br/&gt;buff_size = 256KB&lt;br/&gt;# 设置队列结点的buffer大小。&lt;br/&gt;work_threads=1&lt;br/&gt;# 工作线程数&lt;br/&gt;disk_rw_separated = true&lt;br/&gt;# 磁盘IO读写是否分离，缺省是分离的。&lt;br/&gt;disk_reader_threads = 1&lt;br/&gt;# 针对单个存储路径的读线程数，缺省值为1&lt;br/&gt;disk_writer_threads = 1&lt;br/&gt;# 针对单个存储路径的写线程数，缺省值为1&lt;br/&gt;sync_wait_msec=200&lt;br/&gt;# 同步文件时，如果从binlog中没有读到要同步的文件，休眠N毫秒后重新读取，0表示不休眠，立即再次尝试读取。&lt;br/&gt;sync_interval=0&lt;br/&gt;#  同步上一个文件后，再同步下一个文件的时间间隔，单位为毫秒，0表示不休眠，直接同步下一个文件。&lt;br/&gt;sync_start_time=00:00&lt;br/&gt;sync_end_time=23:59&lt;br/&gt;# 允许系统同步的时间段 (默认是全天) 。一般用于避免高峰同步产生一些问题而设定，相信sa都会明白。&lt;br/&gt;write_mark_file_freq=500&lt;br/&gt;# 把storage的mark文件定期同步到磁盘的时间间隔，单位为秒&lt;br/&gt;store_path_count=1&lt;br/&gt;# 存放文件时storage server支持多个路径（例如磁盘）。这里配置存放文件的基路径数目，通常只配一个目录。&lt;br/&gt;store_path0=/opt/fastdfs&lt;br/&gt;&lt;br/&gt;# 逐一配置store_path个路径，索引号基于0。注意配置方法后面有0,1,2 ......，需要配置0到store_path - 1。&lt;br/&gt;# 如果不配置base_path0，那边它就和base_path对应的路径一样。&lt;br/&gt;subdir_count_per_path=32&lt;br/&gt;# FastDFS存储文件时，采用了两级目录。这里配置存放文件的目录个数&lt;br/&gt;tracker_server=192.168.234.139:13333&lt;br/&gt;# tracker_server 的列表 要写端口的哦&lt;br/&gt;log_level=info&lt;br/&gt;# 日志级别&lt;br/&gt;run_by_group=root&lt;br/&gt;# 运行storage 用户组&lt;br/&gt;run_by_user=root&lt;br/&gt;# 运行storage 用户&lt;br/&gt;allow_hosts=*&lt;br/&gt;# 允许连接IP列表&lt;br/&gt;file_distribute_path_mode=0&lt;br/&gt;# 文件在data目录下分散存储策略。&lt;br/&gt;# 0: 轮流存放&lt;br/&gt;# 1: 随机存储&lt;br/&gt;file_distribute_rotate_count=100&lt;br/&gt;# 当上面的参数file_distribute_path_mode配置为0（轮流存放方式）时，本参数有效。&lt;br/&gt;#当一个目录下的文件存放的文件数达到本参数值时，后续上传的文件存储到下一个目录中&lt;br/&gt;fsync_after_written_bytes=0&lt;br/&gt;# 当写入大文件时，每写入N个字节，调用一次系统函数fsync将内容强行同步到硬盘。0表示从不调用fsync&lt;br/&gt;sync_log_buff_interval=10&lt;br/&gt;# 同步或刷新日志信息到硬盘的时间间隔，单位为秒&lt;br/&gt;sync_binlog_buff_interval=60&lt;br/&gt;# 同步binglog（更新操作日志）到硬盘的时间间隔，单位为秒&lt;br/&gt;sync_stat_file_interval=300&lt;br/&gt;#　把storage的stat文件同步到磁盘的时间间隔，单位为秒。&lt;br/&gt;thread_stack_size=512KB&lt;br/&gt;#线程栈的大小。FastDFS server端采用了线程方式。&lt;br/&gt;#线程栈越大，一个线程占用的系统资源就越多。&lt;br/&gt;upload_priority=10&lt;br/&gt;#本storage server作为源服务器，上传文件的优先级，可以为负数。值越小，优先级越高。这里就和 tracker.conf 中store_server= 2时的配置相对应了&lt;br/&gt;if_alias_prefix=&lt;br/&gt;check_file_duplicate=0&lt;br/&gt;#是否检测上传文件已经存在。如果已经存在，则不存在文件内容，建立一个符号链接以节省磁盘空间。　结合　fastdfh使用的。 1是检测，0是不检测，我们不使用fastdfh 当然 0　&lt;br/&gt;key_namespace=FastDFS&lt;br/&gt;# 当上个参数设定为1 或 yes时 (true/on也是可以的) ， 在FastDHT中的命名空间&lt;br/&gt;keep_alive=0&lt;br/&gt;# 与FastDHT servers 的连接方式 (是否为持久连接) &lt;br/&gt;&lt;br/&gt;# 下面是http的配置了就不多说了&lt;br/&gt;http.disabled=true&lt;br/&gt;http.domain_name=&lt;br/&gt;http.server_port=80&lt;br/&gt;http.trunk_size=256KB&lt;br/&gt;http.need_find_content_type=true&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;tracker.conf整理汉化版&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;disabled=false&lt;br/&gt;#配置是否生效&lt;br/&gt;bind_addr=&lt;br/&gt;#绑定IP&lt;br/&gt;port=13333&lt;br/&gt;#服务端口&lt;br/&gt;connect_timeout=30&lt;br/&gt;#连接超时时间&lt;br/&gt;network_timeout=60&lt;br/&gt;#  tracker server的网络超时，单位为秒。&lt;br/&gt;base_path=/opt/fastdfs/tracker&lt;br/&gt;#目录地址，里面会创建data(存放存储服务器信息)、logs，日志文件&lt;br/&gt;max_connections=256&lt;br/&gt;#系统提供服务最大连接数&lt;br/&gt;work_threads=4&lt;br/&gt;#线程数，通常设置CPU数&lt;br/&gt;store_lookup=2&lt;br/&gt;#上传组(卷) 的方式 0:轮询方式 1: 指定组 2: 平衡负载(选择最大剩余空间的组(卷)上传)这里如果在应用层指定了上传到一个固定组,那么这个参数被绕过&lt;br/&gt;store_group=g1&lt;br/&gt;#当上一个参数设定为1 时 (store_lookup=1，即指定组名时)，必须设置本参数为系统中存在的一个组名。如果选择其他的上传方式，这个参数就没有效了&lt;br/&gt;store_server=0&lt;br/&gt;#选择哪个storage server 进行上传操作(一个文件被上传后，这个storage server就相当于这个文件的storage server源，会对同组的storage server推送这个文件达到同步效果)&lt;br/&gt;# 0: 轮询方式&lt;br/&gt;# 1: 根据ip 地址进行排序选择第一个服务器（IP地址最小者）&lt;br/&gt;# 2: 根据优先级进行排序（上传优先级由storage server来设置，参数名为upload_priority）&lt;br/&gt;store_path=0&lt;br/&gt;#选择storage server 中的哪个目录进行上传。storage server可以有多个存放文件的base path（可以理解为多个磁盘）。&lt;br/&gt;# 0: 轮流方式，多个目录依次存放文件&lt;br/&gt;# 2: 选择剩余空间最大的目录存放文件（注意：剩余磁盘空间是动态的，因此存储到的目录或磁盘可能也是变化的）&lt;br/&gt;download_server=0&lt;br/&gt;#选择哪个 storage server 作为下载服务器&lt;br/&gt;# 0: 轮询方式，可以下载当前文件的任一storage server&lt;br/&gt;# 1: 哪个为源storage server 就用哪一个 (前面说过了这个storage server源 是怎样产生的) 就是之前上传到哪个storage server服务器就是哪个了&lt;br/&gt;reserved_storage_space = 0.1GB&lt;br/&gt;#storage server 上保留的空间,保证系统或其他应用需求空间(指出 如果同组的服务器的硬盘大小一样,以最小的为准,也就是只要同组中有一台服务器达到这个标准了,这个标准就生效,原因就是因为他们进行备份)&lt;br/&gt;log_level=info&lt;br/&gt;#选择日志级别&lt;br/&gt;run_by_group=&lt;br/&gt;#操作系统运行FastDFS的用户组&lt;br/&gt;run_by_user=&lt;br/&gt;#操作系统运行FastDFS的用户&lt;br/&gt;allow_hosts=*&lt;br/&gt;#可以连接到此 tracker server 的ip范围（对所有类型的连接都有影响，包括客户端，storage server）&lt;br/&gt;sync_log_buff_interval = 10&lt;br/&gt;# 同步或刷新日志信息到硬盘的时间间隔，单位为秒&lt;br/&gt;# 注意：tracker server 的日志不是时时写硬盘的，而是先写内存。&lt;br/&gt;check_active_interval = 120&lt;br/&gt;# 检测 storage server 存活的时间隔，单位为秒。&lt;br/&gt;# storage server定期向tracker server 发心跳，如果tracker server在一个check_active_interval内还没有收到storage server的一次心跳，那边将认为该storage server已经下线。所以本参数值必须大于storage server配置的心跳时间间隔。通常配置为storage server心跳时间间隔的2倍或3倍。&lt;br/&gt;thread_stack_size = 64KB&lt;br/&gt;# 线程栈的大小。FastDFS server端采用了线程方式。更正一下，tracker server线程栈不应小于64KB，不是512KB。&lt;br/&gt;# 线程栈越大，一个线程占用的系统资源就越多。如果要启动更多的线程（V1.x对应的参数为max_connections，V2.0为work_threads），可以适当降低本参数值。&lt;br/&gt;storage_ip_changed_auto_adjust = true&lt;br/&gt;# 这个参数控制当storage server IP地址改变时，集群是否自动调整。注：只有在storage server进程重启时才完成自动调整。&lt;br/&gt;storage_sync_file_max_delay = 86400&lt;br/&gt;# V2.0引入的参数。存储服务器之间同步文件的最大延迟时间，缺省为1天。根据实际情况进行调整&lt;br/&gt;storage_sync_file_max_time = 300&lt;br/&gt;# V2.0引入的参数。存储服务器同步一个文件需要消耗的最大时间，缺省为300s，即5分钟。&lt;br/&gt;http.disabled=true&lt;br/&gt;# HTTP服务是否不生效 当然编译的时候我已经把 with_httpd宏去掉了，&lt;br/&gt;http.server_port=80&lt;br/&gt;# HTTP服务端口&lt;br/&gt;# 下列参数只有 开启http服务才有用&lt;br/&gt;http.check_alive_interval=30&lt;br/&gt;http.check_alive_type=tcp&lt;br/&gt;http.check_alive_uri=/status.html&lt;br/&gt;http.need_find_content_type=true&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;Web服务&lt;/p&gt;&lt;p&gt;FastDfs本身提供了组的概念，不同的组可以用不同的域名，如果是图片等类型资源，利用多个子域名在网站优化中是很有帮助的。不过如果你想在一个域名下实现多个服务器的分布式方案，可以利用nignx的反向代理来做urlrewrite。&lt;/p&gt;&lt;p&gt;举个简单的例子&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt; server {&lt;br/&gt;         listen       80;&lt;br/&gt;         server_name 192.168.234.140;&lt;br/&gt;index index.html index.htm index.php;&lt;br/&gt;root  /app/test;&lt;br/&gt;&lt;br/&gt;location /g1{&lt;br/&gt;         proxy_pass http://192.168.234.139;&lt;br/&gt;       }&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;分布式算法&lt;/p&gt;&lt;p&gt;和memcached这些分布式系统不同。Fastdfs的分布式算法是在服务端实现，Fish也在不断改良着算法。最新的是avl树。不过貌似有整rbtree的趋势。&lt;/p&gt;&lt;p&gt;&amp;nbsp;负载均衡，同步&lt;/p&gt;&lt;p&gt;fastdfs还内置了组内的同步功能，不过我觉得对于我的项目可用性不大，因为我要实现的是狭义的分布式文件系统只要能保证海量的可扩展存储方案就可以了，同步、负载均衡之类的就交给专业的运维们吧。&lt;/p&gt;&lt;p&gt;同步功能没有开关配置，在同步时间设置上作手脚就可以了。&lt;/p&gt;&lt;p&gt;sync_start_time，sync_end_time&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;实践-客户端　&lt;/strong&gt;　&lt;/p&gt;&lt;p&gt;系统：windowsXP&lt;/p&gt;&lt;p&gt;开发工具：VS2008&lt;/p&gt;&lt;p&gt;&amp;nbsp;首先我们来看下基本功能&lt;/p&gt;&lt;p&gt;找张mm图片&amp;nbsp; -_____-&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010910575464.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;上传成功 对比一下&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010911040567.jpg" alt="" width="854" height="414" /&gt;&lt;/p&gt;&lt;p&gt;然后再看看分布式结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010911064326.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;192.168.234.139上&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010911134238.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;192.168.234.140上&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010911153930.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;web上浏览&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/87114/2012010911192055.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;性能方面 和服务器本身的带宽 吞吐都有关系 不过作为文件系统 对稳定性的要求更大 而fastdfs的很多实例都证明了这一点&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;看完上面 是不是觉得很容易入手 当然 fastdfs的深度应用还有很多&amp;nbsp;&lt;/p&gt;&lt;p&gt;对于.net下 fastdfs的应用 大家有什么疑问可以联系我&lt;/p&gt;&lt;p&gt;本篇先到此 希望对大家有帮助&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2316903.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2012/01/09/2316903.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2011/12/30/2307832.html</id><title type="text">【C#|.NET】跳出一致性Hash算法 打造更高效的分布式缓存</title><summary type="text">前文 所谓“高效”，觑头而已。背景 谈到分布式缓存，大家首先想到的是memcached。确实memcached是目前最流行的方案之一。不过很多互联网公司不用memcached，例如新蛋。为什么不选择memcached呢，命中率？热插拔？还是性能。这里先不放结论，用事实来说话。算法篇 -1.除余法 如果你手上有老版本的memcache官方文档。你会发现他们用的是除余法来保持节点的一致性。假如你有N台缓存服务器，你需要将某个对象set进某一台节点上。用hash取模这样可以很均匀的保证每台的负载。那么，作为最基本的轮询算法，是否适合分布式缓存我们来看实例。这里假设有4台缓存节点，先设置除余...</summary><published>2011-12-30T10:11:00Z</published><updated>2011-12-30T10:11:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2011/12/30/2307832.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2011/12/30/2307832.html"/><content type="html">&lt;p&gt;&lt;strong&gt;前文&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;所谓&amp;ldquo;高效&amp;rdquo;，觑头而已。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;&amp;nbsp;背景&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;谈到分布式缓存，大家首先想到的是memcached。确实memcached是目前最流行的方案之一。不过很多互联网公司不用memcached，例如新蛋。为什么不选择memcached呢，命中率？热插拔？还是性能。这里先不放结论，用事实来说话。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;算法篇 -1.除余法&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;如果你手上有老版本的memcache官方文档。你会发现他们用的是除余法来保持节点的一致性。假如你有N台缓存服务器，你需要将某个对象set进某一台节点上。用hash取模这样可以很均匀的保证每台的负载。那么，作为最基本的轮询算法，是否适合分布式缓存我们来看实例。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017402996.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这里假设有4台缓存节点，先设置除余方案。&lt;/p&gt;&lt;p&gt;自动设置999条键值。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123016414334.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;下面来看下除余方案的各种综合结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123016510985.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;总的来说如果是相对稳定的环境 这种方案还是相当不错，至于性能我会单独开篇幅来说。&lt;/p&gt;&lt;p&gt;但是如果添加一台新节点 192.168.0.5&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123016522917.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;再来重新获取键值&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123016545081.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;再随机追加200条键值&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017413481.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;注意看数据中的命中率数据 新节点会投入环境 参与新的取模运算 但是之前因为模运算变化的键值就丢失了&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;算法篇 -2 普通hash算法&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;既然取模运算没办法保证我们的键值一致性，那么就要考虑新的方案了。不过设计我们自己的方案之前，我们可以继续看看memcache的使用者们进行了哪些改进。&lt;/p&gt;&lt;p&gt;通常的 hash 算法都是将 value 映射到一个 32 位的 key 值，也即是 0~2的32-1 次方的数值空间；&lt;/p&gt;&lt;p&gt;我不喜欢画图，大家就想象一下吧，一个首尾相接的圆。用hash算法将节点分布在圆的不同部位，同样对key值进行hash算法，通过&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;public static int BinarySearch&amp;lt;T&amp;gt;(T[] array, T value)方法，匹配到对应位置。&lt;/p&gt;&lt;p&gt;还是找了几张图过来.... 嘴拙 讲不清楚 直接看图吧&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017220786.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在这个环形空间中，如果沿着顺时针方向从对象的 key 值出发，直到遇见一个 cache ，那么就将该对象存储在这个 cache 上，因为对象和 cache 的 hash 值是固定的，因此这个 cache 必然是唯一和确定的。左下表示移除节点的情况，右下表示添加节点的情况&lt;/p&gt;&lt;p&gt;继续看图看结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123018270230.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;在稳定状态下 发现负载不是很平衡 不过还能接受 继续看看添加节点的情况&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017281448.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;命中率变70多了 能hold住了 低要求的话 应该还是不错的，再看看新节点的利用情况，随机再生成200条&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017300577.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;马马虎虎吧 负载偏差比较大 命中率一般&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;算法篇 -3 一致性hash算法 _ 虚拟节点&amp;nbsp;(consistent hashing)&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;相对普通hash算法 多了一个虚拟节点的概念 这也是目前memcache最主流的算法。&lt;/p&gt;&lt;p&gt;长话短说 就是我把一个节点虚拟成N多个虚节点 这些虚节点指向同一个物理节点 但是key值hash参照虚节点来设置&lt;/p&gt;&lt;p&gt;直接上图&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017423338.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;稳定状态下不错 同样我们在新添一个节点&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017434923.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;命中率提高了不上 不过负载还不是很平衡 随机再加300条&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017452365.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;对比普通hash算法好多了&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;算法篇 -4 一致性hash算法改进&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;针对一致性hash算法的虚拟节点 说白了就是一个50大小的坑被拆成 5个10大小的坑而已，不过缝隙小了 对于比较聚集的数据来说还是很有好处的&lt;/p&gt;&lt;p&gt;如何改进 将50大小的坑就变成10大小 对于新增的节点 我们不进虚拟节点化或者个性配置节点化&lt;/p&gt;&lt;p&gt;前面效率和一致性hash比较类似 我们直接看添加节点的情况&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017521384.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;98% 有木有 有木有！！！ 负载也还不错 你是不是已经被hold住了。&lt;/p&gt;&lt;p&gt;不过作为不良改进者 虫子还是要告诉大家这个改进一个很大的弊端 就是新节点的利用率&lt;/p&gt;&lt;p&gt;我们再随机新建600条键值&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123017541521.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;对于命中率的提高 是以新节点利用率为代价 至于之间怎么平衡 就看各自把握了&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;算法篇 -5 完美改进&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;上一种改进还是基于memcache现有的基础之上，跳出这个圈子为何要用一致性hash。&lt;/p&gt;&lt;p&gt;大家可以猜想一下这个方案的实现办法。关于这个方案的设计会单独开个篇幅来讲。&lt;/p&gt;&lt;p&gt;言归正传直接上图看结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123018031927.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;添加一台新服务器&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123018041534.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;命中率还是100% hold住 还有更精彩的&amp;nbsp; 我们随机添加500条键值&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011123018085836.jpg" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;本篇先到此 希望对大家有帮助&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2307832.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2011/12/30/2307832.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2011/12/27/2303765.html</id><title type="text">【C#|.NET】长话短说 分布式通信方案综合测评</title><summary type="text">如果你应聘互联网企业的架构师 分布式解决方案属于必问环节 因为流行SOA 关于SOA就不废话了 网上资源很多 重视4个字“基于消息”本篇只测评大家项目中常用的几种Remoting（TCP,HTTP,IPC）WCF(basicHttpBinding,netTcpBinding)HessianMSMQWebService......环境介绍客户机 windows Xp服务器 windows2003（虚拟机）带宽2M测试环境和线上环境差距比较大 我们看相对性就可以了所有方案基于相同远程对象 public class DtoClass : MarshalByRefObject { ...</summary><published>2011-12-27T08:56:00Z</published><updated>2011-12-27T08:56:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2011/12/27/2303765.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2011/12/27/2303765.html"/><content type="html">&lt;p&gt;如果你应聘互联网企业的架构师 分布式解决方案属于必问环节 因为流行SOA 关于SOA就不废话了 网上资源很多 重视4个字&amp;ldquo;基于消息&amp;rdquo;&lt;/p&gt;&lt;p&gt;本篇只测评大家项目中常用的几种&lt;/p&gt;&lt;p&gt;Remoting（TCP,HTTP,IPC）&lt;/p&gt;&lt;p&gt;WCF(basicHttpBinding,netTcpBinding)&lt;/p&gt;&lt;p&gt;Hessian&lt;/p&gt;&lt;p&gt;MSMQ&lt;/p&gt;&lt;p&gt;WebService&lt;/p&gt;&lt;p&gt;......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;环境介绍&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;客户机 windows Xp&amp;nbsp;&amp;nbsp;&amp;nbsp;服务器 windows2003（虚拟机）&lt;/p&gt;&lt;p&gt;带宽2M&lt;/p&gt;&lt;p&gt;测试环境和线上环境差距比较大 我们看相对性就可以了&lt;/p&gt;&lt;p&gt;所有方案基于相同远程对象&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public class DtoClass : MarshalByRefObject&lt;br/&gt;    {&lt;br/&gt;        public static Message GetMessageInfo(string param1, int param2, bool param3)&lt;br/&gt;        {&lt;br/&gt;            var dto = new Message {Param1 = param1, Param2 = param2, Param3 = param3};&lt;br/&gt;            return dto;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [Serializable]&lt;br/&gt;    public class Message&lt;br/&gt;    {&lt;br/&gt;        public string Param1 { get; set; }&lt;br/&gt;        public int Param2 { get; set; }&lt;br/&gt;        public bool Param3 { get; set; }&lt;br/&gt;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public interface IMaoyaTest&lt;br/&gt;    {&lt;br/&gt;        Message GetDto(string param1, int param2, bool param3);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    [ServiceContract]&lt;br/&gt;    public interface IWcfMaoyaTest&lt;br/&gt;    {&lt;br/&gt;        [OperationContract]&lt;br/&gt;        Message GetDto(string param1, int param2, bool param3);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;不同的通信方案 客户端请求相同的对象&lt;/p&gt;&lt;p&gt;例如&amp;nbsp;&amp;nbsp;remoting&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;  public Message TcpSingleCall()&lt;br/&gt;        {&lt;br/&gt;            var proxy = (IMaoyaTest)Activator.GetObject(typeof(IMaoyaTest), "tcp://192.168.234.129:8001/MaoyaTestURL");&lt;br/&gt;            return proxy.GetDto("chongzi", 10, true);&lt;br/&gt;&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;hsssian&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;public Message HessianTest()&lt;br/&gt;        {&lt;br/&gt;            var factory = new CHessianProxyFactory("userName", "password");&lt;br/&gt;            const string url = "http://192.168.234.129/HessianService.hessian"; &lt;br/&gt;            var hessianinstance = (IMaoyaTest)factory.Create(typeof(IMaoyaTest), url);&lt;br/&gt;            return hessianinstance.GetDto("chongzi", 10, true);&lt;br/&gt;          &lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;不同的通信方案对远程对象进行不同的处理&lt;/p&gt;&lt;p&gt;例如 remoting&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt; public class RemotingTest : MarshalByRefObject,IMaoyaTest&lt;br/&gt;    {&lt;br/&gt;        public Message GetDto(string param1, int param2, bool param3)&lt;br/&gt;        {&lt;br/&gt;            return DtoClass.GetMessageInfo("remoting:"+param1,param2+1,param3);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;hsssian&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt; public class MaoyaService : CHessianHandler, IMaoyaTest&lt;br/&gt;    {&lt;br/&gt;        public Message GetDto(string param1, int param2, bool param3)&lt;br/&gt;        {&lt;br/&gt;            return DtoClass.GetMessageInfo("HessianService:" + param1, param2 + 3, param3);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;Remoting&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;NET Framework 远程处理。这种技术可用于与呼叫中心应用程序进行通信，因为二者都是建立在 .NET Framework 之上的。远程处理专门为紧密耦合的 .NET 到 .NET 通信而设计，因此它为本地网络中的应用程序提供了无缝而直接的开发体验。&lt;/p&gt;&lt;p&gt;Remoting支持3种通道TCP HTTP IPC&lt;/p&gt;&lt;p&gt;Remoting支持2种激活方式服务端激活与客户端激活，服务端激活分为singlecall，sington区别为是否有状态，sington给每个客户端分配同一个对象实例，sington有状态。客户端激活为在激活每个对象实例的时候，会给每个客户端激活的类型指派一个URI。其与singcall的主要区别在于客户端激活方式对于对象周期的管理以及有状态。&lt;/p&gt;&lt;p&gt;了解使用场景，我们更关心性能。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122715505654.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;TCP：Transmission Control Protocol 传输控制协议TCP是一种面向连接（连接导向）的、可靠的、基于字节流的运输层（Transport layer）通信协议&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122715531857.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;HTTP（HyperText Transport Protocol）是超文本传输协议的缩写,HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求，请求头包含请求的方法、URL、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应，响应的内容包括消息协议的版本，成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122715560144.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;IPCChannel是.NET Framework 2.0 里面新增的，它使用 Windows 进程间通信 (IPC) 系统在同一计算机上的应用程序域之间传输消息。在同一计算机上的应用程序域之间进行通信时，IPC 信道比 TCP 或 HTTP 信道要快得多。但是IPC只在本机应用之间通信。所以，在客户端和服务端在同一台机器时，我们可以通过注册IPCChannel来提高Remoting的性能。但如果客户端和服务端不在同一台机器时，我们不能注册IPCChannel。&lt;/p&gt;&lt;p&gt;remoting总结&lt;/p&gt;&lt;p&gt;优点（相对于其他分布式方案） tcp方式效率相对较高 ipc王道&amp;nbsp; 可以自定义宿主&lt;/p&gt;&lt;p&gt;缺点&amp;nbsp; 平台限制&lt;/p&gt;&lt;p&gt;应用场景（实例） 统一新闻系统中新建新闻的异步自动审核、逻辑报表 等&amp;nbsp; 使用remoting可以有效分担服务器硬件压力并且不需要对外服务开放 各个模块高效 紧密合作&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;WCF&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Windows Communication Foundation (WCF) 是 Microsoft 为构建面向服务的应用程序而提供的统一编程模型。借助这一模型，开发人员可以构建既能跨平台与现有投资集成又能与现有投资交互的安全、可靠的事务处理解决方案。&lt;/p&gt;&lt;p&gt;wcf是WebService,Remoting,...之上的一层抽象，让程序员们以一种统一的方式去编写基于WebService或Remoting。。。的程序，而且它们之间的切换很简单，只需要改一下配置。 也就是说，开始服务以WS向外提供，因为需求改变，改为Remoting向外提供，只需要修改配置。WCF封装了各种不同实现的具体细节。WCF服务元数据是WCF服务的核心部分服务地址（Address）、绑定（通信协议Binding）、契约（服务、操作、数据Contract）的原始描述信息。&lt;/p&gt;&lt;p&gt;我们这里只测试2中常用的case&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122716233843.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;BasicHttpBinding不支持可靠性，BasicHttpBinding面向旧的ASMX Web服务，是不具有可靠性的；&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122716242918.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;NetTcpBinding 支持可靠性，显然使用TCP传输数据。以及各种WS绑定，默认情况下并不支持可靠性，允许启用；&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;其他协议：&lt;/p&gt;&lt;p&gt;NetMsmqBinding不支持可靠性，MSMQ协议，使用消息队列，针对断开调用，不存在传输会话；&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;MsmqIntegrationBinding不支持可靠性；支持WCF与MSMQ协议通信，不存在传输会话；&lt;/p&gt;&lt;p&gt;NetPeerTcpBinding不支持可靠性。NetPeerTcpBinding则为广播场景设计。&lt;/p&gt;&lt;p&gt;WSDualHttpBinding支持可靠性的，建立两个http会话通道，保持回调通道，确保基于HTTP协议的客户端存在；&lt;/p&gt;&lt;p&gt;NetNamedPipeBinding绑定总是拥有一个确定的从客户端到服务的跳数，因而它的可靠性是绑定固有的；&lt;/p&gt;&lt;p&gt;WSFederationHttpBinding支持可靠性，支持联邦通信协议，支持在多个安全区域进行安全会话。&lt;/p&gt;&lt;p&gt;WCF 总结&lt;/p&gt;&lt;p&gt;优点&amp;nbsp;兼众家之长 易用性、灵活性、易调试性、易部署&lt;/p&gt;&lt;p&gt;缺点 和腾讯的口碑差不多 论tcp 比起remoting 你效率没人高 论http 比起webservice 你没人方便&lt;/p&gt;&lt;p&gt;应用场景（实例） 事件调度中心 作为soa最常用的工具 wcf市场还是蛮大的&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;Hessian&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这货java程序员用的比较多 c#程序员估计有点茫然，这是神马。传输二进制？和remoting比,自然比不上。关键是hessian是基于http协议，不过不是用的soap协议，咱们还是和webservice比吧。&lt;/p&gt;&lt;p&gt;Hessian是一个轻量级的remoting onhttp工具，使用简单的方法提供了RMI的功能. 相比WebService，Hessian更简单、快捷。采用的是二进制RPC协议，因为采用的是二进制协议，所以它很适合于发送二进制数据。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122716342982.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;难怪c#没人用了......&lt;/p&gt;&lt;p&gt;hessian的处理过程 由客户端、序列化到输出流、远程方法（服务端）、序列化到输出流、客户端读取流、输出。&lt;/p&gt;&lt;p&gt;优点&amp;nbsp; 开源 轻量级&amp;nbsp;可以自己扩展&amp;nbsp;&amp;nbsp;相对webservice可以自定义宿主 减轻iis压力&lt;/p&gt;&lt;p&gt;缺点 目前的版本 性能比较差&lt;/p&gt;&lt;p&gt;应用场景&amp;nbsp; 一些开源软件 框架&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;MSMQ&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Message Queue（微软消息队列)是在多个不同的应用之间实现相互通信的一种异步传输模式，相互通信的应用可以分布于同一台机器上，也可以分布于相连的网络空间中的任一位置。它的实现原理是：消息的发送者把自己想要发送的信息放入一个容器中（我们称之为Message），然后把它保存至一个系统公用空间的消息队列(Message Queue)中；本地或者是异地的消息接收程序再从该队列中取出发给它的消息进行处理。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122716473758.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122716483733.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;用于与基于 Windows 的合作伙伴应用程序进行通信，这些应用程序对数据传送、工作量分离以及应用程序生存期均要求有保证。消息队列提供持久稳定的消息传送，这通常是间歇式连接的应用程序的最佳解决方案。&lt;/p&gt;&lt;p&gt;优点: 稳定性 消息优先级 脱机能力 安全性&lt;/p&gt;&lt;p&gt;缺点：比remoting更大的局限性 如果是远程msmq 限于安全性 服务器需要在同一个域&lt;/p&gt;&lt;p&gt;应用场景：（实例） 邮件系统 站内信系统&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;WebService&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个你们都懂的 不说了 直接看测试结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122716523137.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;优点： 跨平台&lt;/p&gt;&lt;p&gt;缺点： 效率相对比较低&lt;/p&gt;&lt;p&gt;应用场景： 很多 大家最常用的方式了 例如商城赠品服务等等&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;其它&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Enterprise Service，wse等等不一一列举了 有空大家自己玩了&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;&lt;strong&gt;本篇到此 希望对大家有帮助&lt;br /&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2303765.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2011/12/27/2303765.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2011/12/21/2295895.html</id><title type="text">【C#|.NET】从控制反转(依赖注入)想到事件注入 (非AOP)</title><summary type="text">前文事件注入的想法是由依赖注入所联想到依赖注入不算什么吸引人的话题本篇就不详说了不过有闲暇时间的机会不妨按照自己的兴趣去摸索、研究一些东西，也是一种乐子。在抓虫系列里简单的描述一下依赖注入在项目中的应用场景抓虫(五) 浅谈依赖注入与控制反转关于依赖注入推荐T2噬菌体同学的一篇文章 依赖注入那些事儿关于事件注入已添加进我的设计模式 【系列索引】结合项目实例 回顾传统设计模式 打造属于自己的模式类系列 概要所谓事件注入是我一时兴起随便杜撰的词，其思想借鉴依赖注入。当然看到这个词很多同学会想到AOP，这里先不置可否。依赖注入（Dependency Injection），是这样一个过程：由于某客户类只</summary><published>2011-12-21T07:16:00Z</published><updated>2011-12-21T07:16:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2011/12/21/2295895.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2011/12/21/2295895.html"/><content type="html">&lt;p&gt;&lt;strong&gt;前文&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;事件注入的想法是由依赖注入所联想到&lt;/p&gt;&lt;p&gt;依赖注入不算什么吸引人的话题&amp;nbsp;本篇就不详说了&amp;nbsp;不过有闲暇时间的机会不妨按照自己的兴趣去摸索、研究一些东西，也是一种乐子。&lt;/p&gt;&lt;p&gt;在抓虫系列里简单的描述一下依赖注入在项目中的应用场景&lt;a href="http://www.cnblogs.com/dubing/archive/2011/10/23/2222137.html" target="_blank"&gt;抓虫(五) 浅谈依赖注入与控制反转&lt;/a&gt;&lt;/p&gt;&lt;p&gt;关于依赖注入推荐T2噬菌体同学的一篇文章 &lt;a href="http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html" target="_blank"&gt;依赖注入那些事儿&lt;/a&gt;&lt;/p&gt;&lt;p&gt;关于事件注入已添加进我的设计模式 &lt;a href="http://www.cnblogs.com/dubing/archive/2011/10/22/2221138.html" target="_blank"&gt;【系列索引】结合项目实例 回顾传统设计模式 打造属于自己的模式类系列 &lt;/a&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;概要&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;所谓事件注入是我一时兴起随便杜撰的词，其思想借鉴依赖注入。当然看到这个词很多同学会想到AOP，这里先不置可否。&lt;/p&gt;&lt;p&gt;依赖注入（Dependency Injection），是这样一个过程：由于某客户类只依赖于服务类的一个接口，而不依赖于具体服务类，所以客户类只定义一个注入点。在程序运行过程中，客户类不直接实例化具体服务类实例，而是客户类的运行上下文环境或专门组件负责实例化服务类，然后将其注入到客户类中，保证客户类的正常运行。&lt;/p&gt;&lt;p&gt;也就是说依赖注入在我们的项目场景中充当一个解耦的角色。在项目结构中它可以解耦出一个模块、一个服务。T2噬菌体同学在他的博文中描述了一个游戏打怪的例子来解释依赖注入的作用。那么我们同样用打怪的例子来阐述下事件注入的场景。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;&amp;nbsp;详解&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;关于原型的设计可以参考T2同学对游戏打怪的描述，我这里直接略过看效果图&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122114073526.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;下面我们撇开T2同学对依赖注入场景的设计。假设目前这个demo就是可行的。但是随着游戏版本的更新，招式越来越多，效果越来越绚，规则越来越多。T2同学用依赖注入解决的重点是将Role和武器之间的依赖，封装算法簇，让它们之间可以互相替换，让算法的变化独立于使用算法的客户类。&lt;/p&gt;&lt;p&gt;那么浮现问题点，如果我要更新的并不是武器等因素，而是对流程的更新。例如玩dota的同学都知道，一个英雄他的技能前后摇摆的时间也是很重要的因素，好吧，我们给游戏添加技能前摇的设置，砍完怪的我还得获得金币，嗯，再添加一下攻击后获得金币的内容。如何符合我们的OCP原则呢。于是，我们引入事件注入的概念。&lt;/p&gt;&lt;p&gt;首先我们来定义我们所需要的行为&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;       /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 攻击前事件&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public static event EventHandler&amp;lt;EventArgs&amp;gt; BeforeAttackEvent;&lt;br/&gt;&lt;br/&gt;        protected virtual void BeforeAttack(EventArgs e)&lt;br/&gt;        {&lt;br/&gt;            EventHandler&amp;lt;EventArgs&amp;gt; tmp = BeforeAttackEvent;&lt;br/&gt;            if (tmp != null)&lt;br/&gt;                tmp(this, e);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 攻击后事件&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public static event EventHandler&amp;lt;GameEventArgs&amp;gt; AttackedEvent;&lt;br/&gt;&lt;br/&gt;        protected virtual void OnAttacked(GameEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            EventHandler&amp;lt;GameEventArgs&amp;gt; tmp = AttackedEvent;&lt;br/&gt;            if (tmp != null)&lt;br/&gt;                tmp(this, e);&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;这里定义的仅仅是事件的句柄，如果在这里就实现我们事件的实体也就违背了我们ocp的原则以及事件注入的概念。&lt;/p&gt;&lt;p&gt;这里要提出说明的&lt;span id="xn1_c3e8346991ffbda57285eebe7c62fcbc" class="sentence SentenceHover"&gt;&lt;span&gt;&lt;span class="selflink"&gt;EventArgs&lt;/span&gt;&lt;/span&gt; 是包含事件数据的类的基类，如果说我们需要对注入的事件进行额外的信息处理，例如我需要获得金币，那么金币这个属性需要在事件数据中说明&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="sentence SentenceHover"&gt;例如上述的攻击后事件&lt;/span&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// 注入事件元素&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    public class GameEventArgs :EventArgs&lt;br/&gt;    {&lt;br/&gt;        public GameEventArgs()&lt;br/&gt;            : this(0)&lt;br/&gt;        {&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public int Coin &lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public GameEventArgs(int coin)&lt;br/&gt;        {&lt;br/&gt;            Coin = coin;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;事件的框架有了，我们便在现有程序中找寻合适的注入点。这里我选择的是攻击前后&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;         /// &amp;lt;summary&amp;gt;         &lt;br/&gt;        /// 攻击怪物         &lt;br/&gt;        /// &amp;lt;/summary&amp;gt;         &lt;br/&gt;        /// &amp;lt;param name="monster"&amp;gt;被攻击的怪物&amp;lt;/param&amp;gt;         &lt;br/&gt;        public void Attack(Monster monster)&lt;br/&gt;        {&lt;br/&gt;            BeforeAttack(EventArgs.Empty);&lt;br/&gt;&lt;br/&gt;            if (monster.HP &amp;lt;= 0)&lt;br/&gt;            {&lt;br/&gt;                Console.WriteLine("此怪物已死");&lt;br/&gt;                return;&lt;br/&gt;            }&lt;br/&gt;            if ("WoodSword" == WeaponTag)&lt;br/&gt;            {&lt;br/&gt;                monster.HP -= 20;&lt;br/&gt;                if (monster.HP &amp;lt;= 0)&lt;br/&gt;                {&lt;br/&gt;                    Console.WriteLine("攻击成功！怪物" + monster.Name + "已死亡");&lt;br/&gt;                }&lt;br/&gt;                else { Console.WriteLine("攻击成功！怪物" + monster.Name + "损失20HP"); }&lt;br/&gt;            }&lt;br/&gt;            else if ("IronSword" == WeaponTag)&lt;br/&gt;            {&lt;br/&gt;                monster.HP -= 50; if (monster.HP &amp;lt;= 0)&lt;br/&gt;                {&lt;br/&gt;                    Console.WriteLine("攻击成功！怪物" + monster.Name + "已死亡");&lt;br/&gt;                }&lt;br/&gt;                else&lt;br/&gt;                {&lt;br/&gt;                    Console.WriteLine("攻击成功！怪物" + monster.Name + "损失50HP");&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            else if ("MagicSword" == WeaponTag)&lt;br/&gt;            {&lt;br/&gt;                Int32 loss = (_random.NextDouble() &amp;lt; 0.5) ? 100 : 200;&lt;br/&gt;                monster.HP -= loss;&lt;br/&gt;                if (200 == loss)&lt;br/&gt;                {&lt;br/&gt;                    Console.WriteLine("出现暴击！！！");&lt;br/&gt;                }&lt;br/&gt;                if (monster.HP &amp;lt;= 0)&lt;br/&gt;                {&lt;br/&gt;                    Console.WriteLine("攻击成功！怪物" + monster.Name + "已死亡");&lt;br/&gt;                }&lt;br/&gt;                else&lt;br/&gt;                {&lt;br/&gt;                    Console.WriteLine("攻击成功！怪物" + monster.Name + "损失" + loss + "HP");&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            else&lt;br/&gt;            {&lt;br/&gt;                Console.WriteLine("角色手里没有武器，无法攻击！");&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            var e =new GameEventArgs();&lt;br/&gt;            OnAttacked(e);&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;这些设计完成之后，我们需要的就是设计来注入些什么事件。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;[Extension("游戏规则_攻击前", "1.0.0.0", "熬夜的虫子")]&lt;br/&gt;    public class GameRule&lt;br/&gt;    {&lt;br/&gt;        public GameRule()&lt;br/&gt;        {&lt;br/&gt;            Role.BeforeAttackEvent += BeforeAttack;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        void BeforeAttack(object sender, EventArgs e)&lt;br/&gt;        {&lt;br/&gt;           Console.WriteLine("技能前摇 扭动身体...");               &lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;[Extension("游戏规则_攻击后", "1.0.0.0", "熬夜的虫子")]&lt;br/&gt;    public class GameRule2&lt;br/&gt;    {&lt;br/&gt;        private readonly Random _random = new Random();&lt;br/&gt;&lt;br/&gt;        public GameRule2()&lt;br/&gt;        {&lt;br/&gt;            Role.AttackedEvent += Attacked;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        void Attacked(object sender, EventArgs e)&lt;br/&gt;        {&lt;br/&gt;            var currentrole = sender as Role;&lt;br/&gt;            int addcoin = _random.Next(1, 10);&lt;br/&gt;            if (currentrole != null)&lt;br/&gt;            {&lt;br/&gt;                currentrole.Coin += addcoin;&lt;br/&gt;                Console.WriteLine("本次攻击获得了..." + addcoin.ToString() + "个金币,当前金币为" + currentrole.Coin+"个");&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;事件定义完成后，我们接下来的步骤就是如何来注入到我们现有的框架中。&lt;/p&gt;&lt;p&gt;老道的同学可以发现在事件定义的过程中，我用了扩展属性。没错，这个属性就是实现注入环节的枢纽所在。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;/// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// 事件注入实现&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    [AttributeUsage(AttributeTargets.Class)]&lt;br/&gt;    public class ExtensionAttribute : Attribute&lt;br/&gt;    {&lt;br/&gt;&lt;br/&gt;        public ExtensionAttribute(string description, string version, string author)&lt;br/&gt;        {&lt;br/&gt;            _Description = description;&lt;br/&gt;            _Version = version;&lt;br/&gt;            _Author = author;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private readonly string _Description;&lt;br/&gt;&lt;br/&gt;        public string Description&lt;br/&gt;        {&lt;br/&gt;            get { return _Description; }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private readonly string _Version;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        public string Version&lt;br/&gt;        {&lt;br/&gt;            get { return _Version; }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private readonly string _Author;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;        public string Author&lt;br/&gt;        {&lt;br/&gt;            get { return _Author; }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;如果想更深入的同学可以在设计一个事件注入管理类，添加一些是否可用，过期时间，版本，描述等等信息来管理注入事件。例如当管理类信息入库，每次注入前check管理类的信息。这样可以可视化并更方便管理注入的事件。&lt;/p&gt;&lt;p&gt;我们回到注入实现这个话题上来，如何利用这个扩展属性，通过反射。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt; var di = new System.IO.DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);&lt;br/&gt;            foreach (var item in di.GetFiles("*.dll", System.IO.SearchOption.TopDirectoryOnly))&lt;br/&gt;            {&lt;br/&gt;                System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(item.FullName);&lt;br/&gt;                Type[] types = assembly.GetTypes();&lt;br/&gt;                foreach (Type type in types)&lt;br/&gt;                {&lt;br/&gt;                    object[] attributes = type.GetCustomAttributes(typeof(Extension.ExtensionAttribute), false);&lt;br/&gt;                    foreach (object attribute in attributes)&lt;br/&gt;                    {&lt;br/&gt;                        assembly.CreateInstance(type.FullName);&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;上面的程序更具我们定义的扩展属性找到相关的注入事件方法类型，并生成实例。到此，一个简单的注入流程就已经OK了。&lt;/p&gt;&lt;p&gt;我们来看一下效果。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122115010169.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;注入事件的组件与源程序分开，源程序不依赖注入事件组件，可以任意的定义多个同类注入事件，将组件放入程序指定的目录即可。&lt;/p&gt;&lt;p&gt;例如我们再新建一个注入事件组件&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;[Extension("游戏规则_攻击后", "1.0.0.0", "熬夜的虫子")]&lt;br/&gt;        public class GameRule&lt;br/&gt;        {&lt;br/&gt;            public GameRule()&lt;br/&gt;            {&lt;br/&gt;                Role.AttackedEvent += Attacked;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            void Attacked(object sender, EventArgs e)&lt;br/&gt;            {&lt;br/&gt;                Console.WriteLine("技能后摆 O(&amp;cap;_&amp;cap;)O哈哈哈~...");&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;配置完成后，看下效果&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122115111047.jpg" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;本篇到此 希望对大家有帮助&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2295895.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2011/12/21/2295895.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2011/12/20/2294799.html</id><title type="text">【linux+C】通过几个实例温习指针</title><summary type="text">前篇回顾 上篇介绍一些vim相关的内容 作为新手，起初玩vim还是蛮痛苦的。不过慢慢尝到甜头后也很难放下了。本篇带一样很久没玩c的同学温故下指针。step 1 直接上图了这里我们定义一个二维数组int a[2][5] = {1,3,5,7,9,2,4,6,8,10};左边文件我们声明一个普通指针 将二维数组的内容填充进来我们来看看运行的结果结论我就不总结了 和大家的想法一样右边文件我们声明一个指针数组来存放我们再看看右边文件的运行结果大学里 谭浩强的c入门熟读的同学应该也早就知道结果了温习一下而已，通过上面的2个例子我们可以理解到这些左边的例子实际上在内存区占用了一连串的地址，右边的例...</summary><published>2011-12-20T07:55:00Z</published><updated>2011-12-20T07:55:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2011/12/20/2294799.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2011/12/20/2294799.html"/><content type="html">&lt;p&gt;&lt;strong&gt;前篇回顾&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;上篇介绍一些vim相关的内容&lt;/p&gt;&lt;p&gt; 作为新手，起初玩vim还是蛮痛苦的。不过慢慢尝到甜头后也很难放下了。本篇带一样很久没玩c的同学温故下指针。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;step 1&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;直接上图了&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122015415839.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这里我们定义一个二维数组int a[2][5] = {1,3,5,7,9,2,4,6,8,10};&lt;/p&gt;&lt;p&gt;左边文件我们声明一个普通指针 将二维数组的内容填充进来&lt;/p&gt;&lt;p&gt;我们来看看运行的结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122015485732.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;结论我就不总结了 和大家的想法一样&lt;/p&gt;&lt;p&gt;右边文件我们声明一个指针数组来存放&lt;/p&gt;&lt;p&gt;我们再看看右边文件的运行结果&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122015522938.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;大学里 谭浩强的c入门熟读的同学应该也早就知道结果了&lt;/p&gt;&lt;p&gt;温习一下而已，通过上面的2个例子我们可以理解到这些&lt;br /&gt;左边的例子实际上在内存区占用了一连串的地址，右边的例子实际上只生成了2个地址，通过不断更新这2个地址的内存内容来实现。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;step 2&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122016063432.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;左边的代码主要来演示指针赋值后的效果&lt;/p&gt;&lt;p&gt;运行结果为&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122016081081.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;右边的代码主要演示值类型与引用类型的区别 这也是为什么要用指针的原因之一&lt;/p&gt;&lt;p&gt;运行结果为&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122016095724.jpg" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;step 3&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122016255939.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;左边的例子我们来看一个简单的c程序&lt;/p&gt;&lt;p&gt;运行看看&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011122016275850.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;右边的就先不看了 需要进阶的场景还有很多&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;预祝大家圣诞快乐！&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2294799.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2011/12/20/2294799.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2011/12/16/2290421.html</id><title type="text">【linux+C】神器 vim  + 指针相关客串</title><summary type="text">前篇回顾 上篇介绍了linux下C编程基本环境配置以及相关工具使用选择。 不过10个大牛9个用vim，那么咱们就来玩vim。linux下玩c就别依靠图形界面。好吧告别Ide,命令行才是c的王道。 本篇文章感谢名为孙鹤同学的技术支持感谢有爱的c大牛们 本文中多处使用vim插件（孙鹤提供），这些插件大多是在http://www.vim.org/处下载。指针客串 因为毕业后就没玩过c了，都说指针是c的重点。但是指针作为一种地址变量，为什么不直接操作变量本身呢。文章末尾为大家揭晓vim的配置文件 ~/.vimrc 用户的默认配置文件 ~/.vim/plugin/ 用户的默认脚本文件...</summary><published>2011-12-16T08:48:00Z</published><updated>2011-12-16T08:48:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2011/12/16/2290421.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2011/12/16/2290421.html"/><content type="html">&lt;p&gt;&lt;strong&gt;前篇回顾&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;上篇介绍了linux下C编程基本环境配置以及相关工具使用选择。&lt;/p&gt;&lt;p&gt;不过10个大牛9个用vim，那么咱们就来玩vim。linux下玩c就别依靠图形界面。好吧告别Ide,命令行才是c的王道。&lt;/p&gt;&lt;p&gt;本篇文章感谢名为孙鹤同学的技术支持　感谢有爱的c大牛们&lt;/p&gt;&lt;p&gt;本文中多处使用vim插件（孙鹤提供），这些插件大多是在&lt;a href="http://www.vim.org/"&gt;http://www.vim.org/&lt;/a&gt;处下载。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;指针客串&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;因为毕业后就没玩过c了，都说指针是c的重点。但是指针作为一种地址变量，为什么不直接操作变量本身呢。文章末尾为大家揭晓&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;vim的配置文件&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;~/.vimrc&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 用户的默认配置文件&lt;br /&gt;~/.vim/plugin/ &amp;nbsp;&amp;nbsp;用户的默认脚本文件的存放目录&lt;br /&gt;~/.vim/ftplugin/&amp;nbsp;用户的默认文件类型相关脚本文件的存放目录&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;vim提供的编程支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;文本信息（行号、文件名等）&lt;br /&gt;代码缩进&lt;br /&gt;语法高亮&lt;br /&gt;快速定位&lt;br /&gt;标记位置&lt;br /&gt;全文搜索&lt;br /&gt;补全&lt;br /&gt;多文件编辑&lt;br /&gt;多窗口编辑&lt;br /&gt;函数列表&lt;br /&gt;文件列表&lt;br /&gt;函数跳转&lt;br /&gt;语法错误&lt;br /&gt;字符集的编码&lt;br /&gt;二进制查看&lt;/p&gt;&lt;p&gt;等等...&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;初试vim&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;在终端以root启动 输入vim命令 显示vim首页&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011121617122532.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;:r filename 读入一个文件内容,并写入到当前编辑器中&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011121616093117.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;按i进入插入模式&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011121616113244.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;编辑完后：w保存&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011121616250080.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;编辑完后按esc退出插入模式 进入正常模式&lt;/p&gt;&lt;p&gt;然后输入：sh进入shell&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011121616225846.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;编译运行&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/87114/2011121616260839.jpg" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;文本信息配置&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;set nu（写入配置文件.vimrc中）&amp;nbsp;显示行号。&lt;br /&gt;ctrl-g（正常模式下使用命令）&amp;nbsp;显示文件信息和当前行。&lt;br /&gt;statusline.vim（插件）&amp;nbsp;增加底部状态栏。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;代码缩进配置&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;filetype on（写入配置文件.vimrc中）&amp;nbsp;使vim对文件类型敏感。&lt;br /&gt;autocmd FileType c,cpp,h :setlocal cindent cinoptions=:0,g0,t0（写入配置文件.vimrc中）&amp;nbsp;设置c缩进风格，具体详情参见:h cinoptions-values。&lt;br /&gt;autocmd FileType c,cpp,h :setlocal et sta sw=4 sts=4 tabstop=4（写入配置文件.vimrc中）&amp;nbsp;设置一次缩进的距离是4个空格。&lt;br /&gt;=（正常模式或者可视模式下使用命令）&amp;nbsp;按照缩进风格排版代码。&lt;br /&gt;&amp;lt;（可视模式下使用命令）&amp;nbsp;向左缩进一级。&lt;br /&gt;&amp;gt;（可视模式下使用命令）&amp;nbsp;向右缩进一级。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;语法高亮&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;filetype plugin on（写入配置文件.vimrc中）&amp;nbsp;通常安装的vim中已经加入了各种语言的语法高亮插件，我们只需要打开文件类型相关的插件就可以了。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;快速定位&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;gd（正常模式下使用命令）&amp;nbsp;跳转到局部变量定义处。&lt;br /&gt;gD（正常模式下使用命令）&amp;nbsp;跳转到全局标量定义处。&lt;br /&gt;*（正常模式下使用命令）&amp;nbsp;搜索并跳到下一个光标所在的单词。&lt;br /&gt;g*（正常模式下使用命令）&amp;nbsp;功能接近*，但是查找的目标不带\&amp;lt;和\&amp;gt;单词分界符号。&lt;br /&gt;#（正常模式下使用命令）&amp;nbsp;搜索并跳到上一个光标所在的单词。&lt;br /&gt;g#（正常模式下使用命令）&amp;nbsp;功能接近#，但是查找的目标不带\&amp;lt;和\&amp;gt;单词分界符号。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;标记位置&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;m{a-zA-Z0-9} （正常模式下使用命令）&amp;nbsp;在当前位置制作一个标记，标记名字可以使用a-z或者A-Z之间的任意字符，例如输入ma，就是将当前位置标记为a标记。注意a-z为单文件标记，不可跨文件使用，而A-Z0-9为全局标记，可以跨文件使用。&lt;br /&gt;&amp;lsquo;{a-zA-Z0-9} （正常模式下使用命令）&amp;nbsp;跳转到本文件的标记上。&lt;br /&gt;:marks [{a-zA-z0-9}] （正常模式下使用命令）&amp;nbsp;查看指定标记的内容，不写标记号则查看所有。&lt;br /&gt;:delm {a-zA-z0-9} （正常模式下使用命令）&amp;nbsp;删除一个标记。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;全文搜索&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;:vimgrep（正常模式下使用命令）&amp;nbsp;全文搜索，功能同grep命令，但是支持在vim进行多文件跳转定位。&lt;br /&gt;使用方法:vimgrep 正则表达式 文件。文件支持通配符，例如*.c代表所有的.c文件。如果希望递归搜索，可以使用**/*，表示搜索所有的文件。&lt;br /&gt;:cl&amp;nbsp;列举结果&lt;br /&gt;:cc（正常模式下使用命令）&amp;nbsp;当前结果&lt;br /&gt;:cn（正常模式下使用命令）&amp;nbsp;下一个结果&lt;br /&gt;:cp（正常模式下使用命令）&amp;nbsp;上一个结果&lt;br /&gt;:cw（正常模式下使用命令）&amp;nbsp;重新打开搜索结果窗口&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;多文件编辑&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;vim f1 f2 &amp;hellip;&amp;hellip; fn（在shell下使用命令）&amp;nbsp;打开多个文件。&lt;br /&gt;:e 文件名（正常模式下使用命令）&amp;nbsp;在vim中打开新文件。&lt;br /&gt;:ls（正常模式下使用命令）&amp;nbsp;所有打开文件列表。&lt;br /&gt;:bn（正常模式下使用命令）&amp;nbsp;到下一个文件。&lt;br /&gt;:bp（正常模式下使用命令）&amp;nbsp;到上一个文件。&lt;br /&gt;:b# 或 ctrl-6（正常模式下使用命令）&amp;nbsp;到最近的前一个文件。&lt;br /&gt;set&amp;nbsp; autowriteall（写入配置文件.vimrc中）&amp;nbsp;如果讨厌每次打开新文件，vim喋喋不休的要求你保存，那么可以设置自动保存。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;多窗口编辑&lt;/strong&gt;&lt;br /&gt;:sp&amp;nbsp; 文件名（正常模式下使用命令）&amp;nbsp;横向拆分窗口（多行窗口）。&lt;br /&gt;:vsp 文件名（正常模式下使用命令）&amp;nbsp;纵向拆分窗口（多列窗口）。&lt;br /&gt;ctrl-w h（正常模式下使用命令）&amp;nbsp;将光标移动到左一个窗口。&lt;br /&gt;ctrl-w j（正常模式下使用命令）&amp;nbsp;将光标移动到下一个窗口。&lt;br /&gt;ctrl-w k（正常模式下使用命令）&amp;nbsp;将光标移动到上一个窗口。&lt;br /&gt;ctrl-w l（正常模式下使用命令）&amp;nbsp;将光标移动到右一个窗口。&lt;br /&gt;ctrl-w +（正常模式下使用命令）&amp;nbsp;当前窗口尺寸变大。&lt;br /&gt;ctrl-w -（正常模式下使用命令）&amp;nbsp;当前窗口尺寸变小。&lt;br /&gt;ctrl-w o（正常模式下使用命令）&amp;nbsp;只显示当前窗口。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;函数列表&lt;/strong&gt;&lt;br /&gt;taglist.vim（插件）&amp;nbsp;列表插件。&lt;br /&gt;let Tlist_Use_Right_Window = 1（写入配置文件.vimrc中）&amp;nbsp;如果希望列表在右侧显示，则加入这个配置，默认是左侧。&lt;br /&gt;:Tlist（正常模式下使用命令）&amp;nbsp;显示函数列表。&lt;br /&gt;d（在taglist窗口下使用）&amp;nbsp;从列表中删除文件。&lt;br /&gt;+（在taglist窗口下使用）&amp;nbsp;展开文件。&lt;br /&gt;-（在taglist窗口下使用）&amp;nbsp;折叠文件。&lt;br /&gt;=（在taglist窗口下使用）&amp;nbsp;折叠所有文件。&lt;br /&gt;x（在taglist窗口下使用）&amp;nbsp;显示或隐藏正常窗口。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;文件列表&lt;/strong&gt;&lt;br /&gt;NERD_tree.vim（插件）&amp;nbsp;横向拆分窗口（多行窗口）。&lt;br /&gt;let NERDTreeWinPos = 'right'（写入配置文件.vimrc中）&amp;nbsp;如果希望文件树在右侧显示，则加入这个配置，默认是左侧。&lt;br /&gt;:NERDTree（正常模式下使用命令）&amp;nbsp;显示文件列表。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;函数跳转&lt;/strong&gt;&lt;br /&gt;ctags（软件，需要另外安装）&amp;nbsp;生成多种语言tag文件的软件。&lt;br /&gt;Ctags &amp;ndash;R *.c（在shell下使用命令）&amp;nbsp;生成当前路径所有.c文件的tag，-R代表递归。&lt;br /&gt;:ta 标记 或 [g] ctrl-]&amp;nbsp;列举标签（多个标签）或者跳转到标签（单个标签）。&lt;br /&gt;ctrl-t&amp;nbsp;返回上一级。&lt;br /&gt;:tags&amp;nbsp;列出标签栈。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;语法错误&lt;/strong&gt;&lt;br /&gt;:make（正常模式下使用命令）&amp;nbsp;执行外部make命令，并且显示所有的编译警告和错误，并且可以在vim中定位。&lt;br /&gt;:cl&amp;nbsp;列举结果&lt;br /&gt;:cc（正常模式下使用命令）&amp;nbsp;当前结果&lt;br /&gt;:cn（正常模式下使用命令）&amp;nbsp;下一个结果&lt;br /&gt;:cp（正常模式下使用命令）&amp;nbsp;上一个结果&lt;br /&gt;:cw（正常模式下使用命令）&amp;nbsp;重新打开搜索结果窗口&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;二进制文件查看 （鉴于有同学理解出现分歧 将二进制查看更新为二进制文件查看）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;:范围!xxd（正常模式下使用命令）&amp;nbsp;把指定范围的部分转化为二进制文件阅读方式。&lt;br /&gt;:范围!xxd -r（正常模式下使用命令）&amp;nbsp;把指定范围的部分转回字符阅读方式。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;字符集的编码&lt;/strong&gt;&lt;br /&gt;let &amp;amp;termencoding=&amp;amp;encoding&lt;br /&gt;set fileencodings=utf-8,gbk,cp936（写入配置文件.vimrc中）&lt;br /&gt;&amp;nbsp;加入多种字符编码支持。&lt;br /&gt;:set fileencoding（正常模式下使用命令）&amp;nbsp;设定文件字符编码。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;补充&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;ctrl-p（插入模式下使用命令）&amp;nbsp;跳出补全菜单。&lt;br /&gt;ctrl-n（在跳出补全菜单后）&amp;nbsp;下一个结果。&lt;br /&gt;ctrl-p（在跳出补全菜单后）&amp;nbsp;上一个结果。&lt;br /&gt;ctrl-y（在跳出补全菜单后）&amp;nbsp;选择当前结果。&lt;br /&gt;ctrl-x ctrl-f（插入模式下使用命令）&amp;nbsp;文件名补全。&lt;br /&gt;ctrl-x ctrl-i（插入模式下使用命令）&amp;nbsp;包含的头文件。&lt;br /&gt;ctrl-x ctrl-]（插入模式下使用命令）&amp;nbsp;ctags（将在下文中介绍）符号补全。&lt;br /&gt;ctrl-x ctrl-o（插入模式下使用命令）&amp;nbsp;omni补全，需要设置omnifunc变量。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;vim其他命令 （参考vi(vim)教程）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;打开文件、保存、关闭文件：&lt;/p&gt;&lt;p&gt;vi filename &amp;nbsp; &amp;nbsp; &amp;nbsp; //打开filename文件&lt;br /&gt;:w&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //保存文件&lt;br /&gt;:w vpser.net&amp;nbsp; //保存至vpser.net文件&lt;br /&gt;:q&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;//退出编辑器，如果文件已修改请使用下面的命令&lt;br /&gt;:q!&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  &amp;nbsp;//退出编辑器，且不保存&lt;br /&gt;:wq &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;//退出编辑器，且保存文件&lt;/p&gt;&lt;p&gt;插入文本或行：&lt;/p&gt;&lt;p&gt;a &amp;nbsp; &amp;nbsp; &amp;nbsp;//在当前光标位置的右边添加文本&lt;br /&gt;i &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;//在当前光标位置的左边添加文本&lt;br /&gt;A &amp;nbsp; &amp;nbsp; //在当前行的末尾位置添加文本&lt;br /&gt;I &amp;nbsp; &amp;nbsp; &amp;nbsp;//在当前行的开始处添加文本(非空字符的行首)&lt;br /&gt;O &amp;nbsp; &amp;nbsp; //在当前行的上面新建一行&lt;br /&gt;o &amp;nbsp; &amp;nbsp; //在当前行的下面新建一行&lt;br /&gt;R &amp;nbsp; &amp;nbsp;//替换(覆盖)当前光标位置及后面的若干文本&lt;br /&gt;J &amp;nbsp; &amp;nbsp;//合并光标所在行及下一行为一行(依然在命令模式)&lt;/p&gt;&lt;p&gt;移动光标：&lt;/p&gt;&lt;p&gt;使用上下左右方向键&lt;/p&gt;&lt;p&gt;命令模式下：h&amp;nbsp;&amp;nbsp; 向左、j&amp;nbsp;&amp;nbsp; 向下 、k&amp;nbsp;&amp;nbsp; 向上、l&amp;nbsp; 向右。&lt;br /&gt;空格键 向右、Backspace&amp;nbsp; 向左、Enter&amp;nbsp; 移动到下一行首、-&amp;nbsp; 移动到上一行首。&lt;/p&gt;&lt;p&gt;删除：&lt;/p&gt;&lt;p&gt;x &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; //删除当前字符&lt;br /&gt;nx&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //删除从光标开始的n个字符&lt;br /&gt;dd &amp;nbsp; &amp;nbsp; &amp;nbsp;//删除当前行&lt;br /&gt;ndd &amp;nbsp; //向下删除当前行在内的n行&lt;br /&gt;u &amp;nbsp; &amp;nbsp; &amp;nbsp; //撤销上一步操作&lt;br /&gt;U &amp;nbsp; &amp;nbsp; &amp;nbsp;//撤销对当前行的所有操作&lt;/p&gt;&lt;p&gt;搜索：&lt;/p&gt;&lt;p&gt;/vpser &amp;nbsp; &amp;nbsp; //向光标下搜索vpser字符串&lt;br /&gt;?vpser&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//向光标上搜索vpser字符串&lt;br /&gt;n &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; //向下搜索前一个搜素动作&lt;br /&gt;N &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;//向上搜索前一个搜索动作&lt;/p&gt;&lt;p&gt;跳转：&lt;/p&gt;&lt;p&gt;n+ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;//向下跳n行&lt;br /&gt;n- &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; //向上跳n行&lt;br /&gt;nG &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;//跳到行号为n的行&lt;br /&gt;G &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; //跳至文件的底部&lt;/p&gt;&lt;p&gt;设置行号：&lt;/p&gt;&lt;p&gt;:set &amp;nbsp;nu &amp;nbsp; &amp;nbsp; //显示行号&lt;br /&gt;:set nonu &amp;nbsp; &amp;nbsp;//取消显示行号&lt;/p&gt;&lt;p&gt;复制：&lt;/p&gt;&lt;p&gt;yy &amp;nbsp; &amp;nbsp;//将当前行复制到缓存区，也可以用 "ayy 复制，"a 为缓冲区，a也可以替换为a到z的任意字母，可以完成多个复制任务。&lt;br /&gt;nyy &amp;nbsp; //将当前行向下n行复制到缓冲区，也可以用 "anyy 复制，"a 为缓冲区，a也可以替换为a到z的任意字母，可以完成多个复制任务。&lt;br /&gt;yw &amp;nbsp; &amp;nbsp;//复制从光标开始到词尾的字符。&lt;br /&gt;nyw &amp;nbsp; //复制从光标开始的n个单词。&lt;br /&gt;y^ &amp;nbsp; &amp;nbsp; &amp;nbsp;//复制从光标到行首的内容。&amp;nbsp;&lt;/p&gt;&lt;p&gt;y$ &amp;nbsp; &amp;nbsp; &amp;nbsp;//复制从光标到行尾的内容。&lt;br /&gt;p &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;//粘贴剪切板里的内容在光标后，如果使用了前面的自定义缓冲区，建议使用"ap 进行粘贴。&lt;br /&gt;P &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;//粘贴剪切板里的内容在光标前，如果使用了前面的自定义缓冲区，建议使用"aP 进行粘贴。&lt;/p&gt;&lt;p&gt;替换：&lt;/p&gt;&lt;p&gt;:s/old/new &amp;nbsp; &amp;nbsp; &amp;nbsp;//用new替换行中首次出现的old&lt;br /&gt;:s/old/new/g &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;//用new替换行中所有的old&lt;br /&gt;:n,m&amp;nbsp;s/old/new/g &amp;nbsp; &amp;nbsp; //用new替换从n到m行里所有的old&lt;br /&gt;:%s/old/new/g &amp;nbsp; &amp;nbsp; &amp;nbsp;//用new替换当前文件里所有的old&lt;/p&gt;&lt;p&gt;编辑其他资源:&lt;/p&gt;&lt;p&gt;:e otherfilename &amp;nbsp; &amp;nbsp;//编辑文件名为otherfilename的文件。&lt;/p&gt;&lt;p&gt;修改文件格式：&lt;/p&gt;&lt;p&gt;:set fileformat=unix &amp;nbsp; //将文件修改为unix格式，如win下面的文本文件在linux下会出现^M。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;客串答案&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;c传递参数都是值传递的，指针的一个作用是为了解决实现类似引用的效果，另外，使用指针可以直接操作内存！&lt;/p&gt;&lt;p&gt;孙鹤同学的解释：&lt;/p&gt;&lt;p&gt;每个线程有固定大小的栈,通常主线程的栈默认一般是8M,用指针去引用内存，往往是在使用堆内存,栈是有限的，并且受生存期影响,所以用堆的情况要比用栈更多,有些东西生存期很长，超过一个函数的调用，那么就需要用堆内存。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;本篇到此 希望对大家有帮助&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2290421.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2011/12/16/2290421.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/dubing/archive/2011/12/16/2289840.html</id><title type="text">读书笔记:  CLR篇 (让你了解C#.Net的实质)  (20111219更新)</title><summary type="text">写在开篇之前 本系列以笔记的方式、将一些书籍的核心内容概括，给自己留一个读书笔记。也方便大家用最短的时间掌握最丰富最重要的内容。 作为读书笔记，本身不属于虫子原创，对于知识点有疑问的同学可以提出大家一起交流。 书籍的选材目前限定在开发、运维、dba、网络安全几方面。欢迎有爱的同学一起学习。 clr基本 CLR(Common Language Runtime)是一个可由多种编程语言使用的“运行时”。(例如：c#，c++/cli,vb,f#,iron python,iron ruby,il...) CLR的核心功能内存管理、程序集加载、安全性、异常处理、线程同步、泛型、尾调用指令和基本...</summary><published>2011-12-16T02:37:00Z</published><updated>2011-12-16T02:37:00Z</updated><author><name>熬夜的虫子</name><uri>http://www.cnblogs.com/dubing/</uri></author><link rel="alternate" href="http://www.cnblogs.com/dubing/archive/2011/12/16/2289840.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/dubing/archive/2011/12/16/2289840.html"/><content type="html">&lt;p&gt;&lt;strong&gt;写在开篇之前&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;本系列以笔记的方式、将一些书籍的核心内容概括，给自己留一个读书笔记。也方便大家用最短的时间掌握最丰富最重要的内容。&lt;/p&gt;&lt;p&gt;作为读书笔记，本身不属于虫子原创，对于知识点有疑问的同学可以提出大家一起交流。&lt;/p&gt;&lt;p&gt;书籍的选材目前限定在开发、运维、dba、网络安全几方面。欢迎有爱的同学一起学习。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;strong&gt;clr基本&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;CLR(Common Language Runtime)是一个可由&lt;span style="color: #ff0000;"&gt;多种编程语言&lt;/span&gt;使用的&amp;ldquo;运行时&amp;rdquo;。(例如：c#，c++/cli,vb,f#,iron python,iron ruby,il...)&lt;/p&gt;&lt;p&gt;CLR的核心功能&lt;span style="color: #ff0000;"&gt;内存管理&lt;/span&gt;、程序集加载、安全性、&lt;span style="color: #ff0000;"&gt;异常处理&lt;/span&gt;、线程同步、泛型、尾调用指令和基本的公共语言基础结构 (CLI) 类型系统等。&lt;/p&gt;&lt;p&gt;托管模块是一个标准的32位microsoft windows可移值执行体&lt;span style="color: #ff0000;"&gt;pe32&lt;/span&gt;文件（64位系统为pe32+）,他们需要clr才能执行。&lt;/p&gt;&lt;p&gt;托管的程序集总是利用windows的&lt;span style="color: #ff0000;"&gt;数据执行保护&lt;/span&gt;和&lt;span style="color: #ff0000;"&gt;地址空间布局随机化&lt;/span&gt;，这2个功能旨在增强整个系统的安全性。&lt;/p&gt;&lt;p&gt;托管模块的组成部分：&lt;span style="color: #ff0000;"&gt;pe32（或pe32+）头&lt;/span&gt;，&lt;span style="color: #ff0000;"&gt;clr头&lt;/span&gt;，&lt;span style="color: #ff0000;"&gt;元数据&lt;/span&gt;，&lt;span style="color: #ff0000;"&gt;il中间代码&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;本地代码编译器生成的是&lt;span style="color: #ff0000;"&gt;面向特定cpu架构的代码&lt;/span&gt;。相反每个面向clr的编译器生成的都是&lt;span style="color: #ff0000;"&gt;il代码&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;　&amp;nbsp;&amp;nbsp; 源代码文件----》编译器----》托管模块&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;加载CLR&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;.net framework sdk提供了名为&lt;span style="color: #ff0000;"&gt;clrver.exe&lt;/span&gt;的命令行使用程序，它能列出一台机器上安装的所有clr版本。&lt;/p&gt;&lt;p&gt;c#编译器可以&lt;span style="color: #ff0000;"&gt;指定一个平台&lt;/span&gt;（基于x86 windows，x64 windows或者ia64 windows）.net4.0之前默认anycpu，4.0 exe项目默认x86&lt;/p&gt;&lt;p&gt;如果一个非托管应用程序调用loadlibrary来加载一个托管程序集，windows会&lt;span style="color: #ff0000;"&gt;自动加载并初始化clr&lt;/span&gt;，以便处理程序集中的代码。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;执行clr&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;span style="color: #000000;"&gt;托管程序集同时包含&lt;span style="color: #ff0000;"&gt;元数据和il&lt;/span&gt;。il是与cpu无关的机器语言。il比大多数cpu机器语言都要高级。il也能使用汇编语言来写。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;为了执行一个方法，首先必须把它的il转换为本地&lt;span style="color: #ff0000;"&gt;cpu指令&lt;/span&gt;。这是clr的jit编译器的职责。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;首次执行 托管exe----&amp;gt;jitcompiler----&amp;gt;查找方法、从元数据中获取il、分配内存块、编译cpu指令、修改方法对应的记录项、跳转内存块中的本地代码&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;第二次执行 托管exe跳过jitcompiler直接跳转内存块中的本地代码&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;对于大多数应用程序，因jit编译造成的性能损失并不显著，而且clr的jit编译器会&lt;span style="color: #ff0000;"&gt;对本地代码进行优化&lt;/span&gt;，优化后的代码会获得更出色的性能。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;c#调试产生的&lt;span style="color: #ff0000;"&gt;pdb&lt;/span&gt;文件就是帮助调试器查找局部变量并将il指令映射到源代码。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;release版本就是让发布程序经过jit优化，所以线上项目最好都以&lt;span style="color: #ff0000;"&gt;release版本&lt;/span&gt;发布&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;clr提供一个在操作系统进程中执行多个托管应用程序的能力。每个托管的应用程序都在一个&lt;span style="color: #ff0000;"&gt;appdomain&lt;/span&gt;中执行。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;IL&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;IL是基于&lt;span style="color: #ff0000;"&gt;栈&lt;/span&gt;的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;微软提供&lt;span style="color: #ff0000;"&gt;ilasm.exe&lt;/span&gt;的il汇编器和一个名为&lt;span style="color: #ff0000;"&gt;ildasm.exe&lt;/span&gt;的il反汇编器。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;/span&gt;IL指令是无类型的（&lt;span style="color: #ff0000;"&gt;typeless&lt;/span&gt;）&lt;/p&gt;&lt;p&gt;IL最大的优势并不在于它对底层CPU的抽象，而是应用&lt;span style="color: #ff0000;"&gt;程序的健壮性和安全性&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;FramWork&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;framework class library是一组&lt;span style="color: #ff0000;"&gt;dll程序集&lt;/span&gt;的名称，其中包含数千个类型定义，每个类型都公开了一些功能。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;通用类型系统（common type system）描述了类型的&lt;span style="color: #ff0000;"&gt;定义和行为&lt;/span&gt;。一个类型可以包含另个或者多个成员。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;公共语言运行规范（common language specification）详细定义了一个&lt;span style="color: #ff0000;"&gt;最小功能集&lt;/span&gt;。任何编译器生成的类型要向兼容于由其他符合cls面向clr的语言所生成的组件，就必须支持这个最小功能集&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;响应文件&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;响应文件是一个文本，其中包含了一组&lt;span style="color: #ff0000;"&gt;编译器命令行开关&lt;/span&gt;。执行csc.exe时，编译器会打开响应文件，并使用其中包含的所有开关，感觉就像是这些开关直接在命令行传递给csc.exe。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;响应文件能带来很多方便，因为不必每次在编译项目时，都手动指定需要的命令行参数。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;c#编译器允许同时指定&lt;span style="color: #ff0000;"&gt;多个响应文件&lt;/span&gt;。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;程序集&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;程序集是一个抽象的概念，&lt;span style="color: #ff0000;"&gt;clr&lt;/span&gt;实际上不和模块一起工作，而是和&lt;span style="color: #ff0000;"&gt;程序集&lt;/span&gt;一起。&lt;/p&gt;&lt;p&gt;程序集是一个或多个模块/资源文件的逻辑分组。是&lt;span style="color: #ff0000;"&gt;重用&lt;/span&gt;、&lt;span style="color: #ff0000;"&gt;安全性&lt;/span&gt;以及&lt;span style="color: #ff0000;"&gt;版本控制&lt;/span&gt;的最小单元。在clr中相当于一个&amp;ldquo;组件&amp;rdquo;&lt;/p&gt;&lt;p&gt;托管模块（il+元数据）+资源文件 ----》编译器----》程序集&lt;/p&gt;&lt;p&gt;默认情况，编译器会把生成的&lt;span style="color: #ff0000;"&gt;托管模块&lt;/span&gt;转换成&lt;span style="color: #ff0000;"&gt;程序集&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;　&amp;nbsp; &amp;nbsp;对于一个&lt;span style="color: #ff0000;"&gt;可重用的、可保护的、可版本控制&lt;/span&gt;的组件，程序集把它的逻辑表示和物理表示区分开。&lt;/p&gt;&lt;p&gt;在程序集的模块中还包含&lt;span style="color: #ff0000;"&gt;与引用的程序集有关的信息&lt;/span&gt;（例如版本号）。这些信息使程序集可以自描述。换句话说，clr能判断出为了执行程序集中的代码，程序集中得依赖对象是什么。不需要在注册表或active directory domain services中保存额外的信息。&lt;/p&gt;&lt;p&gt;程序集的所有文件中，有一个文件容纳了&lt;span style="color: #ff0000;"&gt;清单&lt;/span&gt;。清单也是一组元数据表的集合，表中主要包含了作为程序集的组成部分的文件的名称。&lt;/p&gt;&lt;p&gt;可用单独的文件对类型进行划分、可在自己的程序集中添加资源或者数据文件、程序集包含的各个类型可以用不同的编程语言来实现。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;元数据&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;　&amp;nbsp; 元数据是一组&lt;span style="color: #ff0000;"&gt;数据表&lt;/span&gt;。其中的一些数据表描述可模块中定义的内容，比如类型及成员。还有一些元数据描述了托管模块引用的内容，比如导入的类型及成员。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;元数据是一些&lt;span style="color: #ff0000;"&gt;老技术的超集&lt;/span&gt;，这些老技术包括com的&amp;ldquo;类型库&amp;rdquo;和&amp;ldquo;接口定义语言&amp;rdquo;文件。&lt;/p&gt;&lt;p&gt;元数据总是嵌入和代码相同&lt;span style="color: #ff0000;"&gt;exe/dll文件&lt;/span&gt;中。&lt;/p&gt;&lt;p&gt;元数据的用途：编译时元数据消除对本地c/c++头和库文件的要求，vs使用元数据帮助你&lt;span style="color: #ff0000;"&gt;智能感知代码&lt;/span&gt;，&lt;span style="color: #ff0000;"&gt;类型安全验证&lt;/span&gt;，&lt;span style="color: #ff0000;"&gt;序列化&lt;/span&gt;，&lt;span style="color: #ff0000;"&gt;gc管理&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;元数据是一个二进制数据块，由几个表构成。这些表分为3个类别：&lt;span style="color: #ff0000;"&gt;定义表、引用表和清单表&lt;/span&gt;。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;定义表：moduledef，typedef，methoddef，fielddef，paramdef，propertydef，eventdef&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;引用表：assemblyref,mouduleref,typeref,memberref&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;清单表：assemblydef，filedef，manifestresourcedef，exportedtypesdef&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;程序集还讲语言文化作为其身份标识的一部分。没有指定具体语言文化的程序集称为语言文化中性。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;部署&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;程序集的打包没有任何特殊需求。不需要对注册表进行任何修改，clr就可以在应用程序的目录中查找引用的程序集。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;也可以&lt;span style="color: #ff0000;"&gt;使用其他机制来打包和安装程序集文件&lt;/span&gt;，比如使用.cab文件。还可以将程序集文件打包成一个msi。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;msi文件可实现程序集的&amp;ldquo;按需安装&amp;rdquo;，在clr首次尝试加载程序集的时候才安装这个程序集。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;部署到和应用程序相同的目录中得程序集称为&lt;span style="color: #ff0000;"&gt;私有部署的程序集&lt;/span&gt;，这是因为程序集文件不和其他任何应用程序共享（除非其他应用程序也部署到这个目录中）。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;clr尝试定位一个程序集文件时，总是先在应用程序基目录中查找。如果没有找到，就会扫描几个子目录。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;对于可执行应用程序（exe），配置文件必须在应用程序的基目录中，而且必须采用exe文件的全名作为文件名，再加一个.config扩展名&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;对于microsoft asp.net web窗体应用程序，文件必须在web应用程序的虚拟根目录中，而且总是命名为web.config　&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;共享程序集与强命名程序集&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;弱命名程序集与强命名程序集都是&lt;span style="color: #ff0000;"&gt;c#编译器&lt;/span&gt;或者&lt;span style="color: #ff0000;"&gt;al.exe&lt;/span&gt;产生。他们的区别在于强命名程序集使用发布者的公钥/私钥对进行了签名，它唯一性地标识了程序集的发布者。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;一个程序集可以采取两种方式来部署：&lt;span style="color: #ff0000;"&gt;私有或全局&lt;/span&gt;。弱命名程序集只可以私有部署。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;可以使用&lt;span style="color: #ff0000;"&gt;sn.exe&lt;/span&gt;来生成公钥/私钥对。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;全局程序集缓存&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;如果一个程序集要由多个应用程序访问，必须把它放到一个已知的目录中，而且clr在检测到对该程序集的一个引用时，必须知道自动检查该目录。这个已知的位置成为&lt;span style="color: #ff0000;"&gt;全局程序集缓存&lt;/span&gt;(GAC)。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;GAC通常位于c:\windows\assembly目录下(假定windows安装到c:\windows目录)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;可以使用&lt;span style="color: #ff0000;"&gt;GACUtil.exe&lt;/span&gt;在GAC中安装一个强命名程序集&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;　&lt;/span&gt;&lt;span style="color: #000000;"&gt;　GAC目录是&lt;span style="color: #ff0000;"&gt;结构化&lt;/span&gt;的：其中包含许多子目录，并用一个算法来生成这些子目录的名称。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;CLR解析引用类型&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;CLR先加载并初始化程序集，然后读取clr头，查找标识应用程序的入口方法的methoddeftoken。然后clr会检索methoddef元数据表，找到该方法的il代码在文件中的偏移量，把这些il代码jit编译成本地代码。编译时会对代码进行验证以确保其类型安全性。最后执行本地代码。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;clr可以在三个地方找到类型：同一个文件（早起绑定）、不同的文件但同一个程序集（当前程序集清单目录）、不同的文件不同的程序集（其他程序集清单目录）。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;对于clr来说，所有程序集都是根据&lt;span style="color: #ff0000;"&gt;名称、版本、语言文化和公钥&lt;/span&gt;来标识的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;GAC根据&lt;span style="color: #ff0000;"&gt;名称、版本、语言文化和cpu架构&lt;/span&gt;来标识程序集。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;类型基础&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&lt;strong&gt;&lt;/strong&gt;所有类型都是从&lt;span style="color: #ff0000;"&gt;system.object&lt;/span&gt;派生&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;system.object提供4个公共实例方法&lt;span style="color: #ff0000;"&gt;equals，gethashcode，tostring，gettype&lt;/span&gt;。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;system.object提供2个受保护方法&lt;span style="color: #ff0000;"&gt;memberwiseclone，finalize&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;clr要求所有对象都用&lt;span style="color: #ff0000;"&gt;new操作符&lt;/span&gt;来创建。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;new操作符所作的事情：1.它计算类型及其所有基类型中定义的所有实例字段所需的字节数。堆上的每个对象都需要一些额外的成员--&amp;ldquo;类型对象指针&amp;rdquo;和&amp;ldquo;同步块索引&amp;rdquo;。这些成员由clr用于管理对象。这些额外成员的字节数会计入对象大小。2.它从托管堆中分配指定类型要求的字节数，从而分配对象的内存，分配的所有字节都设为零。3.它初始化对象的--&amp;ldquo;类型对象指针&amp;rdquo;和&amp;ldquo;同步块索引&amp;rdquo;成员。4.调用类型的实例构造器，向其传入在对new的应用中指定的任何实参。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;clr最重要的特性之一就是&lt;span style="color: #ff0000;"&gt;类型安全性&lt;/span&gt;。在运行时，clr总要知道一个对象是什么类型。调用gettype方法，总是知道一个对象确切的类型是什么。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;clr允许将一个对象转换成为它的&lt;span style="color: #ff0000;"&gt;实际类型&lt;/span&gt;或者它的任何&lt;span style="color: #ff0000;"&gt;基类型&lt;/span&gt;。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;使用c#的&lt;span style="color: #ff0000;"&gt;is&lt;/span&gt;和&lt;span style="color: #ff0000;"&gt;as&lt;/span&gt;操作符来转型。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;命名空间用于对相关的类型进行&lt;span style="color: #ff0000;"&gt;逻辑性分组&lt;/span&gt;，开发人员使用命名空间来方便地定位一个类型。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;命名空间和程序集不一定是相关的。特别是同一个命名空间中的各个类型可能是在不同的程序集中实现的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;一个线程创建时，会分配一个1mb大小的栈。这个栈的空间用于向方法传递实参，并用于方法内部定义的局部变量。栈是从高位内存地址向地位内存地址构建的。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;windows进程启动后，clr加载到其中，托管堆初始化，创建一个线程。当jit将方法的il代码转化成本地cpu指令时，会注意到方法内部引用的所有类型。在这个时候clr要确保定义了这些类型的所有程序集已加载。然后利用程序集的元数据，clr提取与这些类型有关的信息，并创建一些数据结构来标识类型本身。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;堆上的所有对象都包含两个额外的成员&lt;span style="color: #ff0000;"&gt;类型对象指针&lt;/span&gt;和&lt;span style="color: #ff0000;"&gt;同步块索引&lt;/span&gt;。定义一个类型时，可以在类型的内部定义静态数据字段。为这些静态数据字段提供支援的字节是在类型对象自身中分配的。在每个类型对象中，最后都包含一个方法表。在方法表中，类型定义的每个方法都有一个对应的记录项。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;当clr确定方法需要的所有类型对象都已创建，而且方法的代码已经编译之后，就允许线程开始执行方法的本地代码。方法的&amp;ldquo;序幕&amp;rdquo;代码执行时必须在线程栈中为局部变量分配内存。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;jit编译器在类型对象的方法表中查找引用了被调用方法的记录项，对方法进行jit编译，再调用jit编译的代码。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;system.object的gettype方法返回的是&lt;span style="color: #ff0000;"&gt;存储在制定对象的&amp;ldquo;类型对象指针&amp;rdquo;成员中的地址&lt;/span&gt;。换言之，gettype方法返回的是指向对象类型的一个指针。这样一来就可以判断出系统中任何对象的真实类型。&lt;/span&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;1219版先更新到此 希望对大家有帮助 &lt;/span&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/dubing/aggbug/2289840.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/dubing/archive/2011/12/16/2289840.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
