??xml version="1.0" encoding="utf-8" standalone="yes"?>一本一本久久a久久精品综合麻豆,人人狠狠综合久久88成人,久久人人爽人人爽人人av东京热 http://www.shnenglu.com/Bugs/MMORPG game develop.zh-cnTue, 06 May 2025 20:17:50 GMTTue, 06 May 2025 20:17:50 GMT60我自qblogQ?/title><link>http://www.shnenglu.com/Bugs/archive/2008/11/11/66614.html</link><dc:creator>Bugs</dc:creator><author>Bugs</author><pubDate>Tue, 11 Nov 2008 08:15:00 GMT</pubDate><guid>http://www.shnenglu.com/Bugs/archive/2008/11/11/66614.html</guid><wfw:comment>http://www.shnenglu.com/Bugs/comments/66614.html</wfw:comment><comments>http://www.shnenglu.com/Bugs/archive/2008/11/11/66614.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/Bugs/comments/commentRss/66614.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Bugs/services/trackbacks/66614.html</trackback:ping><description><![CDATA[Ƣ迎大家光我自qBlogQhttp://iBugs.net <img src ="http://www.shnenglu.com/Bugs/aggbug/66614.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Bugs/" target="_blank">Bugs</a> 2008-11-11 16:15 <a href="http://www.shnenglu.com/Bugs/archive/2008/11/11/66614.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SCTP vs. TCPhttp://www.shnenglu.com/Bugs/archive/2008/06/26/54651.htmlBugsBugsThu, 26 Jun 2008 03:28:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/06/26/54651.htmlhttp://www.shnenglu.com/Bugs/comments/54651.htmlhttp://www.shnenglu.com/Bugs/archive/2008/06/26/54651.html#Feedback0http://www.shnenglu.com/Bugs/comments/commentRss/54651.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/54651.html 

1 控制传输协议(SCTPQ发展简?/p>


  随着IP|向多业务网发展Q尤其是目前IP电话、IP视频会议{业务的发展Q在IP|中传送信令信息成为必然。目前IP|中信o消息的交换通常是用TCP或UDP完成Q但是这两个协议都不能满电信运营网中信令承载的要求?/p>


  为适应IP|成为电信运营核心网的发展趋势,IETF 的信令传输工作组QSIGTRANQ一直在研究和制定IP|新一代的传输协议Qƈ在IETF RFC 2960中定义了控制传输协议(SCTPQStream Control Transmission ProtocolQ。SCTP是面向连接的可靠传送协议,它向上层应用提供了下列服务:


  · 应用数据的无错误无重复的可靠传输Q?/p>


  · Ҏ到的MTU长度q行数据包分D处理,避免IP层的分段Q?/p>


  · 在多个流间的用户消息有序递交Q及单用h息按到达序递交的选项Q?/p>


  · 通过支持兌的多宿主机特性,实现|络U容错?/p>


  SCTP是ؓ传输信o业务而制定的Q它本n所h的、优于TCP的一些先q协议机Ӟ如选择性重传、无序递交和支持多U网l特性等Q得SCTP能够在一定程度上满高性能传输的需求。而且QSCTP采用了类同TCP的流量控制机Ӟ不存在类似基于UDP的实时媒体流对TCP性能造成的劣化干扰问题和公^性问题。因此,SCTP有可能取代TCPQ成Z一代IP|上面向q接的可靠传送层协议?/p>


2 TCP的不?/p>


  TCP是目前Internet上应用最q泛的面向连接的传送层协议Q它为通信的两端提供了可靠的数据传输,而且提供了流量控制和拥塞控制功能。由于原来IP|提供的?#8220;力而ؓQbest-effortQ?#8221;的服务,因此TCP存在许多不之处Q?/p>


  · TCP是面向字节流的。这意味着消息的描q必ȝ应用来完成,而且要在消息l束时显C通知TCP以迫使其立即发送相应的数据?/p>


  · 许多应用只需要信令信息的部分有序Q例如属于同一呼叫或同一会话的消息就是这栗而TCP只提供严格的数据按序传输Q这会导致不必要的队头拥塞ƈ使消息的传输时g增大?/p>


  · TCPq接直接׃对传送层地址QIP地址和端口号Q识别,无法提供对多宿主机的透明支持?/p>


  · 典型的TCP实现不允讔R层应用设定协议控制参数。但是一些应用可能会需要调节传送层协议的属性以满其要求,例如某些应用有较高的时g要求Q而另一些则只要求较高的可靠性?/p>


3 q接与关?/p>


  TCP中的q接是指两个TCP端点通过“三次握手”q程建立的由一对传送层地址QIP地址和端口号Q识别的传送通道?/p>


  在SCTP? TCP中的q接被引申ؓ兌(associ-
ationQ。一个关联的两个SCTP端点都向Ҏ提供一个SCTP端口号和一个IP地址列表Q这h个关联都׃个SCTP端口号和两个IP地址列表来识别。在一个关联内的拥塞控制机制与TCPq接的拥塞控制机制类伹{?/p>


  一个关联是由多个单向的组成的。各个流之间相对独立Q可以单独发送数据而不受其他流的媄响,也可以共同实现用h据的有序递交。流的徏立和拆除q程相对独立、简单。而关联的建立q程相对而言比较复杂,是个“四次握手”q程Q而且其中要用?#8220;cookie”的概c所?#8220;cookie”实际是一个含有端点初始信息和加密信息的数据块Q它在关联徏立时被通信的两端处理ƈ交换?/p>


4 SCTP的多宿主机特性及应用


  SCTP支持传送层的多宿主机服务。当|络发生故障Ӟ多宿L服务可以增强|络的健壮性(robustnessQ。在某些应用场合Q这个特性非帔R要。SCTP对多宿主机服务的支持要求兌的一端或两端在不同的|络接口上分配有多个IP地址?/p>


  一般来_要在通信的两端实现真正的故障Ҏ恢复,每个端点都需要有一个以上的IP|络接口Q以支持多宿L服务。在q种情况下,路径使用的数量就是所有端点的|络接口的最数Q此时端点要正确选择自己的源地址才能获得最佌\径。但是,如果端点L使用同一个源地址Q那么端点就同样会出现单Ҏ障。因为当端点选择一个源地址Ӟ它L选择数据包的源地址来对应网l接口的IP地址Q而在|络接口上数据包受到绑定地址的限制。换句话_׃l定地址的限Ӟ端点永远都不能选择不属于该SCTP兌的源地址Q同时对端端点也必须认可该SCTP兌使用的Q何一个源地址?/p>


  当端点在一个多宿主ZӞ如果兌的两端绑定有多个地址QSCTP兌的可用性将大大增强。利用多宿主个特性可以在两个SCTP端点间徏立冗余的路径Q这寚w些一直寻求在|络的传送层ơ就能提供容错机制的应用特别有用。要在SCTP的两个端炚w建立冗余路径Q要求两个端点的讑֤都必L多个接口Qƈ分配多个地址Q而且必须配置好\由?/p>


  因此Q通过“多宿L”Ҏ,SCTP提供了较TCP强大得多的\径状态监控功能。SCTP可以监测q端地址的可达性,当远端地址不可达时Q它能通过使用备用地址替换ȝ地址实现故障的自动恢复,而且q一q程不需要上层协议的q预。也是_“多宿L”Ҏ可以一个关联可以在多个传输路径间选择和切换,从而提高了|络U容错的能力?/p>


5 TCP与SCTP的安全比?/p>


  1. TCP的安全问?/p>


  一些TCP应用被公认会受到DoSd。例如,d者可以通过发送大量的q接建立hQTCP-SYN数据包)来攻ȝ的地Q有可能来自伪装的IP地址。被dL不停地发送SYN-ACK数据包来回复Qƈq入SYN-received状态,甚至SYN队列被挤满Q例如,{待建立的连接数会达C个极限)Q而且它将拒绝新的q接建立h?/p>


  另外Q伪装连接是对TCP的另一个潜在威胁。通过猜测有效的序列号Q攻击者将可能伪装成一个合法连接。但是,通过使用一个安全的Hashsum法Q对目前SYN-cookieq行伪装的攻ȝ可能性只?/224。例如当使用SYS-cookieӞ要成功作Z个伪装的q接Ӟd者将不得不发?24个数据包?/p>


  2. SCTP的安全机?/p>


  SCTP在设计时充分考虑了TCP的不뀂ؓ防止d者发送伪装的SCTP数据包到现有的连接中QSCTP的两端都使用一个称?#8220;认证标记”?2bit数据来确保数据包真正属于现有的连接。因此,除了合ƈ属于一个连接的源端口和目的端口的地址外,一个有效的SCTP数据包还必须有一个正的标记?/p>


  跟TCP不同的是QSCTP要求在连接徏立时必须使用“cookie”。对服务器来_必须交换3个信息包QINIT、INIT-ACK、COOKIE-ECHOQ,才能建立一个完整的新连接?#8220;cookie”是个长度可变的,包含所有和在服务器端初始化TCB的相x据,加上使用HMAC来确保它的安全。HMAC是在cookie中用来计的Q是一个保密、服务器所拥有的key。引入这U机制的目的在于增强协议的安全性,防止DoSd和伪装等潜在的攻凅R?/p>


  同用SYN-cookie的TCP相比较,SCTP被攻击者伪装的可能性大大降低。因为,d者不得不ȝ包含在cookie中的HMAC倹{可能性小?128?/p>


  值得注意的是QSCTP仅仅试图来增强网l的可用性,它没有包含Q何直接和用户信息认证、完整性和保密功能的协议机Ӟ因ؓq些Ҏ主要取决于IPSec协议和应用层协议的安全特性?/p>


6 SCTP与TCP的功能及应用比较


  ׃SCTP也是一个面向连接的协议Q可提供所有TCP能够提供的传送层服务。因此,现有的许多Internet应用面临选择使用TCP或SCTPQ来满他们对传送层服务的需求。需要注意的是,对处理成本比较敏感的应用Q在使用SCTP或TCP得到的服务是不一LQSCTP可以为应用提供一个单独定制的传输,而TCP为应用提供的是一对地址?/p>


  当然QSCTPq具有一些TCP所不具备的功能Q这P在某些应用场合,选择SCTP实现传送层服务是更好的选择。SCTP在一个连接中可以支持多个独立用户信息的发送。正用该功能Q可以有效减所谓的“head-of-line-blocking”问题带来的媄响,在TCP中出现该问题Q主要是因ؓ数据包的发送有严格的顺序控制。因此,寚w些需要在一个连接中同时支持多个逻辑上独立的信息传送的应用QSCTPq别有用?br>  SCTP保留有应用信息的边界。当应用数据不是q箋的字节流Q而是要接收端单独处理大块的数据包Ӟ该功能就非常有用。相反,TCP在提供可靠数据流传送的同时Qƈ不能指出应用中包含的大块数据包?/p>


  SCTP支持没有指明应用cd的用户信息的传送,而且能够保证数据的可靠传送。对那些需要发送没有顺序的可靠信息的应用Q或者喜Ƣ用自w的信息排序机制的应用,SCTP的这个功能就特别有用?br>



Bugs 2008-06-26 11:28 发表评论
]]>
Linux下设|Shell的颜Ԍhttp://www.shnenglu.com/Bugs/archive/2008/06/24/54442.htmlBugsBugsTue, 24 Jun 2008 03:06:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/06/24/54442.htmlhttp://www.shnenglu.com/Bugs/comments/54442.htmlhttp://www.shnenglu.com/Bugs/archive/2008/06/24/54442.html#Feedback4http://www.shnenglu.com/Bugs/comments/commentRss/54442.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/54442.html  首先使用一个例子来说明如何实现Shell彩色Q?br>    PS1="\[ \033[0;32;40m\u@\h:\w\$ \033[0m \]"


   在上面命令中Q?#8220;\033[0;32;40m”表示定义后面文本的颜Ԍ“\033”表示启动一个{义序列,“[”定义开始颜色定义,“0”定义默认的字体颜Ԍ其它部分E后定义?br>    “32”定义文本的前景色Q这?2表示l色Q?#8220;40”定义文本的背景色Q?0表示黑色?br>    在字W串的最后定义了“ \033[0m”Q它是用来恢复了默认的文本颜色设|,q样只会得C个彩色提C符Q而不会媄响命令和其输出的颜色昄Q即黑底白字Q?

    我们一共有8U字体颜色可供选择Q它们分别是30 (黑色)?1 (U色)?2 (l色)?3 (黄色)?4 (蓝色)?5 ( 紫红??6 (青色)?7 (白色)?br>    对于底色也有8U颜色可供选择Q只需要将字体颜色?修改?卛_Q例?0?1?2?3?4?5?6?7?nbsp;

    文本属?

    我们前面提到Q{义序列符后面?#8220;0”表示定义文本的颜色设|?br>    除了颜色讄以外Q还可以讄文本的其它属性?br>    转义序列W后可以跟以下数|0??2??4??5??7Q分别定义颜艌Ӏ黑体、非黑体、下ȝ、非下画Uѝ闪烁、非闪烁、翻转、非{?br>



Bugs 2008-06-24 11:06 发表评论
]]>
EpollW记Q?/title><link>http://www.shnenglu.com/Bugs/archive/2008/06/23/54350.html</link><dc:creator>Bugs</dc:creator><author>Bugs</author><pubDate>Mon, 23 Jun 2008 02:17:00 GMT</pubDate><guid>http://www.shnenglu.com/Bugs/archive/2008/06/23/54350.html</guid><wfw:comment>http://www.shnenglu.com/Bugs/comments/54350.html</wfw:comment><comments>http://www.shnenglu.com/Bugs/archive/2008/06/23/54350.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.shnenglu.com/Bugs/comments/commentRss/54350.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Bugs/services/trackbacks/54350.html</trackback:ping><description><![CDATA[epoll的接口非常简单,一共就三个函数Q?br><span style="COLOR: rgb(255,1,2)">1. int epoll_create(int size);</span><br>创徏一个epoll的句柄,size用来告诉内核q个监听的数目一共有多大。这个参C同于select()中的W一个参敎ͼl出最大监听的fd+1的倹{需要注意的是,当创建好epoll句柄后,它就是会占用一个fd|在linux下如果查?proc/q程id/fd/Q是能够看到q个fd的,所以在使用完epoll后,必须调用close()关闭Q否则可能导致fd被耗尽?br><br><br><span style="COLOR: rgb(255,1,2)">2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);</span><br>epoll的事件注册函敎ͼ它不同与select()是在监听事g时告诉内核要监听什么类型的事gQ而是在这里先注册要监听的事gcd。第一个参数是epoll_create()的返回|W二个参数表C动作,用三个宏来表C:<br>EPOLL_CTL_ADDQ注册新的fd到epfd中;<br>EPOLL_CTL_MODQ修改已l注册的fd的监听事Ӟ<br>EPOLL_CTL_DELQ从epfd中删除一个fdQ?br>W三个参数是需要监听的fdQ第四个参数是告诉内栔R要监听什么事Qstruct epoll_eventl构如下Q?br>struct epoll_event {<br>  __uint32_t events;  /* Epoll events */<br>  epoll_data_t data;  /* User data variable */<br>};<br><br>events可以是以下几个宏的集合:<br>EPOLLIN Q表C对应的文g描述W可以读Q包括对端SOCKET正常关闭Q;<br>EPOLLOUTQ表C对应的文g描述W可以写Q?br>EPOLLPRIQ表C对应的文g描述W有紧急的数据可读Q这里应该表C有带外数据到来Q;<br>EPOLLERRQ表C对应的文g描述W发生错误;<br>EPOLLHUPQ表C对应的文g描述W被挂断Q?br>EPOLLETQ?EPOLL设ؓ边缘触发(Edge Triggered)模式Q这是相对于水^触发(Level Triggered)来说的?br>EPOLLONESHOTQ只监听一ơ事Ӟ当监听完q次事g之后Q如果还需要l监听这个socket的话Q需要再ơ把q个socket加入到EPOLL队列?br><br><br><span style="COLOR: rgb(255,1,2)">3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);</span><br>{待事g的生,cM于select()调用。参数events用来从内核得C件的集合Qmaxevents告之内核q个events有多大,q个maxevents的g能大于创建epoll_create()时的sizeQ参数timeout是超时时_毫秒Q?会立卌回,-1不定Q也有说法说是永久阻塞)。该函数q回需要处理的事g数目Q如q回0表示已超时?br><br>EPOLL事g有两U模型:<br>Edge Triggered (ET)<br>Level Triggered (LT)<br><br>ET(edge-triggered)是高速工作方式,只支持no-block socket。在q种模式下,当描q符从未qA变ؓqAӞ内核通过epoll告诉你。然后它会假设你知道文g描述W已l就l,q且不会再ؓ那个文g描述W发送更多的qA通知Q直C做了某些操作D那个文g描述W不再ؓqA状态了(比如Q你在发送,接收或者接收请求,或者发送接收的数据于一定量时导致了一个EWOULDBLOCK 错误Q。但是请注意Q如果一直不对这个fd作IO操作(从而导致它再次变成未就l?Q内怸会发送更多的通知(only once),<span style="FONT-WEIGHT: bold; FONT-STYLE: italic">不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark认<br><br>另外Q当使用epoll的ET模型来工作时Q当产生了一个EPOLLIN事g后,<br><span style="COLOR: rgb(255,1,2)">L据的时候需要考虑的是当recv()q回的大如果等于请求的大小Q那么很有可能是~冲有数据未dQ也意味着该次事gq没有处理完Q所以还需要再ơ读?/span>Q?br>while(rs)<br>{<br>  buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);<br>  if(buflen < 0)<br>  {<br>    // ׃是非d的模?所以当errno为EAGAIN?表示当前~冲区已无数据可?br>    // 在这里就当作是该ơ事件已处理?<br>    if(errno == EAGAIN)<br>     break;<br>    else<br>     return;<br>   }<br>   else if(buflen == 0)<br>   {<br>     // q里表示对端的socket已正常关?<br>   }<br><span style="COLOR: rgb(255,1,2)">   if(buflen == sizeof(buf)</span><br style="COLOR: rgb(255,1,2)"><span style="COLOR: rgb(255,1,2)">     rs = 1;   // 需要再ơ读?/span><br>   else<br>     rs = 0;<br>}<br><br><br><span style="FONT-WEIGHT: bold; COLOR: rgb(255,1,2)">q有Q假如发送端量大于接收端的量(意思是epoll所在的E序L转发的socket要快),׃是非d的socket,那么send()函数虽然q回,但实际缓冲区的数据ƈ未真正发l接收端,q样不断的读和发Q当~冲区满后会产生EAGAIN错误(参考man send),同时,不理会这ơ请求发送的数据.所?需要封装socket_send()的函数用来处理这U情?该函C量数据写完再q回Q返?1表示出错。在socket_send()内部,当写~冲已满(send()q回-1,且errno为EAGAIN),那么会等待后再重?q种方式q不很完?在理Z可能会长旉的阻塞在socket_send()内部,但暂没有更好的办?</span><br><br>ssize_t socket_send(int sockfd, const char* buffer, size_t buflen)<br>{<br>  ssize_t tmp;<br>  size_t total = buflen;<br>  const char *p = buffer;<br><br>  while(1)<br>  {<br>    tmp = send(sockfd, p, total, 0);<br>    if(tmp < 0)<br>    {<br>      // 当send收到信号?可以l箋?但这里返?1.<br>      if(errno == EINTR)<br>        return -1;<br><br>      // 当socket是非d?如返回此错误,表示写缓冲队列已?<br>      // 在这里做延时后再重试.<br>      if(errno == EAGAIN)<br>      {<br>        usleep(1000);<br>        continue;<br>      }<br><br>      return -1;<br>    }<br><br>    if((size_t)tmp == total)<br>      return buflen;<br><br>    total -= tmp;<br>    p += tmp;<br>  }<br><br>  return tmp;<br>} </span> <img src ="http://www.shnenglu.com/Bugs/aggbug/54350.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Bugs/" target="_blank">Bugs</a> 2008-06-23 10:17 <a href="http://www.shnenglu.com/Bugs/archive/2008/06/23/54350.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【{载】用异?I/O 大大提高应用E序的性能http://www.shnenglu.com/Bugs/archive/2008/06/19/54038.htmlBugsBugsThu, 19 Jun 2008 09:53:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/06/19/54038.htmlhttp://www.shnenglu.com/Bugs/comments/54038.htmlhttp://www.shnenglu.com/Bugs/archive/2008/06/19/54038.html#Feedback0http://www.shnenglu.com/Bugs/comments/commentRss/54038.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/54038.htmlhttp://www.ibm.com/developerworks/cn/linux/l-async/

使用异步 I/O 大大提高应用E序的性能

学习何时以及如何使用 POSIX AIO API

developerWorks
文档选项
此作为电子邮件发?src="http://www.ibm.com/i/v14/icons/em.gif"

此作为电子邮件发?/font>


U别Q?中

M. Tim Jones (mtj@mtjones.com), N工程? Emulex

2006 q?9 ?28 ?/p>

Linux® 中最常用的输?输出QI/OQ模型是同步 I/O。在q个模型中,当请求发Z后,应用E序׃dQ直到请求满ؓ止。这是很好的一U解x案,因ؓ调用应用E序在等?I/O h完成时不需要用Q何中央处理单元(CPUQ。但是在某些情况中,I/O h可能需要与其他q程产生交叠。可UL操作pȝ接口QPOSIXQ异?I/OQAIOQ应用程序接口(APIQ就提供了这U功能。在本文中,我们对q个 API 概要q行介绍Qƈ来了解一下如何用它?/blockquote>

AIO ?

Linux 异步 I/O ?Linux 内核中提供的一个相当新的增强。它?2.6 版本内核的一个标准特性,但是我们?2.4 版本内核的补丁中也可以找到它。AIO 背后的基本思想是允许进E发起很?I/O 操作Q而不用阻塞或{待M操作完成。稍后或在接收到 I/O 操作完成的通知Ӟq程可以检?I/O 操作的结果?/p>

I/O 模型

在深入介l?AIO API 之前Q让我们先来探烦一?Linux 上可以用的不同 I/O 模型。这q不是一个详的介绍Q但是我们将试图介绍最常用的一些模型来解释它们与异?I/O 之间的区别。图 1 l出了同步和异步模型Q以及阻塞和非阻塞的模型?/p>
?1. 基本 Linux I/O 模型的简单矩?/strong>
基本 Linux I/O 模型的简单矩? src=

每个 I/O 模型都有自己的用模式,它们对于特定的应用程序都有自q优点。本节将要对其一一q行介绍?/p>

同步d I/O

I/O 密集型与 CPU 密集型进E的比较

I/O 密集型进E所执行?I/O 操作比执行的处理操作更多。CPU 密集型的q程所执行的处理操作比 I/O 操作更多。Linux 2.6 的调度器实际上更加偏?I/O 密集型的q程Q因为它们通常会发起一?I/O 操作Q然后进行阻塞,q就意味着其他工作都可以在两者之间有效地交错q行?/p>

最常用的一个模型是同步d I/O 模型。在q个模型中,用户I间的应用程序执行一个系l调用,q会D应用E序d。这意味着应用E序会一直阻塞,直到pȝ调用完成为止Q数据传输完成或发生错误Q。调用应用程序处于一U不再消?CPU 而只是简单等待响应的状态,因此从处理的角度来看Q这是非常有效的?/p>

?2 l出了传l的d I/O 模型Q这也是目前应用E序中最为常用的一U模型。其行ؓ非常Ҏ理解Q其用法对于典型的应用程序来说都非常有效。在调用 read pȝ调用Ӟ应用E序会阻塞ƈ对内核进行上下文切换。然后会触发L作,当响应返回时Q从我们正在从中d的设备中q回Q,数据pUd到用L间的~冲Z。然后应用程序就会解除阻塞(read 调用q回Q?/p>
?2. 同步d I/O 模型的典型流E?/strong>
同步d I/O 模型的典型流E? src=

从应用程序的角度来说Q?code>read 调用会gl很长时间。实际上Q在内核执行L作和其他工作Ӟ应用E序的确会被d?/p>

同步非阻?I/O

同步d I/O 的一U效率稍低的变种是同步非d I/O。在q种模型中,讑֤是以非阻塞的形式打开的。这意味着 I/O 操作不会立即完成Q?code>read 操作可能会返回一个错误代码,说明q个命o不能立即满Q?code>EAGAIN ?EWOULDBLOCKQ,如图 3 所C?/p>
?3. 同步非阻?I/O 模型的典型流E?/strong>
同步非阻?I/O 模型的典型流E? src=

非阻塞的实现?I/O 命o可能q不会立xI需要应用程序调用许多次来等待操作完成。这可能效率不高Q因为在很多情况下,当内核执行这个命令时Q应用程序必要q行忙碌{待Q直到数据可用ؓ止,或者试图执行其他工作。正如图 3 所C的一Pq个Ҏ可以引入 I/O 操作的gӞ因ؓ数据在内怸变ؓ可用到用戯?read q回数据之间存在一定的间隔Q这会导致整体数据吞吐量的降低?/p>

异步d I/O

另外一个阻塞解x案是带有d通知的非d I/O。在q种模型中,配置的是非阻?I/OQ然后用阻?select pȝ调用来确定一?I/O 描述W何时有操作。 select 调用非常有趣的是它可以用来ؓ多个描述W提供通知Q而不仅仅Z个描q符提供通知。对于每个提C符来说Q我们可以请求这个描q符可以写数据、有L据可用以及是否发生错误的通知?/p>
?4. 异步d I/O 模型的典型流E?(select)
异步d I/O 模型的典型流E? src=

select 调用的主要问题是它的效率不是非常高。尽这是异步通知使用的一U方便模型,但是对于高性能?I/O 操作来说不徏议用?/p>

异步非阻?I/OQAIOQ?

最后,异步非阻?I/O 模型是一U处理与 I/O 重叠q行的模型。读h会立卌回,说明 read h已经成功发v了。在后台完成L作时Q应用程序然后会执行其他处理操作。当 read 的响应到达时Q就会生一个信h执行一个基于线E的回调函数来完成这?I/O 处理q程?/p>
?5. 异步非阻?I/O 模型的典型流E?/strong>
异步非阻?I/O 模型的典型流E? src=

在一个进E中Z执行多个 I/O h而对计算操作?I/O 处理q行重叠处理的能力利用了处理速度?I/O 速度之间的差异。当一个或多个 I/O h挂vӞCPU 可以执行其他dQ或者更为常见的是,在发起其?I/O 的同时对已经完成?I/O q行操作?/p>

下一节将深入介绍q种模型Q探索这U模型用的 APIQ然后展C几个命令?/p>



回页?/font>


异步 I/O 的动?

从前?I/O 模型的分cMQ我们可以看?AIO 的动机。这U阻塞模型需要在 I/O 操作开始时d应用E序。这意味着不可能同旉叠进行处理和 I/O 操作。同步非d模型允许处理?I/O 操作重叠q行Q但是这需要应用程序根据重现的规则来检?I/O 操作的状态。这样就剩下异步非阻?I/O 了,它允许处理和 I/O 操作重叠q行Q包?I/O 操作完成的通知?/p>

除了需要阻塞之外,select 函数所提供的功能(异步d I/OQ与 AIO cM。不q,它是寚w知事gq行dQ而不是对 I/O 调用q行d?/p>



回页?/font>


Linux 上的 AIO ?

本节探?Linux 的异?I/O 模型Q从而帮助我们理解如何在应用E序中用这U技术?/p>

在传l的 I/O 模型中,有一个用惟一句柄标识?I/O 通道。在 UNIX® 中,q些句柄是文件描q符Q这对等同于文g、管道、套接字{等Q。在d I/O 中,我们发v了一ơ传输操作,当传输操作完成或发生错误Ӟpȝ调用׃q回?/p>
Linux 上的 AIO

AIO ?2.5 版本的内怸首次出现Q现在已l是 2.6 版本的品内核的一个标准特性了?/p>

在异步非d I/O 中,我们可以同时发v多个传输操作。这需要每个传输操作都有惟一的上下文Q这h们才能在它们完成时区分到底是哪个传输操作完成了。在 AIO 中,q是一?aiocbQAIO I/O Control BlockQ结构。这个结构包含了有关传输的所有信息,包括为数据准备的用户~冲区。在产生 I/O Q称为完成)通知Ӟaiocb l构p用来惟一标识所完成?I/O 操作。这?API 的展C显CZ如何使用它?/p>



回页?/font>


AIO API

AIO 接口?API 非常单,但是它ؓ数据传输提供了必需的功能,q给Z两个不同的通知模型。表 1 l出?AIO 的接口函敎ͼ本节E后会更详细q行介绍?/p>
?1. AIO 接口 API
API 函数 说明
aio_read h异步L?/td>
aio_error 查异步请求的状?/td>
aio_return 获得完成的异步请求的q回状?/td>
aio_write h异步写操?/td>
aio_suspend 挂v调用q程Q直C个或多个异步h已经完成Q或p|Q?/td>
aio_cancel 取消异步 I/O h
lio_listio 发v一pd I/O 操作

每个 API 函数都?aiocb l构开始或查。这个结构有很多元素Q但是清?1 仅仅l出了需要(或可以)使用的元素?/p>
清单 1. aiocb l构中相关的?
                        struct aiocb {
                        int aio_fildes;               // File Descriptor
                        int aio_lio_opcode;           // Valid only for lio_listio (r/w/nop)
                        volatile void *aio_buf;       // Data Buffer
                        size_t aio_nbytes;            // Number of Bytes in Data Buffer
                        struct sigevent aio_sigevent; // Notification Structure
                        /* Internal fields */
                        ...
                        };
                        

sigevent l构告诉 AIO ?I/O 操作完成时应该执行什么操作。我们将?AIO 的展CZ对这个结构进行探索。现在我们将展示各个 AIO ?API 函数是如何工作的Q以及我们应该如何用它们?/p>

aio_read

aio_read 函数h对一个有效的文g描述W进行异步读操作。这个文件描q符可以表示一个文件、套接字甚至道?code>aio_read 函数的原型如下:

int aio_read( struct aiocb *aiocbp );
                        

aio_read 函数在请求进行排队之后会立即q回。如果执行成功,q回值就?0Q如果出现错误,q回值就?-1Qƈ讄 errno 的倹{?/p>

要执行读操作Q应用程序必d aiocb l构q行初始化。下面这个简短的例子展CZ如何填充 aiocb hl构Qƈ使用 aio_read 来执行异步读hQ现在暂时忽略通知Q操作。它q展CZ aio_error 的用法,不过我们稍后再作解释?/p>
清单 2. 使用 aio_read q行异步L作的例子
                        #include <aio.h>
                        ...
                        int fd, ret;
                        struct aiocb my_aiocb;
                        fd = open( "file.txt", O_RDONLY );
                        if (fd < 0) perror("open");
                        /* Zero out the aiocb structure (recommended) */
                        bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
                        /* Allocate a data buffer for the aiocb request */
                        my_aiocb.aio_buf = malloc(BUFSIZE+1);
                        if (!my_aiocb.aio_buf) perror("malloc");
                        /* Initialize the necessary fields in the aiocb */
                        my_aiocb.aio_fildes = fd;
                        my_aiocb.aio_nbytes = BUFSIZE;
                        my_aiocb.aio_offset = 0;
                        ret = aio_read( &my_aiocb );
                        if (ret < 0) perror("aio_read");
                        while ( aio_error( &my_aiocb ) == EINPROGRESS ) ;
                        if ((ret = aio_return( &my_iocb )) > 0) {
                        /* got ret bytes on the read */
                        } else {
                        /* read failed, consult errno */
                        }
                        

在清?2 中,在打开要从中读取数据的文g之后Q我们就清空?aiocb l构Q然后分配一个数据缓冲区。ƈ对q个数据~冲区的引用攑ֈ aio_buf 中。然后,我们?aio_nbytes 初始化成~冲区的大小。ƈ?aio_offset 讄?0Q该文g中的W一个偏U量Q。我们将 aio_fildes 讄Z中读取数据的文g描述W。在讄q些域之后,p?aio_read hq行L作。我们然后可以调?aio_error 来确?aio_read 的状态。只要状态是 EINPROGRESSQ就一直忙等待,直到状态发生变化ؓ止。现在,h可能成功Q也可能p|?/p>
使用 AIO 接口来编译程?/strong>

我们可以?aio.h 头文件中扑ֈ函数原型和其他需要的W号。在~译使用q种接口的程序时Q我们必M?POSIX 实时扩展库(librtQ?/p>

注意使用q个 API 与标准的库函C文g中读取内Ҏ非常怼的。除?aio_read 的一些异步特性之外,另外一个区别是L作偏U量的设|。在传统?read 调用中,偏移量是在文件描q符上下文中q行l护的。对于每个读操作来说Q偏U量都需要进行更斎ͼq样后箋的读操作才能对下一块数据进行寻址。对于异?I/O 操作来说q是不可能的Q因为我们可以同时执行很多读hQ因此必Mؓ每个特定的读h都指定偏U量?/p>

aio_error

aio_error 函数被用来确定请求的状态。其原型如下Q?/p>
int aio_error( struct aiocb *aiocbp );
                        

q个函数可以q回以下内容Q?/p>

  • EINPROGRESSQ说明请求尚未完?
  • ECANCELLEDQ说明请求被应用E序取消?
  • -1Q说明发生了错误Q具体错误原因可以查?errno

aio_return

异步 I/O 和标准块 I/O 之间的另外一个区别是我们不能立即讉Kq个函数的返回状态,因ؓ我们q没有阻塞在 read 调用上。在标准?read 调用中,q回状态是在该函数q回时提供的。但是在异步 I/O 中,我们要?aio_return 函数。这个函数的原型如下Q?/p>
ssize_t aio_return( struct aiocb *aiocbp );
                        

只有?aio_error 调用定h已经完成Q可能成功,也可能发生了错误Q之后,才会调用q个函数?code>aio_return 的返回值就{h于同步情况中 read ?write pȝ调用的返回|所传输的字节数Q如果发生错误,q回值就?-1Q?/p>

aio_write

aio_write 函数用来h一个异步写操作。其函数原型如下Q?

int aio_write( struct aiocb *aiocbp );
                        

aio_write 函数会立卌回,说明h已经q行排队Q成功时q回gؓ 0Q失败时q回gؓ -1Qƈ相应地设|?errnoQ?/p>

q与 read pȝ调用cMQ但是有一点不一L行ؓ需要注意。回想一下对?read 调用来说Q要使用的偏U量是非帔R要的。然而,对于 write 来说Q这个偏U量只有在没有设|?O_APPEND 选项的文件上下文中才会非帔R要。如果设|了 O_APPENDQ那么这个偏U量׃被忽略,数据都会被附加到文g的末。否则,aio_offset 域就定了数据在要写入的文g中的偏移量?/p>

aio_suspend

我们可以使用 aio_suspend 函数来挂P或阻塞)调用q程Q直到异步请求完成ؓ止,此时会生一个信P或者发生其他超时操作。调用者提供了一?aiocb 引用列表Q其中Q何一个完成都会导?aio_suspend q回?aio_suspend 的函数原型如下:

int aio_suspend( const struct aiocb *const cblist[],
                        int n, const struct timespec *timeout );
                        

aio_suspend 的用非常简单。我们要提供一?aiocb 引用列表。如果Q何一个完成了Q这个调用就会返?0。否则就会返?-1Q说明发生了错误。请参看清单 3?/p>
清单 3. 使用 aio_suspend 函数d异步 I/O
                        struct aioct *cblist[MAX_LIST]
                        /* Clear the list. */
                        bzero( (char *)cblist, sizeof(cblist) );
                        /* Load one or more references into the list */
                        cblist[0] = &my_aiocb;
                        ret = aio_read( &my_aiocb );
                        ret = aio_suspend( cblist, MAX_LIST, NULL );
                        

注意Q?code>aio_suspend 的第二个参数?cblist 中元素的个数Q而不?aiocb 引用的个数?code>cblist 中Q?NULL 元素都会?aio_suspend 忽略?/p>

如果?aio_suspend 提供了超Ӟ而超时情늚发生了Q那么它׃q回 -1Q?code>errno 中会包含 EAGAIN?/p>

aio_cancel

aio_cancel 函数允许我们取消Ҏ个文件描q符执行的一个或所?I/O h。其原型如下Q?/p>
int aio_cancel( int fd, struct aiocb *aiocbp );
                        

要取消一个请求,我们需要提供文件描q符?aiocb 引用。如果这个请求被成功取消了,那么q个函数׃q回 AIO_CANCELED。如果请求完成了Q这个函数就会返?AIO_NOTCANCELED?/p>

要取消对某个l定文g描述W的所有请求,我们需要提供这个文件的描述W,以及一个对 aiocbp ?NULL 引用。如果所有的h都取消了Q这个函数就会返?AIO_CANCELEDQ如果至有一个请求没有被取消Q那么这个函数就会返?AIO_NOT_CANCELEDQ如果没有一个请求可以被取消Q那么这个函数就会返?AIO_ALLDONE。我们然后可以?aio_error 来验证每?AIO h。如果这个请求已l被取消了,那么 aio_error ׃q回 -1Qƈ?errno 会被讄?ECANCELED?/p>

lio_listio

最后,AIO 提供了一U方法?lio_listio API 函数同时发v多个传输。这个函数非帔R要,因ؓq意味着我们可以在一个系l调用(一ơ内怸下文切换Q中启动大量?I/O 操作。从性能的角度来看,q非帔R要,因此值得我们q旉探烦一下?code>lio_listio API 函数的原型如下:

int lio_listio( int mode, struct aiocb *list[], int nent,
                        struct sigevent *sig );
                        

mode 参数可以?LIO_WAIT ?LIO_NOWAIT?code>LIO_WAIT 会阻塞这个调用,直到所有的 I/O 都完成ؓ止。在操作q行排队之后Q?code>LIO_NOWAIT ׃q回?code>list 是一?aiocb 引用的列表,最大元素的个数是由 nent 定义的。注?list 的元素可以ؓ NULLQ?code>lio_listio 会将其忽略?code>sigevent 引用定义了在所?I/O 操作都完成时产生信号的方法?/p>

对于 lio_listio 的请求与传统?read ?write h在必L定的操作斚wE有不同Q如清单 4 所C?/p>
清单 4. 使用 lio_listio 函数发v一pdh
                        struct aiocb aiocb1, aiocb2;
                        struct aiocb *list[MAX_LIST];
                        ...
                        /* Prepare the first aiocb */
                        aiocb1.aio_fildes = fd;
                        aiocb1.aio_buf = malloc( BUFSIZE+1 );
                        aiocb1.aio_nbytes = BUFSIZE;
                        aiocb1.aio_offset = next_offset;
                        aiocb1.aio_lio_opcode = LIO_READ;
                        ...
                        bzero( (char *)list, sizeof(list) );
                        list[0] = &aiocb1;
                        list[1] = &aiocb2;
                        ret = lio_listio( LIO_WAIT, list, MAX_LIST, NULL );
                        

对于L作来_aio_lio_opcode 域的gؓ LIO_READ。对于写操作来说Q我们要使用 LIO_WRITEQ不q?LIO_NOP 对于不执行操作来说也是有效的?/p>



回页?/font>


AIO 通知

现在我们已经看过了可用的 AIO 函数Q本节将深入介绍对异步通知可以使用的方法。我们将通过信号和函数回调来探烦异步函数的通知机制?/p>

使用信号q行异步通知

使用信号q行q程间通信QIPCQ是 UNIX 中的一U传l机ӞAIO 也可以支持这U机制。在q种范例中,应用E序需要定义信号处理程序,在生指定的信号时就会调用这个处理程序。应用程序然后配|一个异步请求将在请求完成时产生一个信受作Z号上下文的一部分Q特定的 aiocb h被提供用来记录多个可能会出现的请求。清?5 展示了这U通知Ҏ?/p>
清单 5. 使用信号作ؓ AIO h的通知
                        void setup_io( ... )
                        {
                        int fd;
                        struct sigaction sig_act;
                        struct aiocb my_aiocb;
                        ...
                        /* Set up the signal handler */
                        sigemptyset(&sig_act.sa_mask);
                        sig_act.sa_flags = SA_SIGINFO;
                        sig_act.sa_sigaction = aio_completion_handler;
                        /* Set up the AIO request */
                        bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
                        my_aiocb.aio_fildes = fd;
                        my_aiocb.aio_buf = malloc(BUF_SIZE+1);
                        my_aiocb.aio_nbytes = BUF_SIZE;
                        my_aiocb.aio_offset = next_offset;
                        /* Link the AIO request with the Signal Handler */
                        my_aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
                        my_aiocb.aio_sigevent.sigev_signo = SIGIO;
                        my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
                        /* Map the Signal to the Signal Handler */
                        ret = sigaction( SIGIO, &sig_act, NULL );
                        ...
                        ret = aio_read( &my_aiocb );
                        }
                        void aio_completion_handler( int signo, siginfo_t *info, void *context )
                        {
                        struct aiocb *req;
                        /* Ensure it's our signal */
                        if (info->si_signo == SIGIO) {
                        req = (struct aiocb *)info->si_value.sival_ptr;
                        /* Did the request complete? */
                        if (aio_error( req ) == 0) {
                        /* Request completed successfully, get the return status */
                        ret = aio_return( req );
                        }
                        }
                        return;
                        }
                        

在清?5 中,我们?aio_completion_handler 函数中设|信号处理程序来捕获 SIGIO 信号。然后初始化 aio_sigevent l构产生 SIGIO 信号来进行通知Q这是通过 sigev_notify 中的 SIGEV_SIGNAL 定义来指定的Q。当L作完成时Q信号处理程序就从该信号?si_value l构中提取出 aiocbQƈ查错误状态和q回状态来定 I/O 操作是否完成?/p>

对于性能来说Q这个处理程序也是通过h下一ơ异步传输而l进?I/O 操作的理惛_斏V采用这U方式,在一ơ数据传输完成时Q我们就可以立即开始下一ơ数据传输操作?/p>

使用回调函数q行异步通知

另外一U通知方式是系l回调函数。这U机制不会ؓ通知而生一个信P而是会调用用L间的一个函数来实现通知功能。我们在 sigevent l构中设|了?aiocb 的引用,从而可以惟一标识正在完成的特定请求。请参看清单 6?/p>
清单 6. ?AIO h使用U程回调通知
                        void setup_io( ... )
                        {
                        int fd;
                        struct aiocb my_aiocb;
                        ...
                        /* Set up the AIO request */
                        bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
                        my_aiocb.aio_fildes = fd;
                        my_aiocb.aio_buf = malloc(BUF_SIZE+1);
                        my_aiocb.aio_nbytes = BUF_SIZE;
                        my_aiocb.aio_offset = next_offset;
                        /* Link the AIO request with a thread callback */
                        my_aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
                        my_aiocb.aio_sigevent.notify_function = aio_completion_handler;
                        my_aiocb.aio_sigevent.notify_attributes = NULL;
                        my_aiocb.aio_sigevent.sigev_value.sival_ptr = &my_aiocb;
                        ...
                        ret = aio_read( &my_aiocb );
                        }
                        void aio_completion_handler( sigval_t sigval )
                        {
                        struct aiocb *req;
                        req = (struct aiocb *)sigval.sival_ptr;
                        /* Did the request complete? */
                        if (aio_error( req ) == 0) {
                        /* Request completed successfully, get the return status */
                        ret = aio_return( req );
                        }
                        return;
                        }
                        

在清?6 中,在创q aiocb h之后Q我们?SIGEV_THREAD h了一个线E回调函数来作ؓ通知Ҏ。然后我们将指定特定的通知处理E序Qƈ要传输的上下文加蝲到处理程序中Q在q种情况中,是个?aiocb h自己的引用)。在q个处理E序中,我们单地引用到达?sigval 指针q?AIO 函数来验证请求已l完成?/p>



回页?/font>


?AIO q行pȝ优化

proc 文gpȝ包含了两个虚拟文Ӟ它们可以用来对异?I/O 的性能q行优化Q?/p>

  • /proc/sys/fs/aio-nr 文g提供了系l范围异?I/O h现在的数目?
  • /proc/sys/fs/aio-max-nr 文g是所允许的ƈ发请求的最大个数。最大个数通常?64KBQ这对于大部分应用程序来说都已经_了?




回页?/font>


l束?

使用异步 I/O 可以帮助我们构徏 I/O 速度更快、效率更高的应用E序。如果我们的应用E序可以对处理和 I/O 操作重叠q行Q那?AIO 可以帮助我们构建可以更高效C用可?CPU 资源的应用程序。尽这U?I/O 模型与在大部?Linux 应用E序中用的传统d模式都不同,但是异步通知模型在概念上来说却非常简单,可以化我们的设计?



参考资?

学习

获得产品和技?/strong>
  • 订购免费?SEK for LinuxQ这有两?DVDQ包括最新的 IBM for Linux 的试用YӞ包括 DB2®、Lotus®、Rational®、Tivoli® ?WebSphere®?

  • 在您的下一个开发项目中采用 IBM 试用软gQ这可以?developerWorks 上直接下载?


讨论


关于作?/span>

M. Tim Jones

Tim Jones 是一名嵌入式软g工程师,他是 GNU/Linux Application Programming?em>AI Application Programming 以及 BSD Sockets Programming from a Multilanguage Perspective {书的作者。他的工E背景非常广泛,从同步宇宙飞船的内核开发到嵌入式架构设计,再到|络?/p>



Bugs 2008-06-19 17:53 发表评论
]]>
初次使用linux下的异步I/Ohttp://www.shnenglu.com/Bugs/archive/2008/06/19/54037.htmlBugsBugsThu, 19 Jun 2008 09:50:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/06/19/54037.htmlhttp://www.shnenglu.com/Bugs/comments/54037.htmlhttp://www.shnenglu.com/Bugs/archive/2008/06/19/54037.html#Feedback0http://www.shnenglu.com/Bugs/comments/commentRss/54037.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/54037.html 

 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <aio.h>
 4#include <errno.h>
 5
 6
 7int main(int argc, char *argv[])
 8{
 9
10  int fd, ret;
11  struct aiocb my_aiocb;
12
13  fd = open( "file.txt", O_RDONLY );
14  if (fd < 0) perror("open");
15
16  /* Zero out the aiocb structure (recommended) */
17  bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
18
19  /* Allocate a data buffer for the aiocb request */
20  my_aiocb.aio_buf = malloc(BUFSIZE+1);
21  if (!my_aiocb.aio_buf) perror("malloc");
22
23  /* Initialize the necessary fields in the aiocb */
24  my_aiocb.aio_fildes = fd;
25  my_aiocb.aio_nbytes = BUFSIZE;
26  my_aiocb.aio_offset = 0;
27
28  ret = aio_read( &my_aiocb );
29  if (ret < 0) perror("aio_read");
30
31  while ( aio_error( &my_aiocb ) == EINPROGRESS ) ;
32
33  if ((ret = aio_return( &my_iocb )) > 0{
34      printf("%s\n", my_aiocb.aio_buf);
35    /* got ret bytes on the read */
36  }
 else {
37    /* read failed, consult errno */
38  }

39
40
41}


g++ test.cpp -lrt



Bugs 2008-06-19 17:50 发表评论
]]>
RamDisk好处Q?/title><link>http://www.shnenglu.com/Bugs/archive/2008/06/16/53517.html</link><dc:creator>Bugs</dc:creator><author>Bugs</author><pubDate>Mon, 16 Jun 2008 03:37:00 GMT</pubDate><guid>http://www.shnenglu.com/Bugs/archive/2008/06/16/53517.html</guid><wfw:comment>http://www.shnenglu.com/Bugs/comments/53517.html</wfw:comment><comments>http://www.shnenglu.com/Bugs/archive/2008/06/16/53517.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.shnenglu.com/Bugs/comments/commentRss/53517.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Bugs/services/trackbacks/53517.html</trackback:ping><description><![CDATA[<p>如果你有_大的内存Q?GQ,你可以采用RamDiskq个技术?br><br>何谓RamDiskQ就是内存映成盘Q?br>有什么好处呢Q?br>讉K速度?br>      可用于频发存取,大吞吐量盘操作<br>掉电后即消失</p>        临时文g<br><br><br>linux下的/tmp是ramdisk<br><br>windows下需要安装YӞ推荐一个(gavotte ramdiskQ?br> <img src ="http://www.shnenglu.com/Bugs/aggbug/53517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Bugs/" target="_blank">Bugs</a> 2008-06-16 11:37 <a href="http://www.shnenglu.com/Bugs/archive/2008/06/16/53517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>配置文gc!http://www.shnenglu.com/Bugs/archive/2008/05/26/51146.htmlBugsBugsMon, 26 May 2008 07:25:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/05/26/51146.htmlhttp://www.shnenglu.com/Bugs/comments/51146.htmlhttp://www.shnenglu.com/Bugs/archive/2008/05/26/51146.html#Feedback4http://www.shnenglu.com/Bugs/comments/commentRss/51146.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/51146.html////////////////////////////
// file : test.conf
a = 1;

b = 1
2
3
;

c = hi you;

d = "hi you" boy 110;

e = "\\=\\ \"test\"";        //  \=\"test"

/* end */
////////////////////////////


其中Q?br>// ?nbsp;/* */是注释;
 \\ 转义为\ Q?\*转义?Q?br>每个值空格分隔,如果使用了引?Q则" "之间的就为|
转义W,必须用在""形式的gQ?br>分号;为结束符受?br>
载入配置文gQ?br>
1bool Open(const char *filename);


获取指定key的valueQ?br>
1const char *GetValue(const char *key, int idx=0);


下面是一个用demoQ?br>
 1#include "../src/Common/Settings.h"
 2
 3int main(int argc, char *argv[])
 4{
 5
 6    Settings s;
 7    if( s.Open("test.conf") )
 8    {
 9        LOGI("load file succed!");
10
11        LOGE("%s",  s.GetValue("c"3) );
12    }

13    else
14    {
15        LOGE("load file failed!");
16    }

17    return 0;
18}

19

//
代码Q?a >http://code.google.com/p/bugs1111 里面查找settgings.h settgings.cpp

Bugs 2008-05-26 15:25 发表评论
]]>
|络~程 心得2http://www.shnenglu.com/Bugs/archive/2008/04/24/48047.htmlBugsBugsThu, 24 Apr 2008 10:33:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/04/24/48047.htmlhttp://www.shnenglu.com/Bugs/comments/48047.htmlhttp://www.shnenglu.com/Bugs/archive/2008/04/24/48047.html#Feedback7http://www.shnenglu.com/Bugs/comments/commentRss/48047.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/48047.html那么在关闭的时候,会经历TIME_WAIT的过E,一般windows下是2分钟Q这D|_客户端connect的时候,会出?WSAEADDRINUSE:10048)Q?br>怎么不经历这个状态呢Q?br>使用下面代码Q?br>
  // 如果要已l处于连接状态的soket在调用closesocket后强制关闭,不经历TIME_WAIT的过E:
  BOOL bDontLinger = FALSE;
  if (setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL))< 0) {
   wsaperror("setsockopt");
   break;
  }


Bugs 2008-04-24 18:33 发表评论
]]>
|络~程 心得1http://www.shnenglu.com/Bugs/archive/2008/04/08/46509.htmlBugsBugsTue, 08 Apr 2008 06:43:00 GMThttp://www.shnenglu.com/Bugs/archive/2008/04/08/46509.htmlhttp://www.shnenglu.com/Bugs/comments/46509.htmlhttp://www.shnenglu.com/Bugs/archive/2008/04/08/46509.html#Feedback2http://www.shnenglu.com/Bugs/comments/commentRss/46509.htmlhttp://www.shnenglu.com/Bugs/services/trackbacks/46509.html

以前目里发C个这L问题Q当|络服务q程x的时候,在立卛_动该服务Q会有错误提Cport被占用了Q监听失败?br>
最q在看《unix |络~程》,在里面了解到?链接时的三次握手 ?关闭时的四次握手Q?br>在关闭时最后会有一个TIME_WAIT状态,q个状态时间是TCP里最长的Q是二倍MSL旉Q大U在1-4分钟?br>至于Z么要保留q个状态和q么长的旉Q请参考《unix |络~程》第二章 2.7.

但这L问题是可以解决的Q?span>SO_REUSEADDR    enables local address reuseQ可以在TIME_WAIT状态下使用相同的PORT?/span>

int reuser_addr = 1;
 ::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void*)&reuse_addr, sizeof(reuse_addr));

SO_REUSEADDR 的用途除了上面这U情况,q有三种分别是:
*)在多|卡的时候,多进E可以用不同IPQ相同PORT?br>*)与上条差不多Q在单进E用用不同IPQ相同PORT?br>*)在UDPq播的时候,可以在相同IP和PORT下用,TCP则不行?/span>


Bugs 2008-04-08 14:43 发表评论
]]>
ŷƷƵһþþþƷ| þþžžþƷ| þëƬѿһ| þAV| ޾ƷĻþò| ޾Ʒþþþϼ| þþƷaĻ þþƷŷƬ | պƷþһ| Ʒ۲ӰԺþ| Ʒþþþþҹҹ| þþþһƷ| ٸۺϾþĻ| ޹ƷþõӰŷ| Ʒþþþþһ| 97þþƷһ| վþþ| Ʒþһ| þþƷ| ԭۺϾþô˵| þˬˬƬAV| 鶹Ʒþþþþþ99| ƷþĻ| ƷŮͬһþ| þ91Ʒ91| ˮϵþþƷ| Ʒþþþþ˳ | ŷսպ91ۺһþþ| þܳ| 69ۺϾþþƷ| ƷȾþþø| ˳ɾƷþþþ| 91ƷùۺϾþ| vavavaþ| ޺ݺۺϾþ| ձþþҹƷ| 91þþƷ˾þ| Ưޱ˾þþƷ| RE99þþƷ66| þѸƵ| þùƷ77777| þۺϹɫ88þþƷۺ|