﻿<?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++博客-ifeng-随笔分类-linux</title><link>http://www.cppblog.com/ifeng/category/17826.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 10 Jan 2012 05:22:01 GMT</lastBuildDate><pubDate>Tue, 10 Jan 2012 05:22:01 GMT</pubDate><ttl>60</ttl><item><title>FastCGI运行模型学习总结</title><link>http://www.cppblog.com/ifeng/archive/2012/01/05/163635.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Thu, 05 Jan 2012 08:58:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2012/01/05/163635.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/163635.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2012/01/05/163635.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/163635.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/163635.html</trackback:ping><description><![CDATA[<div><p style="margin-top: 0in; margin-right: 0in; margin-bottom: 0in; margin-left: 0in; font-weight: bold; font-family: arial; font-size: 13.5pt; ">FastCGI的工作原理</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">1、Web Server启动时载入FastCGI进程管理器（IIS ISAPI或Apache Module)</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">2、FastCGI进程管理器自身初始化，启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">3、当客户端请求到达Web Server时，FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">4、FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时，请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中，php-cgi在此便退出了。</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">在上述情况中，你可以想象CGI通常有多慢。每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展并重初始化全部数据结构。使用FastCGI，所有这些都只在进程启动时发生一次。一个额外的好处是，持续数据库连接(Persistent database connection)可以工作。 </p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in;font-size:10.0pt"><span style="font-family:SimSun">这个很容易找到。也容易理解，但是继续</span><span style="font-family:Calibri">google</span><span style="font-family:SimSun">之后，发现自己的概念又模糊了。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">比如有些例子用</p>  <p style="margin:0in"><span style="font-weight: bold; font-family: Arial; font-size: 10.5pt; ">spawn-fcgi</span> </p>  <p style="margin:0in"><span style="font-weight: bold; font-family: SimSun; font-size: 10.5pt; ">/usr/local/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -C 5 -u </span><span style="font-weight: bold; font-family: Calibri; font-size: 10.5pt; ">root</span><span style="font-weight: bold; font-family: SimSun; font-size: 10.5pt; "> -g </span><span style="font-weight: bold; font-family: Calibri; font-size: 10.5pt; ">root</span><span style="font-weight: bold; font-family: SimSun; font-size: 10.5pt; "> -f /usr/bin/php-cgi</span> </p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin-top: 0in; margin-right: 0in; margin-bottom: 0in; margin-left: 0in; font-weight: bold; font-family: Arial; font-size: 10.5pt; ">参数含义如下</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <ol type="1" style="margin-left:.75in;direction:ltr;unicode-bidi:embed;  margin-top:0in;margin-bottom:0in;font-family:SimSun;font-size:10.5pt;  font-weight:bold">  <li value="1" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-f      &lt;fcgiapp&gt; 指定调用FastCGI的进程的执行程序位置，根据系统上所装的PHP的情况具体设置</span></li>  <li value="2" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-a &lt;addr&gt; 绑定到地址addr</span></li>  <li value="3" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-p &lt;port&gt; 绑定到端口port</span></li>  <li value="4" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-s &lt;path&gt; 绑定到unix socket的路径path</span></li>  <li value="5" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-C &lt;childs&gt; 指定产生的FastCGI的进程数，默认为5（仅用于PHP）</span></li>  <li value="6" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-P &lt;path&gt; 指定产生的进程的PID文件路径</span></li>  <li value="7" style="margin-top: 0px; margin-bottom: 0px; vertical-align: middle; "><span style="font-size: 10.5pt; ">-u和-g FastCGI使用什么身份（-u 用户 -g      用户组）运行，Ubuntu下可以使用www-data，其他的根据情况配置，如nobody、apache等</span></li> </ol>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in;font-size:10.0pt"><span style="font-family:SimSun">刚看到</span><span style="font-family:Calibri">FastCGI</span><span style="font-family:SimSun">原理的时候，我想象中的运行模型是，前端的反向代理服务器如</span><span style="font-family:Calibri">Nginx</span><span style="font-family: SimSun">收到请求，然后转发给</span><span style="font-family:Calibri">cgi</span><span style="font-family:SimSun">进程，这个</span><span style="font-family:Calibri">cgi</span><span style="font-family:SimSun">进程有</span><span style="font-family:Calibri">N</span><span style="font-family:SimSun">个，从而实现并发处理。但是接下来搜索到的</span><span style="font-family:Calibri">C</span><span style="font-family:SimSun">语言实现的</span><span style="font-family:Calibri">FastCGI</span><span style="font-family:SimSun">应用的例子好像又把这个模型给否定了。并且</span><span style="font-family:Calibri">fastcgi</span><span style="font-family: SimSun">是语言无关的，难道你要用</span><span style="font-family:Calibri">python</span><span style="font-family:SimSun">写并发？<br /></span></p><div style="background-color: #eeeeee; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;"fcgi_stdio.h"<br />#include&nbsp;&lt;stdlib.h&gt;<br /><span style="color: #0000FF; ">int</span>&nbsp;count;<br /><span style="color: #0000FF; ">void</span>&nbsp;initialize(<span style="color: #0000FF; ">void</span>)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;count=0;<br />}<br /><span style="color: #0000FF; ">void</span>&nbsp;main(<span style="color: #0000FF; ">void</span>)<br />{<br />initialize();<br />&nbsp;<br /><span style="color: #0000FF; ">while</span>&nbsp;(FCGI_Accept()&nbsp;&gt;=&nbsp;0)&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;printf("Content-type:&nbsp;text/html&#8220;r&#8220;n"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&#8220;r&#8220;n"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;title&gt;FastCGI&nbsp;Hello!&nbsp;(C,&nbsp;fcgi_stdio&nbsp;library)&lt;/title&gt;"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;h1&gt;FastCGI&nbsp;Hello!&nbsp;(C,&nbsp;fcgi_stdio&nbsp;library)&lt;/h1&gt;"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Request&nbsp;number&nbsp;%d&nbsp;running&nbsp;on&nbsp;host&nbsp;&lt;i&gt;%s&lt;/i&gt;&#8220;n",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++count,&nbsp;getenv("SERVER_HOSTNAME"));<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div><p style="margin:0in;font-weight:bold;font-size:10.5pt;color:#333333"><span style="font-family:宋体">这个代码看不出来有任何并发处理的部分。比如</span><span style="font-family:Calibri">fork</span><span style="font-family: 宋体">什么的。</span></p></div><p>&nbsp;</p><div>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in;font-size:10.0pt"><span style="font-family:SimSun">另外一种模型就是有一种叫做FastCGI进程管理器的进程，就像上面说的是管理</span><span style="font-family: Calibri">fastcgi</span><span style="font-family:SimSun">进程的进程，请求转发到管理器的时候，由它来进行选择相应的应用进程，卡就卡在这了，这个管理器是怎么来选择进程的啊，假如我有</span><span style="font-family:Calibri">N</span><span style="font-family:SimSun">个不同逻辑的可执行文件，它怎么知道要转发给哪个进程呢，</span><span style="font-family:Calibri">google</span><span style="font-family:SimSun">到的</span><span style="font-family:Calibri">fastcgi</span><span style="font-family: SimSun">配置都是针对反向代理的后端也即管理器设置的，没有发现有针对不同逻辑发给不同的应用进程的部分。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">继续狂搜，还是无果，都是类似的文章。网上搜索不到的问题，要么就是很难很偏，要么就是很简单，简单到不值一提，很显然，我属于后者。转换思路，开始考虑假如要自己来实现这个功能的话该怎么办。一步步地推理，在结合搜索到的文章，大概理清了思路，我的理解如下，不对的地方请指正。</p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in"><span style="font-weight:bold;font-family:Calibri; font-size:10.0pt">1.</span><span style="font-family:SimSun; font-size:10.0pt">有一个</span><span style="font-family:Calibri; font-size:10.0pt">CGI</span><span style="font-family:SimSun; font-size:10.0pt">进程管理器，这个管理器一般是用第</span><span style="font-family: Calibri;font-size:10.0pt">3</span><span style="font-family:SimSun; font-size:10.0pt">方的</span><span style="font-family:Calibri; font-size:10.0pt">fastcgi</span><span style="font-family:SimSun; font-size:10.0pt">开发套件，比如上面提到的</span><span style="font-weight: bold; font-family: Arial; font-size: 10.5pt; ">spawn-fcgi</span><span style="font-family:SimSun;font-size:10.0pt"> ，用它可以启动指定可执行文件的</span><span style="font-family:SimSun;font-size:10.0pt">N</span><span style="font-family:SimSun;font-size:10.0pt">个实例，关于之前选择进程的疑问，这里可以得到解释，那就是多个进程只是同一个可执行文件的实例，假如你想把不同的模块分开生成可执行文件的话估计就得再启动多一个管理器了吧。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in;font-size:10.0pt"><span style="font-weight:bold; font-family:Calibri">2.</span><span style="font-family:SimSun">假如你是用</span><span style="font-family:Calibri">python</span><span style="font-family:SimSun">写的</span><span style="font-family:Calibri">fastcgi</span><span style="font-family:SimSun">的应用程序，那么当你用管理器启动了</span><span style="font-family:Calibri">100</span><span style="font-family:SimSun">个实例的时候，也就相当于启动了</span><span style="font-family:Calibri">100</span><span style="font-family:SimSun">个</span><span style="font-family:Calibri">python</span><span style="font-family:SimSun">解析器，如果是用</span><span style="font-family:Calibri">C</span><span style="font-family:SimSun">等静态语言写的话那还好，只是跟你写的程序大小有关。</span></p>  <p style="margin:0in;font-family:SimSun;font-size:10.0pt">&nbsp;</p>  <p style="margin:0in;font-size:10.0pt"><span style="font-family:SimSun">可能是没有接触过</span><span style="font-family:Calibri">CGI</span><span style="font-family:SimSun">程序的原因，让我对这基本的模型都纠结了一下午，希望这篇文章能帮些初学者。</span></p></div><hr /></div><img src ="http://www.cppblog.com/ifeng/aggbug/163635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2012-01-05 16:58 <a href="http://www.cppblog.com/ifeng/archive/2012/01/05/163635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>服务器多线程方案的选择</title><link>http://www.cppblog.com/ifeng/archive/2011/11/20/160587.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Sun, 20 Nov 2011 14:35:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/11/20/160587.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/160587.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/11/20/160587.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/160587.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/160587.html</trackback:ping><description><![CDATA[<div><div>最近想写个多线程模型的服务器，但是一直纠结要选哪种方式，参考了memcached，但是觉得不完美.</div><div>备选方案，当然这些都是NIO</div><div>1.一个IO线程，专门处理连接读写数据，一个逻辑线程，专门处理数据。</div><div>2.一个IO线程，一个线程池，可任意配置线程池的数量。</div><div></div><div>先考虑1，假设连接层用epoll的ET模式实现，当IO线程发生可读事件时，必须把接收缓冲区的数据全部收完，一直read直到发生EAGAIN错误，否则就必须自己在上层维护一个可读队列。</div><div><span style="white-space:pre">	</span>方法a:每收到一个协议包，就转发给逻辑处理.处理完再接着收取剩下的包。但是TCP是无边界的，有可能收到0.5个或者2.5个包，这时你得为每个连接准备个buf,并且每收到个包都要跟逻辑线程同步加锁一次,还有个很大的弊端就是，连接层已经跟逻辑协议相关了，这似乎不是很好。</div><div><span style="white-space:pre">	</span>方法b:IO线程把所有数据都收完再通知逻辑线程。当然这样也无法避免收到半个协议包的情况，所以我是想维护一个recv到的数据队列，IO线程把每次收到的包都丢到这个队列。</div><div><span style="white-space:pre">	</span></div><div><span style="white-space:pre">	</span>a,b2种方法都面临着send的麻烦，现在send也有以下方案.</div><div><span style="white-space:pre">	</span>方法a.每次需要write的时候就直接send发不完的就加到发送队列中去。在发送前必须要先判断一下队列是不是空，如果不为空就必须先处理队列，剩余数据待可读事件发生时再处理，&nbsp;&nbsp;&nbsp;于是脑子中又出现一大堆锁了。有2个线程可能对socket进行写操作。</div><div><span style="white-space:pre">	</span></div><div><span style="white-space:pre">	</span>方法b.每次需要send的时候都直接把数据丢到发送队列去，等到可读事件到来时再尽量把队列都发送完。但是响应可能没那么迅速了。</div><div>这两种方法都必须为每个数据包增加一个标识TCP连接的字段，因为socket fd是可以重复使用的，比如用户A连接分配的socket是100，逻辑线程正在为A处理数据，但是用户A断开连接了，同时立即有另外个用户连接进来并且分配的socket是100，这时悲剧就发生了。</div><div></div><div>再考虑下线程池的2种情况.</div><div>a.主线程负责IO，包括处理连接，读写，把读到的数据加入recv队列，子线程把需要写的加入send队列.</div><div>这个方案有个很大的缺陷：无法保证先到的请求先返回，这是很致命的，只能通过客户端来确保收到前一个请求的结果以后再发送下一个请求。</div><div></div><div>b.主线程只负责监听连接，收到连接到来事件后，通知线程池去accept连接，因此每个连接的数据都会由同一个线程处理，也就保证了顺序，但是这样的话子线程就必须承担起IO的任务了，这样好像就有些分工不清了，这个是memcached中用的方案.</div><div></div><div></div><div>PS:用epoll的ET模式需要一直recv,这样有可能是使得活跃的连接占用了全部带宽，因此需要在上层对连接进行限速，因此也就需要维护可读事件了。</div><div></div><div>纠结好几天了，第一次写多线程服务器，一直为选方案纠结啊，我本人倾向于线程池，毕竟可以利用多核的优势啊。不知道大家实际上用的都是什么方案呢，非常想知道，请指教。<br />再PS：做了个小测试，nginx+memcached,下载一个700多K的文件，开100个线程，每个线程下载100次，全部命中跟全部不命中的情况几乎没有差别，这是为什么呢？难道linux系统本身就已经有cached了吗？<br /></div></div><img src ="http://www.cppblog.com/ifeng/aggbug/160587.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-11-20 22:35 <a href="http://www.cppblog.com/ifeng/archive/2011/11/20/160587.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有关TCP和UDP 粘包 消息保护边界(转)</title><link>http://www.cppblog.com/ifeng/archive/2011/11/11/159950.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Fri, 11 Nov 2011 02:22:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/11/11/159950.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/159950.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/11/11/159950.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/159950.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/159950.html</trackback:ping><description><![CDATA[<div><div>在socket网络程序中，TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程，收发两端（客户端和服务器端）都要有一一成对的socket，因此，发送端为了将多个发往接收端的包，更有效的发到对方，使用了优化方法（Nagle算法），将多次间隔较小且数据量小的数据，合并成一个大的数据块，然后进行封包。这样，接收端，就难于分辨出来了，必须提供科学的拆包机制。</div><div>对于UDP，不会使用块的合并优化算法，这样，实际上目前认为，是由于UDP支持的是一对多的模式，所以接收端的skbuff(套接字缓冲区）采用了链式结构来记录每一个到达的UDP包，在每个UDP包中就有了消息头（消息来源地址，端口等信息），这样，对于接收端来说，就容易进行区分处理了</div><div></div><div>保护消息边界和流</div><div>那么什么是保护消息边界和流呢?</div><div></div><div>保护消息边界，就是指传输协议把数据当作一条独立的消息在网上&nbsp;</div><div>传输,接收端只能接收独立的消息.也就是说存在保护消息边界,接收&nbsp;</div><div>端一次只能接收发送端发出的一个数据包.&nbsp;</div><div>而面向流则是指无保护消息保护边界的,如果发送端连续发送数据,&nbsp;</div><div>接收端有可能在一次接收动作中,会接收两个或者更多的数据包.</div><div></div><div>我们举个例子来说,例如,我们连续发送三个数据包,大小分别是2k,&nbsp;</div><div>4k , 8k,这三个数据包,都已经到达了接收端的网络堆栈中,如果使&nbsp;</div><div>用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有&nbsp;</div><div>三次接收动作,才能够把所有的数据包接收完.而使用TCP协议,我们&nbsp;</div><div>只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的&nbsp;</div><div>数据包接收下来.只需要有一次接收动作.</div><div></div><div>这就是因为UDP协议的保护消息边界使得每一个消息都是独立的.而&nbsp;</div><div>流传输,却把数据当作一串数据流,他不认为数据是一个一个的消息.</div><div></div><div>所以有很多人在使用tcp协议通讯的时候,并不清楚tcp是基于流的&nbsp;</div><div>传输,当连续发送数据的时候,他们时常会认识tcp会丢包.其实不然,&nbsp;</div><div>因为当他们使用的缓冲区足够大时,他们有可能会一次接收到两个甚&nbsp;</div><div>至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个&nbsp;</div><div>数据包,而已经接收的其他数据包却被忽略了.所以大家如果要作这&nbsp;</div><div>类的网络编程的时候,必须要注意这一点.</div><div></div><div>结论：</div><div>根据以上所说，可以这样理解，TCP为了保证可靠传输，尽量减少额外</div><div>开销（每次发包都要验证），因此采用了流式传输，面向流的传输，</div><div>相对于面向消息的传输，可以减少发送包的数量。从而减少了额外开</div><div>销。但是，对于数据传输频繁的程序来讲，使用TCP可能会容易粘包。</div><div>当然，对接收端的程序来讲，如果机器负荷很重，也会在接收缓冲里</div><div>粘包。这样，就需要接收端额外拆包，增加了工作量。因此，这个特</div><div>别适合的是数据要求可靠传输，但是不需要太频繁传输的场合（</div><div>两次操作间隔100ms，具体是由TCP等待发送间隔决定的，取决于内核</div><div>中的socket的写法）</div><div></div><div>而UDP，由于面向的是消息传输，它把所有接收到的消息都挂接到缓冲</div><div>区的接受队列中，因此，它对于数据的提取分离就更加方便，但是，</div><div>它没有粘包机制，因此，当发送数据量较小的时候，就会发生数据包</div><div>有效载荷较小的情况，也会增加多次发送的系统发送开销（系统调用，</div><div>写硬件等）和接收开销。因此，应该最好设置一个比较合适的数据包</div><div>的包长，来进行UDP数据的发送。（UDP最大载荷为1472，因此最好能</div><div>每次传输接近这个数的数据量，这特别适合于视频，音频等大块数据</div><div>的发送，同时，通过减少握手来保证流媒体的实时性）</div></div><img src ="http://www.cppblog.com/ifeng/aggbug/159950.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-11-11 10:22 <a href="http://www.cppblog.com/ifeng/archive/2011/11/11/159950.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一致性hash算法</title><link>http://www.cppblog.com/ifeng/archive/2011/10/18/158611.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Tue, 18 Oct 2011 05:49:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/10/18/158611.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/158611.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/10/18/158611.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/158611.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/158611.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="color: #333333; font-family: verdana, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff; ">http://hbluojiahui.blog.163.com/blog/static/31064767201098114026211/</span><img src ="http://www.cppblog.com/ifeng/aggbug/158611.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-10-18 13:49 <a href="http://www.cppblog.com/ifeng/archive/2011/10/18/158611.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mysql字符串转义函数</title><link>http://www.cppblog.com/ifeng/archive/2011/10/17/158523.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Mon, 17 Oct 2011 03:43:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/10/17/158523.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/158523.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/10/17/158523.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/158523.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/158523.html</trackback:ping><description><![CDATA[<div><div>在mysql插入数据表，如果数据中带有'\&#8220;会造成语法错误，这个不用解释，你懂的，因此需要写个转义函数，一开始想直接用string的replace，但是这个方法要调用3次</div><div>放在服务端感觉效率太低了，于是用C写了个，感觉还可以，时间复杂度跟需要转义字符的个数无关，如果源串没有匹配的话不需要copy操作.<br /><span class="Apple-style-span" style="font-size: 13px; background-color: #eeeeee; "><span style="color: #008000; ">//</span><span style="color: #008000; ">转义函数,&#8216;转成\'</span></span></div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><span style="color: #0000FF; ">bool</span><span style="color: #000000; ">&nbsp;ConverToDBStr(&nbsp;</span><span style="color: #0000FF; ">const</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;src,</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">*</span><span style="color: #000000; ">dst&nbsp;)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">记录上次匹配的位置</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;dOffset&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">目标字符串游标</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;nCopy&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">本次需要成&nbsp;copy的字节数</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">const</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">*</span><span style="color: #000000; ">p&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;src;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">(&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">p&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">p</span><span style="color: #000000; ">==</span><span style="color: #000000; ">'</span><span style="color: #000000; ">\\</span><span style="color: #000000; ">'</span><span style="color: #000000; ">||*</span><span style="color: #000000; ">p</span><span style="color: #000000; ">==</span><span style="color: #000000; ">'</span><span style="color: #000000; ">\</span><span style="color: #000000; ">''</span><span style="color: #000000; ">||*p==</span><span style="color: #000000; ">'"</span><span style="color: #000000; ">'&nbsp;)</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nCopy&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;p</span><span style="color: #000000; ">-</span><span style="color: #000000; ">src</span><span style="color: #000000; ">-</span><span style="color: #000000; ">i</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memcpy(&nbsp;dst</span><span style="color: #000000; ">+</span><span style="color: #000000; ">dOffset,src</span><span style="color: #000000; ">+</span><span style="color: #000000; ">i</span><span style="color: #000000; ">+</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,nCopy&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dOffset</span><span style="color: #000000; ">+=</span><span style="color: #000000; ">nCopy;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">(dst</span><span style="color: #000000; ">+</span><span style="color: #000000; ">Offset)</span><span style="color: #000000; ">=</span><span style="color: #000000; ">'</span><span style="color: #000000; ">\\</span><span style="color: #000000; ">'</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">(dst</span><span style="color: #000000; ">+</span><span style="color: #000000; ">dOffset</span><span style="color: #000000; ">+</span><span style="color: #000000; ">1</span><span style="color: #000000; ">)</span><span style="color: #000000; ">=*</span><span style="color: #000000; ">p;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dOffset</span><span style="color: #000000; ">+=</span><span style="color: #000000; ">2</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;p</span><span style="color: #000000; ">-</span><span style="color: #000000; ">src;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p</span><span style="color: #000000; ">++</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(&nbsp;dOffset</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;)</span><span style="color: #008000; ">//</span><span style="color: #008000; ">有匹配到，copy最后的字符串</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memcpy(&nbsp;dst</span><span style="color: #000000; ">+</span><span style="color: #000000; ">dOffset,src</span><span style="color: #000000; ">+</span><span style="color: #000000; ">i</span><span style="color: #000000; ">+</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,p</span><span style="color: #000000; ">-</span><span style="color: #000000; ">src</span><span style="color: #000000; ">-</span><span style="color: #000000; ">i&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">;<br /></span></div><div><span class="Apple-style-span" style="font-size: 13px; background-color: #eeeeee; ">}<br />可以看到，这个函数稍微改动下就可以实现replace</span></div></div><img src ="http://www.cppblog.com/ifeng/aggbug/158523.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-10-17 11:43 <a href="http://www.cppblog.com/ifeng/archive/2011/10/17/158523.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>nginx笔记</title><link>http://www.cppblog.com/ifeng/archive/2011/09/30/157201.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Fri, 30 Sep 2011 01:45:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/09/30/157201.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/157201.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/09/30/157201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/157201.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/157201.html</trackback:ping><description><![CDATA[<div><p style="margin:0in"><span style="font-family:SimSun;font-size:17.0pt">ngx_connection</span><span style="font-family:Calibri;font-size: 17.0pt">_t,</span><span style="font-family:SimSun;font-size:10.0pt">抽象的连接，在</span><span style="font-family:Calibri;font-size:10.0pt">core</span><span style="font-family:SimSun;font-size:10.0pt">模块的</span><span style="font-family:SimSun;font-size:10.0pt; color:#333333">ngx_event_process_init</span><span style="font-family: SimSun;font-size:10.0pt"> 函数中预先分配好。<span class="Apple-style-span" style="font-family: verdana, 'courier new'; background-color: #eeeeee; ">ngx_event_process_init预分配connects，read\write&nbsp;事件的数组，</span></span></p><div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><span style="color: #000000; ">并依次初始化，并依次初始化各连接的链表关系，也就是在data上存下一个connection的指针&nbsp;<br />&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">connections&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx_alloc(</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(ngx_connection_t)&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">connection_n,&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">log);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">connections&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;NULL)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;NGX_ERROR;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />.<br /><br />&nbsp;c&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">connections;<br />.<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">do</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i</span><span style="color: #000000; ">--</span><span style="color: #000000; ">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i].data&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i].read&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">read_events[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i].write&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">write_events[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i].fd&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(ngx_socket_t)&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">c[i];<br /></span><span style="color: #0000FF; ">#if</span><span style="color: #000000; ">&nbsp;(NGX_THREADS)</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i].</span><span style="color: #0000FF; ">lock</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br /></span><span style="color: #0000FF; ">#endif</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(i);<br />&nbsp;&nbsp;&nbsp;&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">free_connections&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;next;<br />&nbsp;&nbsp;&nbsp;&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">free_connection_n&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">connection_n;<br /><br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">初始化linsten&nbsp;socket，并设置listen的处理函数为&nbsp;rev-&gt;handler&nbsp;=&nbsp;ngx_event_acceptex;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">Rev</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">accept</span><span style="color: #000000; ">=</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br />&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">listening.nelts;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;ngx_get_connection(ls[i].fd,&nbsp;cycle</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">log);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(c&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;NULL)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;NGX_ERROR;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}（结构体部分成员）</span></div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;ngx_connection_s&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">data;<br />&nbsp;&nbsp;&nbsp;&nbsp;ngx_event_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">read;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">读事件处理</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;ngx_event_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">write;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">写事件处理</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;ngx_socket_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fd;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">连接对应的socket</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;ngx_listening_t&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">listening;</span><span style="color: #000000; ">/</span><span style="color: #000000; "><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;ngx_log_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">log;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;ngx_pool_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">pool;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">平台相关的读写，对应socket的send,recv</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx_recv_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;recv;<br />&nbsp;&nbsp;&nbsp;&nbsp;ngx_send_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;sockaddr&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">sockaddr;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">地址</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;socklen_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;socklen;<br />&nbsp;&nbsp;&nbsp;&nbsp;ngx_str_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addr_text;<br />}<br /><div><p style="margin:0in;font-size:10.0pt"><span style="font-family:SimSun">ngx_get_connection</span><span style="font-family:Calibri">:</span><span style="font-family:SimSun">从</span><span style="font-family:Calibri">freeconnect</span><span style="font-family:SimSun">队头取出一个</span><span style="font-family: Calibri">connection,</span><span style="font-family:SimSun">并将</span><span style="font-family:Calibri">socket</span><span style="font-family:SimSun">绑定此</span><span style="font-family: Calibri; ">connection<br /></span></p><div><p style="margin:0in;font-size:10.0pt"><span style="font-family:SimSun">在上层应用（比如</span><span style="font-family:Calibri">HTTP</span><span style="font-family:SimSun">），使用ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags)加入读事件。</span></p></div><p>&nbsp;</p>  <p style="margin-top: 0in; margin-right: 0in; margin-bottom: 0in; margin-left: 0in; "></p><div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><span style="color: #000000; ">在ngx_epoll_process_events函数中，<br />&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(flags&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">&nbsp;NGX_POST_EVENTS)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx_locked_post_event(wev,&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">ngx_posted_events);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wev</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">handler(wev);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />如果带有NGX_POST_EVENTS标记，就把事件投递到队列中不立即处理。<br />在ngx_process_events_and_timers&nbsp;中，会在每个循环调用ngx_event_process_posted(cycle,&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">ngx_posted_events);不断取出事件队列进行处理。<br />&nbsp;NGX_POST_EVENTS是为了进行耗时操作前先释放进程锁，放入队列稍后再处理(用进程锁应该是避免N个进程accept导致的惊群，新版linux已经不会出现这个问题)。<br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(ngx_posted_events)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(ngx_threaded)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx_wakeup_worker_thread(cycle);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ngx_event_process_posted(cycle,&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">ngx_posted_events);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span></div><p>&nbsp;</p></div></span></div></div><img src ="http://www.cppblog.com/ifeng/aggbug/157201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-09-30 09:45 <a href="http://www.cppblog.com/ifeng/archive/2011/09/30/157201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EPOLL下的accept(转载)</title><link>http://www.cppblog.com/ifeng/archive/2011/09/29/157141.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Thu, 29 Sep 2011 09:08:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/09/29/157141.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/157141.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/09/29/157141.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/157141.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/157141.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: （转载者注：看完这个，再回头看看nginx源码，发现它在accept时用的是LT模式，read,write时是ET模式）不知道是谁第一个犯了错，在网上贴出所谓epoll通用框架的代码。注意看accpet的处理：1epfd = epoll_create(10);2&nbsp;3struct&nbsp;sockaddr_in clientaddr;4struct&nbsp;sockaddr_in se...&nbsp;&nbsp;<a href='http://www.cppblog.com/ifeng/archive/2011/09/29/157141.html'>阅读全文</a><img src ="http://www.cppblog.com/ifeng/aggbug/157141.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-09-29 17:08 <a href="http://www.cppblog.com/ifeng/archive/2011/09/29/157141.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>nginx源码简单分析</title><link>http://www.cppblog.com/ifeng/archive/2011/09/27/156948.html</link><dc:creator>冷锋</dc:creator><author>冷锋</author><pubDate>Tue, 27 Sep 2011 03:26:00 GMT</pubDate><guid>http://www.cppblog.com/ifeng/archive/2011/09/27/156948.html</guid><wfw:comment>http://www.cppblog.com/ifeng/comments/156948.html</wfw:comment><comments>http://www.cppblog.com/ifeng/archive/2011/09/27/156948.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ifeng/comments/commentRss/156948.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ifeng/services/trackbacks/156948.html</trackback:ping><description><![CDATA[<p>由于工作需要，分析了nginx的连接层事件处理模块，只是初步的大体分析。<br /><br />mian函数(nginx.c)里面做一些初始化的工作，最主要的部分，是调用ngx_init_cycle，ngx_master_process_cycle（主进程循环），<br />ngx_init_cycle主要是做一些初始化的工作，包括调用ngx_open_listening_sockets打开socket端口监听等。<br />ngx_master_process_cycle函数中，先设置一下需要阻塞的信号，然后是调用ngx_start_worker_processes函数创建worker进程，然后进入一个死循环。里面应该是管理worker进程的，主循环里面调用了sigsuspend函数挂起等待信号，具体怎么管理还没研究。</p>
<p>ngx_start_worker_processes：调用ngx_spawn_process，循环创建N个worker进程<br />ngx_spawn_process：调用socketpair创建用于父子进程通信的socket,里面进行了一大堆socket参数设置，然后调用worker进程的主循环ngx_worker_process_cycle，<br />然后主进程设置进程表相应信息。<br />ngx_worker_process_cycle：先调用ngx_worker_process_init初始化进程，里面应该是设置成守护进程等等，有初始化模块信息，关闭对等socket的其中一个channel,其中比较关键的是调用ngx_add_channel_event。里面调用ngx_get_connection返回一个free的ngx_connection_t,最关键的是ngx_add_conn，其对应到epoll模块的ngx_epoll_add_connection，在这里就是添加相应的监听socket进监听队列，并设置连接为激活状态，可以看到这里epoll是用的ET模式。</p>
<p>接下来在ngx_worker_process_cycle中，检查是否配置了多线程模式，如果有，就创建多线程，我只关注多进程，因此先无视它，关键点是调用ngx_process_events_and_timers函数，<br />ngx_process_events_and_timers：调用ngx_process_events和ngx_event_process_posted，<br />ngx_process_events对应是ngx_epoll_process_events，这里会调用epoll_wait，就跟平常的epoll使用一样。<br />ngx_event_process_posted(cycle, &amp;ngx_posted_accept_events);处理accept队列中所有事件，ngx_posted_accept_events没有找到初始化的地方，估计是编译脚本自动生成的，估计会对应到ngx_event_accept函数进行处理，里面就是普通的accept操作，返回fd,并生成一条ngx connection,然后调用ngx_add_conn加入epoll监听队列。<br />至此，整个流程完成。<br />虽然还有很多地方不懂，但总算了解了大体流程了。以上分析不保证正确，仅供参考，仅作为个人学习笔记，欢迎指正。</p><img src ="http://www.cppblog.com/ifeng/aggbug/156948.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ifeng/" target="_blank">冷锋</a> 2011-09-27 11:26 <a href="http://www.cppblog.com/ifeng/archive/2011/09/27/156948.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>