﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-圆心</title><link>http://www.cppblog.com/range/</link><description>寻找世界的心，寻找自己的心 </description><language>zh-cn</language><lastBuildDate>Wed, 22 Apr 2026 01:47:11 GMT</lastBuildDate><pubDate>Wed, 22 Apr 2026 01:47:11 GMT</pubDate><ttl>60</ttl><item><title>unix共享内存要点</title><link>http://www.cppblog.com/range/archive/2012/07/23/184665.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Sun, 22 Jul 2012 16:08:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2012/07/23/184665.html</guid><wfw:comment>http://www.cppblog.com/range/comments/184665.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2012/07/23/184665.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/184665.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/184665.html</trackback:ping><description><![CDATA[<br />共享内存优点：1.在进程之间不通过内核传递数据，即不通过系统调用拷贝数据，达到快速，高效的数据传输。<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.随内核持续<br />*nix的共享内存有两套API：Posix和System V<br /><br />两者的主要差别是共享内存的大小<br />1.Posix共享内存大小可通过函数ftruncate随时修改<br />2.System V共享内存大小在创建时就已经确定，而且最大值根据系统有所不同<br /><br />&nbsp;Posix共享内存&nbsp;<br />&nbsp; &nbsp; #include &lt;sys/mman.h&gt; &nbsp;（mmap，munmap，msync，shm_open，shm_unlink）<br /><br />最主要的函数 &nbsp;-- mmap<br />&nbsp; &nbsp; &nbsp;void* mmap(void* addr,size_t len,int prot,int flags,int fd,off_t offset)<br />&nbsp; &nbsp; &nbsp;函数将一个句柄映射到内存中，这个句柄可以是open的文件句柄，也可以是shm_open的共享内存区对象。当fd=-1时为匿名共享内存。<br />&nbsp; &nbsp; &nbsp;*nix一切皆文件的观点，shm_open也是在/dev/shm目录下创建一个文件对象，返回对象的描述符。<br />&nbsp; &nbsp; &nbsp;mmap将句柄作为共享内存的底层支撑对象，映射到内存中，这样可以不通过read、write在进程之间共享内存。由此推测一下，在*nix的进程间传递数据更加原始的方法是进程间读写一个文件。但是频繁的open、read、write、lseek系统调用会消耗过多的计算资源。所以想到了将这个文件句柄映射到内存中，这样就提高了进程间传递数据的效率。<br /><br />需要注意的函数 -- msync<br />&nbsp; &nbsp; &nbsp; 当修改了内存映射区的内存后，内核会在某个时刻将文件的内容更新。为了确信文件被更新，调用函数msync。文件的更新可以是同步（MS_SYNC）也可以是异步（MS_ASYNC）。（估计这里也是调用了函数write更新文件）<br /><br />System V共享内存<br />&nbsp; &nbsp; #include &lt;sys/shm.h&gt; &nbsp;(shmget,shmat,shmdt,shmctl)<br />由于System V的共享内存有大小的限制，所以可考虑，使用共享内存数组来解决这个问。虽然数组的大小即一个进程可以获取共享内存的数量也是有限制，但是可以缓解System V单个共享内存过小的问题。<img src ="http://www.cppblog.com/range/aggbug/184665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2012-07-23 00:08 <a href="http://www.cppblog.com/range/archive/2012/07/23/184665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>erlang Receive的工作机制</title><link>http://www.cppblog.com/range/archive/2012/07/01/181020.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Sun, 01 Jul 2012 09:17:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2012/07/01/181020.html</guid><wfw:comment>http://www.cppblog.com/range/comments/181020.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2012/07/01/181020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/181020.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/181020.html</trackback:ping><description><![CDATA[<div>receive works as follows:</div><div>1. When we enter a receive statement, we start a timer (but only if an&nbsp;after section is present in the expression).</div><div>2. Take the first message in the mailbox and try to match it against&nbsp;Pattern1, Pattern2, and so on. If the match succeeds, the message&nbsp;is removed from the mailbox, and the expressions following the&nbsp;pattern are evaluated.</div><div>3. If none of the patterns in the receive statement matches the first&nbsp;message in the mailbox, then the first message is removed from&nbsp;the mailbox and put into a &#8220;save queue.&#8221; The second message&nbsp;in the mailbox is then tried. This procedure is repeated until a&nbsp;matching message is found or until all the messages in the mailbox&nbsp;have been examined.</div><div><div>4. If none of the messages in the mailbox matches, then the process&nbsp;is suspended and will be rescheduled for execution the next time a&nbsp;new message is put in the mailbox. Note that when a new message&nbsp;arrives, the messages in the save queue are not rematched; only&nbsp;the new message is matched.</div><div>5. As soon as a message has been matched, then all messages that&nbsp;have been put into the save queue are reentered into the mailbox&nbsp;in the order in which they arrived at the process. If a timer was&nbsp;set, it is cleared.</div><div>6. If the timer elapses when we are waiting for a message, then evaluate&nbsp;the expressions ExpressionsTimeout and put any saved messages&nbsp;back into the mailbox in the order in which they arrived at the&nbsp;process.</div></div><img src ="http://www.cppblog.com/range/aggbug/181020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2012-07-01 17:17 <a href="http://www.cppblog.com/range/archive/2012/07/01/181020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>strcasestr函数</title><link>http://www.cppblog.com/range/archive/2011/10/09/157888.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Sun, 09 Oct 2011 11:12:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2011/10/09/157888.html</guid><wfw:comment>http://www.cppblog.com/range/comments/157888.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2011/10/09/157888.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/157888.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/157888.html</trackback:ping><description><![CDATA[<br /><div><span style="font-size: 12px;">&nbsp;</span><span style="font-size: 12pt; "> &nbsp; &nbsp; &nbsp;#define _GNU_SOURCE</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12pt; ">&nbsp; &nbsp; &nbsp; &nbsp;#include &lt;string.h&gt;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12pt; ">&nbsp; &nbsp; &nbsp; &nbsp;char *strcasestr(const char *haystack, const char *needle);</span></div><div style="color: black; font-family: Tahoma; font-size: 11px; "><br /><span style="font-size: 12pt; ">&nbsp; &nbsp; &nbsp; &nbsp; 用于在c串haystack中查找c串needle，忽略大小写。如果找到则返回needle串在haystack串中第一次出现的位置的char指针</span><br /><br /><span style="font-size: 12pt; ">&nbsp; &nbsp; &nbsp; &nbsp; 在实际的应用中如果只加上头文件，当编译时会出现 &nbsp;</span><span class="Apple-style-span" style="font-family: verdana, 'courier new'; font-size: 12pt; ">warning: assignment makes pointer from integer without a cast</span></div><div><br /><span style="font-size: 12pt; ">&nbsp; &nbsp; &nbsp; &nbsp;这是因为函数的声明在调用之后。未经声明的函数默认返回int型。</span><br />&nbsp;<br /><span style="font-size: 12pt; ">&nbsp; &nbsp; &nbsp; &nbsp;因此要在#include</span><span style="font-size: 12pt; color: red; ">所有</span><span style="font-size: 12pt; ">头文件之前加 &nbsp;</span><div style="display: inline-block; "></div><span class="Apple-style-span" style="font-size: 12pt; ">#define _GNU_SOURCE &nbsp;，以此解决此问题。</span></div><img src ="http://www.cppblog.com/range/aggbug/157888.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2011-10-09 19:12 <a href="http://www.cppblog.com/range/archive/2011/10/09/157888.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>服务器高性能程序 磁盘I/O篇</title><link>http://www.cppblog.com/range/archive/2011/08/26/154449.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Fri, 26 Aug 2011 12:04:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2011/08/26/154449.html</guid><wfw:comment>http://www.cppblog.com/range/comments/154449.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2011/08/26/154449.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/154449.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/154449.html</trackback:ping><description><![CDATA[<div><p>Linux IO<span style="font-family:宋体;">系统的架构图</span></p>  <p><img src="http://www.cppblog.com/images/cppblog_com/range/21.jpg" width="326" height="433" alt="" /><br /></p>  <p>&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:-21.0pt;"><span><span>一．</span><span style="font-family:宋体;">设备</span>-------- </span><span style="font-family:宋体;">影响磁盘性能的因素</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">硬盘的转速影响硬盘的整体性能。一般情况下转速越大，性能会越好。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">硬盘的性能因素主要包括两个：1.</span><span style="font-family:宋体;">平均访问时间2</span><span style="font-family:宋体;">传输速率。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">平均访问时间包括两方面因素：</span></p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">平均寻道时间</span><span><span><span style="font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:black">(Average Seek Time)</span></span></span><span><span><span style="font-family:宋体; color:black">是指硬盘的磁头移动到盘面指定磁道所需的时间</span></span></span><span style="font-family:宋体;">。一般在3ms</span><span style="font-family:宋体;">至15ms</span><span style="font-family:宋体;">之间。</span></p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">平均旋转等待时间</span><span><span style="font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:black">(Latency)</span></span><span><span style="font-family:宋体;color:black">是指磁头已处于要访问的磁道，等待所要访问的扇区旋转至磁头下方的时间。</span></span><span style="font-family:宋体;">一般在2ms</span><span style="font-family:宋体;">至6ms</span><span style="font-family:宋体;">之间。</span></p>  <p style="margin-left:21.0pt;">&nbsp;</p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">传输速率(Data Transfer Rate) </span><span style="font-family:宋体;">硬盘的数据传输率是指硬盘读写数据的速度，单位为兆字节每秒（MB/s</span><span style="font-family:宋体;">）。磁盘每秒能传输80M~320M</span><span style="font-family:宋体;">字节。</span></p>  <p style="margin-left:21.0pt;">&nbsp;</p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">传输速率包括内部传输速率和外部传输速率。</span></p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">内部传输率(Internal Transfer Rate) </span><span style="font-family:宋体;">也称为持续传输率(Sustained Transfer Rate)</span><span style="font-family:宋体;">，它反映了硬盘</span><a href="http://baike.baidu.com/view/266782.htm" target="_blank"><span><span style="font-family:宋体; color:windowtext;text-decoration:none;text-underline:none">缓冲区</span></span></a><span style="font-family:宋体;">未用时的性能。内部传输率主要依赖于硬盘的旋转速度。</span></p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">外部传输率（External Transfer Rate</span><span style="font-family:宋体;">）也称为</span><a href="http://baike.baidu.com/view/188732.htm" target="_blank"><span><span style="font-family:宋体; color:windowtext;text-decoration:none;text-underline:none">突发数据传输率</span></span></a><span style="font-family:宋体;">（<span>Burst Data Transfer Rate</span></span><span style="font-family:宋体;">）或接口传输率，它标称的是</span><a href="http://baike.baidu.com/view/65714.htm" target="_blank"><span><span style="font-family:宋体; color:windowtext;text-decoration:none;text-underline:none">系统总线</span></span></a><span style="font-family:宋体;">与硬盘缓冲区之间的数据传输率，外部数据传输率与</span><a href="http://baike.baidu.com/view/82486.htm" target="_blank"><span><span style="font-family:宋体; color:windowtext;text-decoration:none;text-underline:none">硬盘接口类型</span></span></a><span style="font-family:宋体;">和</span><a href="http://baike.baidu.com/view/6845.htm" target="_blank"><span><span style="font-family:宋体; color:windowtext;text-decoration:none;text-underline:none">硬盘缓存</span></span></a><span style="font-family:宋体;">的大小有关。STAT2 </span><span style="font-family:宋体;">的传输速率在300MB/s</span><span style="font-family:宋体;">级别。</span></p>  <p style="margin-left:21.0pt;">&nbsp;</p>  <p style="text-indent:20.25pt"><span style="font-family:宋体;">因此在硬件级上，提高磁盘性能的关键主要是降低平均访问时间。</span></p>  <p style="margin-left:21.0pt;text-indent:-21.0pt;"><span><span>二．</span><span style="font-family:宋体;">设备驱动</span></span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">内存到硬盘的传输方式：poll</span><span style="font-family:宋体;">，中断，DMA</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>DMA</span><span style="font-family:宋体;">：当 CPU </span><span style="font-family:宋体;">初始化这个传输动作，传输动作本身是由&nbsp;DMA </span><span style="font-family:宋体;">控制器&nbsp;</span><span style="font-family:宋体;">来实行和完成。</span></p>  <p style="margin-left:52.5pt; text-indent:-31.5pt;"><span>DMA</span><span style="font-family:宋体;">控制器获得总线控制权后，CPU</span><span style="font-family:宋体;">即刻挂起或只执行内部操作，由DMA</span><span style="font-family:宋体;">控制器输出读写命令，直接控制RAM</span><span style="font-family:宋体;">与I/O</span><span style="font-family:宋体;">接口进行DMA</span><span style="font-family:宋体;">传输。DMA</span><span style="font-family:宋体;">每次传送的是磁盘上相邻的扇区。Scatter-gather DMA</span><span style="font-family:宋体;">允许传送不相邻的扇区。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>CPU</span><span style="font-family:宋体;">性能与硬盘与内存的数据传输速率关系不大。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">设备驱动内有一个结构管理着IO</span><span style="font-family:宋体;">的请求队列</span></p>  <p style="margin-left:21.0pt;"><span>structrequest_queue</span><span style="font-family:宋体;">（include/linux/Blkdev.h</span><span style="font-family:宋体;">）</span></p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">这里不仅仅有读写请求的数据块，还有用于IO</span><span style="font-family:宋体;">调度的回调函数结构。每次需要传输的时候，就从队列中选出一个数据块交给DMA</span><span style="font-family:宋体;">进行传输。</span></p>  <p style="margin-left:21.0pt;">&nbsp;</p>  <p style="margin-left:21.0pt;"><span style="font-family:宋体;">所以<a name="_GoBack">IO</a></span><span><span style="font-family:宋体;">调度的回调函数这是降低平均访问的时间</span></span><span style="font-family:宋体;">的关键。</span></p>  <p>&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:-21.0pt;"><span><span>三．</span>OS</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>IO</span><span style="font-family:宋体;">调度器</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Linux kernel</span><span style="font-family:宋体;">提供了四个调度器供用户选择。他们是noop,cfq,deadline,as</span><span style="font-family:宋体;">。可以在系统启动时设置内核参数elevator=&lt;name&gt;</span><span style="font-family:宋体;">来指定默认的调度器。也可以在运行时为某个块设备设置IO</span><span style="font-family:宋体;">调度程序。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">下面来简要介绍这四个调度器的电梯调度算法。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Noop</span><span style="font-family:宋体;">：最简单的调度算法。新的请求总是被添加到队头或者队尾，然后总是从队头中选出将要被处理的请求。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>CFQ</span><span style="font-family:宋体;">：（Complete FarinessQueueing</span><span style="font-family:宋体;">）它的目标是在所有请求的进程中平均分配IO</span><span style="font-family:宋体;">的带宽。因此，它会根据进程创建自己的请求队列，然后将IO</span><span style="font-family:宋体;">请求放入相应的队列中。在使用轮转法从每个非空的队列中取出IO</span><span style="font-family:宋体;">请求。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Deadline</span><span style="font-family:宋体;">：使用了四个队列，两个以磁盘块序号排序的读写队列，两个以最后期限时间排序的读写队列。算法首先确定下一个读写的方向，读的优先级高于写。然后检查被选方向的最后期限队列：如果最后期限时间的队列中有超时的请求，则将刚才的请求移动至队尾，然后在磁盘号排序队列中从超时请求开始处理。当处理完一个方向的请求后，在处理另一个方向的请求。（读请求的超时时间是500ms</span><span style="font-family:宋体;">，写请求的超时时间是5s</span><span style="font-family:宋体;">）</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Anticipatory</span><span style="font-family:宋体;">：它是最复杂的IO</span><span style="font-family:宋体;">调度算法。和deadline</span><span style="font-family:宋体;">算法一样有四个队列。还附带了一些启发式策略。它会从当前的磁头位置后的磁盘号中选择请求。在调度了一个由P</span><span style="font-family:宋体;">进程的IO</span><span style="font-family:宋体;">请求后，会检查下一个请求，如果还是P</span><span style="font-family:宋体;">进程的请求，则立即调度，如果不是，同时预测P</span><span style="font-family:宋体;">进程很快会发出请求，则还延长大约7ms</span><span style="font-family:宋体;">的时间等待P</span><span style="font-family:宋体;">进程的IO</span><span style="font-family:宋体;">请求。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Write/Read</span><span style="font-family:宋体;">函数</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">以ext3</span><span style="font-family:宋体;">的write</span><span style="font-family:宋体;">为例：</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">系统调用write()</span><span style="font-family:宋体;">的作用就是修改页高速缓存内的一些页的内容，如果页高速缓存内没有所要的页则分配并追加这些页。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">当脏页达到一定数量或者超时后，将脏页刷回硬盘。也可以执行相关系统调用。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">为什么要达到一定数量，是因为延迟写能在一定层度上提高系统的性能，这也使得块设备的平均读请求会多于写请求。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">在程序中调用write</span><span style="font-family:宋体;">函数，将进入系统调用f_op-&gt;write</span><span style="font-family:宋体;">。这个函数将调用ext3</span><span style="font-family:宋体;">的do_sync_write</span><span style="font-family:宋体;">。这个函数将参数封装后调用generic_file_aio_write</span><span style="font-family:宋体;">。由参数名可以看出同步写变成了异步写。如果没有标记O_DIRECT</span><span style="font-family:宋体;">，将调用函数generic_file_buffered_write</span><span style="font-family:宋体;">将写的内容写进kernel</span><span style="font-family:宋体;">的高速页缓存中。Buffer</span><span style="font-family:宋体;">是以page</span><span style="font-family:宋体;">为单位即4k</span><span style="font-family:宋体;">。之后当调用cond_resched()</span><span style="font-family:宋体;">进行进程的调度，DMA</span><span style="font-family:宋体;">会将buffer</span><span style="font-family:宋体;">中的内容写进硬盘。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">所以当每次以4k</span><span style="font-family:宋体;">为单位写入硬盘时效率会达到最高。下面是UNIX</span><span style="font-family:宋体;">环境高级编程的实验结果：</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/22.jpg" width="471" height="598" alt="" /><br /></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">下图是linux </span><span style="font-family:宋体;">的块设备的数据操作层次：</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Sector</span><span style="font-family:宋体;">扇区：是设备驱动和IO</span><span style="font-family:宋体;">调度程序处理数据粒度。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Block</span><span style="font-family:宋体;">块：是VFS</span><span style="font-family:宋体;">和文件系统处理数据的粒度。其大小不唯一，可以是512,1024,2048,4096</span><span style="font-family:宋体;">字节。内核操作的块大小是4096</span><span style="font-family:宋体;">字节。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Segment</span><span style="font-family:宋体;">段：是DMA</span><span style="font-family:宋体;">传送的单位。每一个段包含了相邻的扇区，它能使DMA</span><span style="font-family:宋体;">传送不相邻的扇区。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/23.jpg" width="359" height="353" alt="" /><br /></p>  <p>&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:-21.0pt;"><span><span>四．</span><span style="font-family:宋体;">用户程序</span></span></p>  <p style="margin-left:21.0pt"><span style="font-family:宋体;">根据以上的分析，我们的<span>write buffer</span></span><span style="font-family:宋体;">一般设置为4K</span><span style="font-family:宋体;">的倍数。</span></p>  <p style="margin-left:21.0pt">&nbsp;</p>  <p style="margin-left:21.0pt"><span style="font-family:宋体;">在程序中有意识的延迟写。这个是os</span><span style="font-family:宋体;">的策略，当然也可以应用到程序的设计中。当然也会有缺点：1.</span><span style="font-family:宋体;">如果硬件错误或掉电，则会丢失内容（做额外的备份）2.</span><span style="font-family:宋体;">需要额外的内存空间。（牺牲内存来提高IO</span><span style="font-family:宋体;">的效率）</span></p>  <p style="margin-left:21.0pt">&nbsp;</p>  <p style="margin-left:21.0pt"><span style="font-family:宋体;">我们还需根据系统的IO</span><span style="font-family:宋体;">调度器的调度策略，设计出不同的IO</span><span style="font-family:宋体;">策略。尽量降低磁盘的平均访问时间，降低请求队列，提高数据传输的速率。</span></p>  <p>&nbsp;</p>  <p>&nbsp;</p>  <p>&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:-21.0pt;"><span><span>五．</span><span style="font-family:宋体;">监控硬盘的工具和指标</span></span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Iostat&#8211;x &#8211;k 1</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>&nbsp;-x</span><span style="font-family:宋体;">显示更多的消息&nbsp;-k</span><span style="font-family:宋体;">数据以KB</span><span style="font-family:宋体;">为单位 1</span><span style="font-family:宋体;">每秒显示一次</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">输出显示的信息</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Iowait</span><span style="font-family:宋体;">：cpu</span><span style="font-family:宋体;">等待未完成的IO</span><span style="font-family:宋体;">请求而空闲的时间的比例。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Idle</span><span style="font-family:宋体;">：cpu</span><span style="font-family:宋体;">空闲且无IO</span><span style="font-family:宋体;">请求的比例。</span></p>  <p style="margin-left:31.5pt; text-indent:-10.5pt;"><span>rrqm/s</span><span style="font-family:宋体;">：每秒这个设备相关的读取请求有多少被Merge</span><span style="font-family:宋体;">了。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>wrqm/s</span><span style="font-family:宋体;">：每秒这个设备相关的写入请求有多少被Merge</span><span style="font-family:宋体;">了。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>rsec/s</span><span style="font-family:宋体;">：每秒读取的扇区数；</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>wsec/</span><span style="font-family:宋体;">：每秒写入的扇区数。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>r/s</span><span style="font-family:宋体;">：每秒完成的读 I/O </span><span style="font-family:宋体;">设备次数。即<span> delta(rio)/s</span></span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>w/s</span><span style="font-family:宋体;">：每秒完成的写 I/O </span><span style="font-family:宋体;">设备次数。即<span> delta(wio)/s</span></span></p>  <p style="margin-left:31.5pt; text-indent:-10.5pt;"><span>await</span><span style="font-family:宋体;">：每一个IO</span><span style="font-family:宋体;">请求的处理的平均时间（单位是毫秒）。包括加入请求队列和服务的时间。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>svctm:&nbsp;&nbsp; </span><span style="font-family:宋体;">平均每次设备I/O</span><span style="font-family:宋体;">操作的服务时间。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>avgrq-sz: </span><span style="font-family:宋体;">平均每次设备I/O</span><span style="font-family:宋体;">操作的数据大小 (</span><span style="font-family:宋体;">扇区)</span><span style="font-family:宋体;">。即<span> delta(rsect+wsect)/delta(rio+wio)<br /> avgqu-sz: </span></span><span style="font-family:宋体;">平均I/O</span><span style="font-family:宋体;">队列长度。即 delta(aveq)/s/1000 (</span><span style="font-family:宋体;">因为aveq</span><span><span style="font-family:宋体;color:#333333">的单位为毫秒</span></span><span><span style="font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#333333">)</span></span><span><span style="font-family:宋体;color:#333333">。</span></span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>%util</span><span style="font-family:宋体;">：在统计时间内所有处理IO</span><span style="font-family:宋体;">时间，除以总共统计时间。例如，如果统计间隔1</span><span style="font-family:宋体;">秒，该设备有0.8</span><span style="font-family:宋体;">秒在处理IO</span><span style="font-family:宋体;">，而0.2</span><span style="font-family:宋体;">秒闲置，那么该设备的%util = 0.8/1 = 80%</span><span style="font-family:宋体;">，所以该参数暗示了设备的繁忙程度。一般地，如果该参数是100%</span><span style="font-family:宋体;">表示设备已经接近满负荷运行了（当然如果是多磁盘，即使%util</span><span style="font-family:宋体;">是100%</span><span style="font-family:宋体;">，因为磁盘的并发能力，所以磁盘使用未必就到了瓶颈）。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">下面我们做一个实验来分析一下</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">我们使用命令</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span><span>time dd if=/dev/zero of=/home/zhouyuan/mytest bs=1M count=3000</span></span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">向mytest</span><span style="font-family:宋体;">写入数据，写入3G</span><span style="font-family:宋体;">。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">截取部分的状态监控：</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/24.jpg" width="992" height="354" alt="" /><br /></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/25.jpg" width="692" height="361" alt="" /><br /></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/26.jpg" width="668" height="357" alt="" /><br /></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">如图2</span><span style="font-family:宋体;">，当两条数据<span> iowait </span></span><span><span style="font-family: 宋体;">达到了</span> 99% </span><span style="font-family:宋体;">以上，写入的数据是0</span><span style="font-family:宋体;">，这是因为DMA</span><span style="font-family:宋体;">将内存的中的数据传输给设备。结合图1</span><span style="font-family:宋体;">的前两条数据，利用率达到了99%+</span><span style="font-family:宋体;">却没有写入的磁盘块。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">如图3</span><span style="font-family:宋体;">，iowait</span><span style="font-family:宋体;">下降，说明cpu</span><span style="font-family:宋体;">开始执行相关程序，而此时块设备开始写入的数据。这两个操作是异步进行的。</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;">&nbsp;</p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Vmstat&#8211;k &#8211;n 1</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>Swap</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">　　si: </span><span style="font-family:宋体;">从磁盘交换到内存的交换页数量，单位：KB/</span><span style="font-family:宋体;">秒</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">　　so: </span><span style="font-family:宋体;">从内存交换到磁盘的交换页数量，单位：KB/</span><span style="font-family:宋体;">秒</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span>IO</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">　　bi: 从</span><span style="font-family:宋体;">块设备接受的块数，单位：块/</span><span style="font-family:宋体;">秒</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><span style="font-family:宋体;">　　bo: </span><span style="font-family:宋体;">发送到块设备的块数，单位：块/</span><span style="font-family:宋体;">秒</span></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/27.jpg" width="748" height="31" alt="" /><br /></p>  <p style="margin-left:21.0pt;text-indent:0cm;"><img src="http://www.cppblog.com/images/cppblog_com/range/28.jpg" width="736" height="461" alt="" /><br /></p>  <p style="margin-left: 21pt; text-indent: 0cm; "><span style="font-family: 宋体; ">从图中我们可以看出系统的延迟写。</span></p></div><img src ="http://www.cppblog.com/range/aggbug/154449.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2011-08-26 20:04 <a href="http://www.cppblog.com/range/archive/2011/08/26/154449.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>#pragma pack学习</title><link>http://www.cppblog.com/range/archive/2011/07/15/151094.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Fri, 15 Jul 2011 12:36:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2011/07/15/151094.html</guid><wfw:comment>http://www.cppblog.com/range/comments/151094.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2011/07/15/151094.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/151094.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/151094.html</trackback:ping><description><![CDATA[<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;&nbsp;<span style="font-family: 宋体">最近调试网络的服务端程序，自己写了一个小客户端程序来测试，发现服务程序解包错误。经调试发现客户端的协议头大小和服务器端的协议头大小不一致。原因是服务器端加了</span>#pragma pack(1),<span style="font-family: 宋体">而客户端没加。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 之前没接触过这个编译宏，现在来认真学习之。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 首先</span>google<span style="font-family: 宋体">之</span>~~</p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 原来</span>#pragma pack<span style="font-family: 宋体">有几种形式，我所接触到的是</span>#pragma pack(n)<span style="font-family: 宋体">，即变量以</span>n<span style="font-family: 宋体">字节对齐。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 变量对齐在每个系统中是不一样的，默认的对齐方式能有效的提高</span>cpu<span style="font-family: 宋体">取指取数的速度，但是可能会浪费一定的空间。在网络程序中采用</span>#pragma pack(1),<span style="font-family: 宋体">即变量紧缩，</span><span style="background-color: #ff6600; font-family: 宋体">不但可以减少网络流量，还可以兼容各种系统，不会因为系统对齐方式不同而导致解包错误。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 了解了概念和优点，现在我们就来测试之</span>~</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 平台：</span>CPU&#8212;Pentium E5700&nbsp;<span style="font-family: 宋体">内存</span>&#8212;2G</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;1.<span style="font-family: 宋体">操作系统：</span><span>ubuntu 11.04 32bit&nbsp;&nbsp;&nbsp;</span><span style="font-family: 宋体">编译器：</span>G++ 4.5.2</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;2.<span style="font-family: 宋体">操作系统：</span>windows xp<span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="font-family: 宋体">编译器：VS2010</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 先看第一个测试。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 结构体在正常情况和紧缩情况在以上不同环境下占用的内存大小。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><font class="Apple-style-span" size="3"></font></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 1074px; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><font class="Apple-style-span" size="3"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;pack&nbsp;{<br /></span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i;<br /></span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">short</span><span style="color: #000000">&nbsp;s;<br /></span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000">&nbsp;d;<br /></span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;c;<br /></span><span style="color: #008080">6</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">short</span><span style="color: #000000">&nbsp;f;<br /></span><span style="color: #008080">7</span>&nbsp;<span style="color: #000000">}</span></font></div>
<p style="text-indent: 0px; margin: 5px auto"></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp;&nbsp;<br />&nbsp; &nbsp;测试结果为：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; 1<span style="font-family: 宋体">：<br />&nbsp; &nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/12.jpg" width="400" height="52" /></span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; 2<span style="font-family: 宋体">：<br /></span>&nbsp; &nbsp;&nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/13.jpg" width="401" height="50" /><br /><span style="font-family: 宋体" class="Apple-style-span">&nbsp;&nbsp;</span><span style="font-family: 宋体" class="Apple-style-span"><br /></span><span style="font-family: 宋体" class="Apple-style-span">&nbsp; &nbsp; 测试结果分析：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 可以看出紧缩后结构体的大小为</span>15<span style="font-family: 宋体">，是结构体内置类型大小的和。但是在默认情况下，结构体的大小都是对齐字节数的倍数。</span>ubuntu<span style="font-family: 宋体">下</span>pack<span style="font-family: 宋体">只需要</span>20<span style="font-family: 宋体">个字节，而</span>windows<span style="font-family: 宋体">要</span>24<span style="font-family: 宋体">个字节。这是因为</span>ubuntu<span style="font-family: 宋体">是以</span>4<span style="font-family: 宋体">字节对齐，而</span>windows<span style="font-family: 宋体">则是以最大的内置类型的字节数对齐，在结构体内最大的内置类型为</span>double<span style="font-family: 宋体">，其大小为</span>8<span style="font-family: 宋体">个字节。他们在内存中的对齐方式如下图：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; 1<span style="font-family: 宋体">：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp;&nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/3.jpg" width="691" height="244" /></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; 2<span style="font-family: 宋体">：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp;&nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/4.jpg" width="681" height="281" /></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp;还需注意的是，</span><span style="background-color: #ff6600; font-family: 宋体">在对齐类型的内部都是以</span><span style="background-color: #ff6600">2</span><span style="background-color: #ff6600; font-family: 宋体">字节对齐的。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp;结论：</span><span style="background-color: #ff6600; font-family: 宋体">在默认情况下，</span><span style="background-color: #ff6600">linux</span><span style="background-color: #ff6600; font-family: 宋体">操作系统是以</span><span style="background-color: #ff6600">4</span><span style="background-color: #ff6600; font-family: 宋体">字节对齐，</span><span style="background-color: #ff6600">windows</span><span style="background-color: #ff6600; font-family: 宋体">操作系统则是以最大的内置类型对齐。</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp;第二个测试</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp;一个结构体内包含另外一个结构体，其大小的情况。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp;内部的结构体为</span></p>
<p style="text-align: left; text-indent: 0px; margin: 5px auto" align="left"><font class="Apple-style-span" size="3"></font></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 1074px; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><font class="Apple-style-span" size="3"><span style="color: #008080">1</span>&nbsp;<span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;pack&nbsp;{<br /></span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">short</span><span style="color: #000000">&nbsp;s;<br /></span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000">&nbsp;d;<br /></span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000">}</span></font></div>
<p style="text-indent: 0px; margin: 5px auto"></p>
<p style="text-align: left; text-indent: 0px; margin: 5px auto" align="left"><span style="font-family: 宋体">&nbsp; &nbsp;外部的结构体为</span></p>
<p style="text-align: left; text-indent: 12pt; margin: 5px auto" align="left"><span style="font-size: 12pt">&nbsp; &nbsp;</span><span style="font-size: 13px" class="Apple-style-span"><span style="color: #008080">1</span></span><span style="font-size: 13px" class="Apple-style-span">&nbsp;</span><span style="font-size: 13px" class="Apple-style-span"><span style="color: #0000ff">struct</span></span><span style="font-size: 13px" class="Apple-style-span"><span style="color: #000000">&nbsp;complex&nbsp;_pack{</span></span></p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 1074px; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;c;<br /></span><span style="color: #008080">3</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;pack&nbsp;s;<br /></span><span style="color: #008080">4</span>&nbsp;<span style="color: #000000">&nbsp;&nbsp;</span><span style="color: #0000ff">double</span><span style="color: #000000">&nbsp;d;<br /></span><span style="color: #008080">5</span>&nbsp;<span style="color: #000000">};</span></div>
<p style="text-align: left; text-indent: 0px; margin: 5px auto" align="left"><span style="font-family: 宋体; font-size: 12pt">&nbsp; &nbsp; 我们有四种情况：</span></p>
<p style="text-align: left; text-indent: -18pt; margin: 5px auto 5px 18pt" align="left"><span style="font-size: 12pt"><span>&nbsp; &nbsp; &nbsp;1.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-size: 12pt">pack</span><span style="font-family: 宋体; font-size: 12pt">紧缩，</span><span style="font-size: 12pt">complex _pack</span><span style="font-family: 宋体; font-size: 12pt">紧缩</span></p>
<p style="text-align: left; text-indent: -18pt; margin: 5px auto 5px 18pt" align="left"><span style="font-size: 12pt"><span>&nbsp; &nbsp; &nbsp;2.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-size: 12pt">pack</span><span style="font-family: 宋体; font-size: 12pt">紧缩，</span><span style="font-size: 12pt">complex _pack</span><span style="font-family: 宋体; font-size: 12pt">默认</span></p>
<p style="text-align: left; text-indent: -18pt; margin: 5px auto 5px 18pt" align="left"><span style="font-size: 12pt"><span>&nbsp; &nbsp; &nbsp;3.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-size: 12pt">pack</span><span style="font-family: 宋体; font-size: 12pt">默认，</span><span style="font-size: 12pt">complex _pack</span><span style="font-family: 宋体; font-size: 12pt">紧缩</span></p>
<p style="text-align: left; text-indent: -18pt; margin: 5px auto 5px 18pt" align="left"><span style="font-size: 12pt"><span>&nbsp; &nbsp; &nbsp;4.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="font-size: 12pt">pack</span><span style="font-family: 宋体; font-size: 12pt">默认，</span><span style="font-size: 12pt">complex _pack</span><span style="font-family: 宋体; font-size: 12pt">默认</span></p>
<p style="text-align: left; text-indent: 0px; margin: 5px auto" align="left"><span style="font-family: 宋体; font-size: 12pt">&nbsp; &nbsp; 以下的排列均按此顺序。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; &nbsp;测试的结果</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp; 1<span style="font-family: 宋体">：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;&nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/6.jpg" width="430" height="307" /></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;2<span style="font-family: 宋体">：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;&nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/5.jpg" width="432" height="294" /></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 测试结果分析：</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 在两个操作系统下，除了第一种情况</span>----<span style="font-family: 宋体">内结构体和外结构体都紧缩</span>----<span style="font-family: 宋体">相同之外，其他三种情况都不相同。我们可以根据偏移画出结构体在内存中的情况。第一种情况省略。</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;1<span style="font-family: 宋体">：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/7.jpg" width="400" height="456" /></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;2<span style="font-family: 宋体">：</span></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp;<img alt="" src="http://www.cppblog.com/images/cppblog_com/range/8.jpg" width="368" height="555" /></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 结论：</span>#pragma pack<span style="font-family: 宋体">只影响当前结构体的变量的对齐情况，并不会影响结构体内部的结构体变量的排列情况。或者说</span><span style="background-color: #ff6600">#pragma pack</span><span style="background-color: #ff6600; font-family: 宋体">的作用域只是一层</span><span style="font-family: 宋体">。我们由第三种情况，内部结构体正常，外部结构体紧缩，可以得出结构体的对齐是按偏移计算的。</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="font-family: 宋体">&nbsp; &nbsp; 这里还有一个问题没解决，为什么第二种情况内部结构体的偏移都是</span>1?不是4或者8？</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p><img src ="http://www.cppblog.com/range/aggbug/151094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2011-07-15 20:36 <a href="http://www.cppblog.com/range/archive/2011/07/15/151094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NAT学习</title><link>http://www.cppblog.com/range/archive/2011/07/15/151093.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Fri, 15 Jul 2011 12:35:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2011/07/15/151093.html</guid><wfw:comment>http://www.cppblog.com/range/comments/151093.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2011/07/15/151093.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/151093.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/151093.html</trackback:ping><description><![CDATA[<p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; text-indent: 0px; ">&nbsp; &nbsp; &nbsp; The IP Network Address Translator<span style="font-family: 宋体; ">，</span>IP<span style="font-family: 宋体; ">网络地址转换是人们说的</span>NAT<span style="font-family: 宋体; ">，或者说</span>NA(P)T<span style="font-family: 宋体; ">。</span>NAT<span style="font-family: 宋体; ">是为了解决</span>IPv4<span style="font-family: 宋体; ">地址不足而提出来得一种替代方案，可以对外界屏蔽内部的网络拓扑。随着网络的发展，</span>NAT<span style="font-family: 宋体; ">阻碍了构建在覆盖网络的</span>P2P<span style="font-family: 宋体; ">程序的发展。因为覆盖网络是构建在应用层，屏蔽了传输层以下的网络拓扑，网络中的每一个节点或某些节点有此网络的路由表，由这些路由表构建出这个覆盖网络，但是</span>NAT<span style="font-family: 宋体; ">阻碍的覆盖网络中节点的连接。<br />&nbsp; &nbsp;&nbsp;<br />&nbsp; &nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/range/9.jpg" width="541" height="337" alt="" /><br />&nbsp; &nbsp;<br />&nbsp; &nbsp;&nbsp;</span><span style="font-family: 宋体; ">上图显示了</span>NAT<span style="font-family: 宋体; ">的原理。</span>NAT<span style="font-family: 宋体; ">将内网的</span>IP<span style="font-family: 宋体; ">替换为公网</span>IP<span style="font-family: 宋体; ">，将端口映射为公网的端口。公网</span>IP<span style="font-family: 宋体; ">替换内网</span>IP<span style="font-family: 宋体; ">是固定的，</span>NAT<span style="font-family: 宋体; ">的不足之处在于端口的替换。因为</span>NAT<span style="font-family: 宋体; ">还没有形成标准，替换策略有几种，这也是</span>NAT<span style="font-family: 宋体; ">行为的关键。</span></p><div style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; text-indent: 0px; "><span style="font-family: 宋体; ">&nbsp; &nbsp; &nbsp;在《</span><span>Behavior and Classification of NAT Devices and Implications for NAT Traversal</span><span style="font-family: 宋体; ">》一文中就把端口映射的行为分成四种，其中包括保留端口，不保留端口，端口重载，端口复用。这四种分类最终区分了</span>NAT<span style="font-family: 宋体; ">的四种类型即</span>Full cone NAT<span style="font-family: 宋体; ">，</span>Symmetric NAT<span style="font-family: 宋体; ">，</span>Port-Restrictes cone NAT&nbsp;<span style="font-family: 宋体; ">，</span><span>Address-Restriced cone NAT</span><span style="font-family: 宋体; ">。</span></p><p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; text-indent: 0px; "><span style="font-family: 宋体; ">&nbsp; &nbsp; &nbsp;为了使覆盖网络中的节点相互通信，我们需要进行</span>NAT<span style="font-family: 宋体; ">穿越。在《</span>A NAT Traversal Mechanism for Peer-To-Peer Networks<span style="font-family: 宋体; ">》一文种介绍了根据两端不同的</span>NAT<span style="font-family: 宋体; ">类型对应的四种</span>NAT<span style="font-family: 宋体; ">穿越方案。如下图<br />&nbsp; &nbsp; &nbsp;<img src="http://www.cppblog.com/images/cppblog_com/range/10.jpg" width="539" height="170" alt="" /><br />&nbsp; &nbsp; &nbsp;</span></p><div style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; display: inline-block; "><div style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><span style="font-size: 10.5pt; font-family: 宋体; ">&nbsp; &nbsp; 这些解决方案都需要</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Calibri, sans-serif; ">STUN</span><span class="apple-style-span"><span style="font-size: 10.5pt; font-family: 宋体; color: black; ">（</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Arial, sans-serif; color: black; ">Simple Traversal of User Datagram Protocol through Network Address Translators (NATs)</span><span style="font-size: 10.5pt; font-family: 宋体; color: black; ">，</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Arial, sans-serif; color: black; ">NAT</span><span style="font-size: 10.5pt; font-family: 宋体; color: black; ">的</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Arial, sans-serif; color: black; ">UDP</span><span style="font-size: 10.5pt; font-family: 宋体; color: black; ">简单穿越）</span></span><span style="font-size: 10.5pt; font-family: 宋体; ">协议帮助。STUN协议要求一台具有公网</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Calibri, sans-serif; ">IP</span><span style="font-size: 10.5pt; font-family: 宋体; ">的主机帮助一台主机进行</span><span lang="EN-US" style="font-size: 10.5pt; font-family: Calibri, sans-serif; ">NAT</span><span style="font-size: 10.5pt; font-family: 宋体; ">类型的判断。<br />&nbsp; &nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/range/11.jpg" width="684" height="647" alt="" /></span></div></div><br />&nbsp; &nbsp; &nbsp;&nbsp;<span style="font-family: 宋体; ">上图是</span>STUN<span style="font-family: 宋体; ">协议的流程，其主要的思想是通过</span>STUN<span style="font-family: 宋体; ">的回射来判断主机的</span>NAT<span style="font-family: 宋体; ">类型。</span><div style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; text-indent: 0px; "><span style="font-family: 宋体; ">&nbsp; &nbsp; &nbsp;除了直接连接，反向连接、打洞和依赖都需要第三台主机的帮助。</span></p><p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; text-indent: 0px; "><span style="font-family: 宋体; ">&nbsp; &nbsp; &nbsp;在《</span>Characterization and Measurement of TCP Traversal through NATs and Firewalls<span style="font-family: 宋体; ">》一文中介绍了</span>TCP<span style="font-family: 宋体; ">穿越的方法。在</span>STUNT#2<span style="font-family: 宋体; ">方法中，第三台主机和两台需要连接的主机都有长连接，当一方需要发起来连接时，向第三台主机发请求，第三台主机向被请求的主机发送邀请，此时需要连接的主机都向对方发送</span>SYN<span style="font-family: 宋体; ">包，此时双方的防火墙都有了洞，只要有一方的</span>SYN<span style="font-family: 宋体; ">包到达对方主机，连接就会被建立。</span>Relay<span style="font-family: 宋体; ">方法需要耗费的代价太大，在</span>P2P<span style="font-family: 宋体; ">应用中一般会消极的处理双方都是对称</span>NAT<span style="font-family: 宋体; ">的情况。</span></p></div><br /><br /><br /><br /><br /><p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; text-indent: 0px; ">&nbsp;</p></div><img src ="http://www.cppblog.com/range/aggbug/151093.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2011-07-15 20:35 <a href="http://www.cppblog.com/range/archive/2011/07/15/151093.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Initialization</title><link>http://www.cppblog.com/range/archive/2011/07/15/151092.html</link><dc:creator>Range</dc:creator><author>Range</author><pubDate>Fri, 15 Jul 2011 12:31:00 GMT</pubDate><guid>http://www.cppblog.com/range/archive/2011/07/15/151092.html</guid><wfw:comment>http://www.cppblog.com/range/comments/151092.html</wfw:comment><comments>http://www.cppblog.com/range/archive/2011/07/15/151092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/range/comments/commentRss/151092.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/range/services/trackbacks/151092.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; &nbsp;<span style="font-size: 18pt; ">Hello World！</span><img src ="http://www.cppblog.com/range/aggbug/151092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/range/" target="_blank">Range</a> 2011-07-15 20:31 <a href="http://www.cppblog.com/range/archive/2011/07/15/151092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>