<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>idea&#039;s blog &#187; Computer System</title>
	<atom:link href="http://www.ideawu.net/blog/category/computer-system/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ideawu.net/blog</link>
	<description>网络服务器架构, Linux C/C++服务器端开发, TCP/IP网络协议, PHP Web后端和Web前端开发, 网站架构.</description>
	<lastBuildDate>Wed, 08 Feb 2012 10:02:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Fn和CTRL的故事</title>
		<link>http://www.ideawu.net/blog/archives/614.html</link>
		<comments>http://www.ideawu.net/blog/archives/614.html#comments</comments>
		<pubDate>Fri, 05 Aug 2011 14:55:50 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/2011/08/fn%e5%92%8cctrl%e7%9a%84%e6%95%85%e4%ba%8b.html</guid>
		<description><![CDATA[<p>从前, 键盘工程师新创造了一个叫&#8221;Fn&#8221;的人造人, 想把它加入到键盘按键的队伍里. 工程师想, 它是一个革命性的产品, 因为, 它功能强大, 这从它的名字就能看出它的工程师老母对它的期望. 它可以帮忙打开键盘灯, 这样, 在黑暗中你也可以使用笔记本电脑. 它还可以帮忙调整屏幕亮度, 调整音量, 真是一个强大贴心的助手. 所以, 工程师决定把它放到了原来一个叫&#8221;CTRL&#8221;的人的位置, 把CTRL排挤到了一边. 那是键盘上最左下角的地方, 也是手指流量最密集的地方.</p>
<p>但是, Fn并不受欢迎, 因为没有人经常需要, 没有人天天不停地打开和关闭键盘灯, 即使好几年下来有一天遇到了, 先开灯或者在进入黑暗之前打开键盘灯也很正常.</p>
<p>相反, 人们怀念CTRL, 因为人们每天要把手指放在CTRL上面上千遍:</p>
<p>CTRL + C: 复制<br />
CTRL + V: 粘贴<br />
CTRL + S: 保存<br />
CTRL + A: 全选<br />
CTRL + X: 剪切<br />
CTRL + W: 关闭窗口<br />
CTRL + T: 打开浏览器标签<br />
CTRL + 空格: 切换输入法</p>
<p>对比Fn, Fn用不了一两回. 因为那些自以为是很内裤的功能, 其实都是和硬件有关, 根本就不常用到. 比如谁会没事按Fn让自己的键盘灯一亮一灭的, 或者没完没了地调整屏幕亮度和音量, 他有病啊!</p>
<p>大部分的电脑厂商都明白了这个道理, 绝情地把Fn赶走了, 重新迎回CTRL. 但是, 有一个叫IBM的巨人和它的买主还是坚持迂腐, 感情上不愿意把CTRL接回来, 最终决定帮人在BIOS里偷偷给Fn和CTRL换了衣服.</p>
<p>Fn垂头丧气, 成了不受欢迎的失败产品. 现在, 它在寻找一个最不起眼的角落, 想静地躺在那里, 不要像以前那么招摇.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/512.html' rel='bookmark' title='Permanent Link: screen 命令使用'>screen 命令使用</a></li>
<li><a href='http://www.ideawu.net/blog/archives/42.html' rel='bookmark' title='Permanent Link: Linux不是Windows'>Linux不是Windows</a></li>
<li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
<li><a href='http://www.ideawu.net/blog/archives/391.html' rel='bookmark' title='Permanent Link: 一对多关系的不稳定性'>一对多关系的不稳定性</a></li>
<li><a href='http://www.ideawu.net/blog/archives/329.html' rel='bookmark' title='Permanent Link: 一种有趣的编程模型'>一种有趣的编程模型</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/614.html" title="Fn和CTRL的故事">Fn和CTRL的故事</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>从前, 键盘工程师新创造了一个叫&#8221;Fn&#8221;的人造人, 想把它加入到键盘按键的队伍里. 工程师想, 它是一个革命性的产品, 因为, 它功能强大, 这从它的名字就能看出它的工程师老母对它的期望. 它可以帮忙打开键盘灯, 这样, 在黑暗中你也可以使用笔记本电脑. 它还可以帮忙调整屏幕亮度, 调整音量, 真是一个强大贴心的助手. 所以, 工程师决定把它放到了原来一个叫&#8221;CTRL&#8221;的人的位置, 把CTRL排挤到了一边. 那是键盘上最左下角的地方, 也是手指流量最密集的地方.</p>
<p>但是, Fn并不受欢迎, 因为没有人经常需要, 没有人天天不停地打开和关闭键盘灯, 即使好几年下来有一天遇到了, 先开灯或者在进入黑暗之前打开键盘灯也很正常.</p>
<p>相反, 人们怀念CTRL, 因为人们每天要把手指放在CTRL上面上千遍:</p>
<p>CTRL + C: 复制<br />
CTRL + V: 粘贴<br />
CTRL + S: 保存<br />
CTRL + A: 全选<br />
CTRL + X: 剪切<br />
CTRL + W: 关闭窗口<br />
CTRL + T: 打开浏览器标签<br />
CTRL + 空格: 切换输入法</p>
<p>对比Fn, Fn用不了一两回. 因为那些自以为是很内裤的功能, 其实都是和硬件有关, 根本就不常用到. 比如谁会没事按Fn让自己的键盘灯一亮一灭的, 或者没完没了地调整屏幕亮度和音量, 他有病啊!</p>
<p>大部分的电脑厂商都明白了这个道理, 绝情地把Fn赶走了, 重新迎回CTRL. 但是, 有一个叫IBM的巨人和它的买主还是坚持迂腐, 感情上不愿意把CTRL接回来, 最终决定帮人在BIOS里偷偷给Fn和CTRL换了衣服.</p>
<p>Fn垂头丧气, 成了不受欢迎的失败产品. 现在, 它在寻找一个最不起眼的角落, 想静地躺在那里, 不要像以前那么招摇.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/512.html' rel='bookmark' title='Permanent Link: screen 命令使用'>screen 命令使用</a></li>
<li><a href='http://www.ideawu.net/blog/archives/42.html' rel='bookmark' title='Permanent Link: Linux不是Windows'>Linux不是Windows</a></li>
<li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
<li><a href='http://www.ideawu.net/blog/archives/391.html' rel='bookmark' title='Permanent Link: 一对多关系的不稳定性'>一对多关系的不稳定性</a></li>
<li><a href='http://www.ideawu.net/blog/archives/329.html' rel='bookmark' title='Permanent Link: 一种有趣的编程模型'>一种有趣的编程模型</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/614.html" title="Fn和CTRL的故事">Fn和CTRL的故事</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/614.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>概率选取的实现</title>
		<link>http://www.ideawu.net/blog/archives/610.html</link>
		<comments>http://www.ideawu.net/blog/archives/610.html#comments</comments>
		<pubDate>Wed, 03 Aug 2011 01:02:49 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/2011/08/%e6%a6%82%e7%8e%87%e9%80%89%e5%8f%96%e7%9a%84%e5%ae%9e%e7%8e%b0.html</guid>
		<description><![CDATA[<p>常常有这样的功能需求: 每次从一批候选项中随机选取其中一项, 要求每一项的出现都有一定的概率. 比如说, 有如下候选项和对应的概率: A:10%, B:5%, C:25%, D:60%.</p>
<p>现在, 把每一项的概率用一个正整数(概率值)来表示, 不使用百分率, 整数的总和不一定等于100, 可以是任意大小,</p>
<pre>实际概率 = 概率值/总和 * 100%</pre>
<p>概率选取的算法如下:</p>
<ul>
<li>依次(顺序可随机)将各项按概率值从原点开始放在一维坐标上首尾相连, 这样, 每一项对应一个取值区间</li>
<li>在总区间范围内随机选取一个点, 落在哪一项对应的区间就选中哪一项</li>
</ul>
<p>用伪码表示:</p>
<pre>
total_p = sum(p1 + p2 + p3 + ...)
rand = random(1, total_p) // [1, total_p]
foreach(items as item){
    rand -= item.p
    if(rand &lt;= 0){
        // 选中了
    }
}
</pre>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/302.html' rel='bookmark' title='Permanent Link: 生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论'>生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论</a></li>
<li><a href='http://www.ideawu.net/blog/archives/438.html' rel='bookmark' title='Permanent Link: PHP中使用foreach和引用导致程序BUG'>PHP中使用foreach和引用导致程序BUG</a></li>
<li><a href='http://www.ideawu.net/blog/archives/202.html' rel='bookmark' title='Permanent Link: 写自己的 http_build_query'>写自己的 http_build_query</a></li>
<li><a href='http://www.ideawu.net/blog/archives/495.html' rel='bookmark' title='Permanent Link: 开发搜索引擎 &#8211; PHP中文分词'>开发搜索引擎 &#8211; PHP中文分词</a></li>
<li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/610.html" title="概率选取的实现">概率选取的实现</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>常常有这样的功能需求: 每次从一批候选项中随机选取其中一项, 要求每一项的出现都有一定的概率. 比如说, 有如下候选项和对应的概率: A:10%, B:5%, C:25%, D:60%.</p>
<p>现在, 把每一项的概率用一个正整数(概率值)来表示, 不使用百分率, 整数的总和不一定等于100, 可以是任意大小,</p>
<pre>实际概率 = 概率值/总和 * 100%</pre>
<p>概率选取的算法如下:</p>
<ul>
<li>依次(顺序可随机)将各项按概率值从原点开始放在一维坐标上首尾相连, 这样, 每一项对应一个取值区间</li>
<li>在总区间范围内随机选取一个点, 落在哪一项对应的区间就选中哪一项</li>
</ul>
<p>用伪码表示:</p>
<pre>
total_p = sum(p1 + p2 + p3 + ...)
rand = random(1, total_p) // [1, total_p]
foreach(items as item){
    rand -= item.p
    if(rand &lt;= 0){
        // 选中了
    }
}
</pre>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/302.html' rel='bookmark' title='Permanent Link: 生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论'>生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论</a></li>
<li><a href='http://www.ideawu.net/blog/archives/438.html' rel='bookmark' title='Permanent Link: PHP中使用foreach和引用导致程序BUG'>PHP中使用foreach和引用导致程序BUG</a></li>
<li><a href='http://www.ideawu.net/blog/archives/202.html' rel='bookmark' title='Permanent Link: 写自己的 http_build_query'>写自己的 http_build_query</a></li>
<li><a href='http://www.ideawu.net/blog/archives/495.html' rel='bookmark' title='Permanent Link: 开发搜索引擎 &#8211; PHP中文分词'>开发搜索引擎 &#8211; PHP中文分词</a></li>
<li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/610.html" title="概率选取的实现">概率选取的实现</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/610.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>关系数据库应用设计基础</title>
		<link>http://www.ideawu.net/blog/archives/606.html</link>
		<comments>http://www.ideawu.net/blog/archives/606.html#comments</comments>
		<pubDate>Fri, 24 Jun 2011 10:02:57 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/2011/06/%e5%85%b3%e7%b3%bb%e6%95%b0%e6%8d%ae%e5%ba%93%e5%ba%94%e7%94%a8%e8%ae%be%e8%ae%a1%e5%9f%ba%e7%a1%80.html</guid>
		<description><![CDATA[<p>这是我给部门同事做的技术分享.</p>
<p>当今绝大部分的软件系统都用到了关系数据库, 所以, 作为软件开发工程师, 必须掌握关系数据库应用设计能力.</p>
<div style="width:425px" id="__ss_8410690"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ideawu/ss-8410690" title="关系数据库应用设计基础">关系数据库应用设计基础</a></strong> <object id="__sse8410690" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-110624045756-phpapp02&#038;stripped_title=ss-8410690&#038;userName=ideawu" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse8410690" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-110624045756-phpapp02&#038;stripped_title=ss-8410690&#038;userName=ideawu" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ideawu">ideawu</a> </div>
</p></div>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/589.html' rel='bookmark' title='Permanent Link: 高性能并发Web服务器实现核心内幕'>高性能并发Web服务器实现核心内幕</a></li>
<li><a href='http://www.ideawu.net/blog/archives/482.html' rel='bookmark' title='Permanent Link: 开发爬虫友好的Ajax网站'>开发爬虫友好的Ajax网站</a></li>
<li><a href='http://www.ideawu.net/blog/archives/364.html' rel='bookmark' title='Permanent Link: [不会停止]idea&#8217;s blog 即将停止了&#8230;'>[不会停止]idea&#8217;s blog 即将停止了&#8230;</a></li>
<li><a href='http://www.ideawu.net/blog/archives/355.html' rel='bookmark' title='Permanent Link: 朋友在中关村买华硕笔记本被骗'>朋友在中关村买华硕笔记本被骗</a></li>
<li><a href='http://www.ideawu.net/blog/archives/585.html' rel='bookmark' title='Permanent Link: 史上最强大的PHP Web面试题(会做就能进百度)'>史上最强大的PHP Web面试题(会做就能进百度)</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/606.html" title="关系数据库应用设计基础">关系数据库应用设计基础</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>这是我给部门同事做的技术分享.</p>
<p>当今绝大部分的软件系统都用到了关系数据库, 所以, 作为软件开发工程师, 必须掌握关系数据库应用设计能力.</p>
<div style="width:425px" id="__ss_8410690"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/ideawu/ss-8410690" title="关系数据库应用设计基础">关系数据库应用设计基础</a></strong> <object id="__sse8410690" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-110624045756-phpapp02&#038;stripped_title=ss-8410690&#038;userName=ideawu" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse8410690" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-110624045756-phpapp02&#038;stripped_title=ss-8410690&#038;userName=ideawu" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/ideawu">ideawu</a> </div>
</p></div>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/589.html' rel='bookmark' title='Permanent Link: 高性能并发Web服务器实现核心内幕'>高性能并发Web服务器实现核心内幕</a></li>
<li><a href='http://www.ideawu.net/blog/archives/482.html' rel='bookmark' title='Permanent Link: 开发爬虫友好的Ajax网站'>开发爬虫友好的Ajax网站</a></li>
<li><a href='http://www.ideawu.net/blog/archives/364.html' rel='bookmark' title='Permanent Link: [不会停止]idea&#8217;s blog 即将停止了&#8230;'>[不会停止]idea&#8217;s blog 即将停止了&#8230;</a></li>
<li><a href='http://www.ideawu.net/blog/archives/355.html' rel='bookmark' title='Permanent Link: 朋友在中关村买华硕笔记本被骗'>朋友在中关村买华硕笔记本被骗</a></li>
<li><a href='http://www.ideawu.net/blog/archives/585.html' rel='bookmark' title='Permanent Link: 史上最强大的PHP Web面试题(会做就能进百度)'>史上最强大的PHP Web面试题(会做就能进百度)</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/606.html" title="关系数据库应用设计基础">关系数据库应用设计基础</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/606.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>史上最强大的PHP Web面试题(会做就能进百度)</title>
		<link>http://www.ideawu.net/blog/archives/585.html</link>
		<comments>http://www.ideawu.net/blog/archives/585.html#comments</comments>
		<pubDate>Thu, 31 Mar 2011 08:57:24 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[IT技术和评论]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[程序员]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=585</guid>
		<description><![CDATA[<p><img src="http://www.ideawu.net/blog/wp-content/uploads/2011/03/cat_tree.jpg" alt="" title="cat_tree" width="246" height="364" class="alignright size-full wp-image-586" /></p>
<blockquote><p>
<strong>注:</strong> 只要你会做了这道题目, 你的能力已经可以进入百度了! 如果别的部门不要你, 请你给我发邮件, 我一定尽我所能强烈推荐你! 如果你不想加入百度, 而别的公司又不要你, 只能说明那家公司瞎眼了.
</p></blockquote>
<p><strong>题目:</strong> 见图片, 该图是某网页的一个区域的截图, 用于显示商品或者其它信息的分类. 该分类的每一项可以折叠和收起(展开和收缩, 如果有子分类的话). 分类的级数不固定. 现有一个PHP变量:</p>
<pre>
$cats = array(
    array(
        'id' => 1,
        'name' => '学术和教育',
        'children' => array(
            array(
                'id' => 2,
                'name' => '自然科学',
                'children' => null,
            ),
            // ...
        ),
    ),
    // ...
);
</pre>
<p>请写一段PHP代码, 将该数组所包含的分类数据生成一段能实现如图片所示功能的HTML/JavaScript代码, 可不考虑CSS样式.</p>
<p>&#8212;&#8212;&#8212;-</p>
<p><strong>注解:</strong> 这道题目考察的范围非常广, 包括<a href="http://www.ideawu.net/blog/category/web/php">PHP</a>, HTML, <a href="http://www.ideawu.net/blog/tag/javascript">JavaScript</a>, CSS, <strong>递归</strong>, 只有真正掌握了如上几种全部技能, 才能实现完整的功能, 否则必须依赖分工. 应聘者所能实现的程度越大, 得分就越高.</p>
<p>如果应聘者的应聘职位不包括HTML/JS/CSS, 那么题目可改为: 把上面的PHP数据用缩进换行文本的形式保存到文件, 并读取文件生成一个同样的PHP数组.(自定义格式的序列化和反序列化)</p>
<p><strong>看到这篇日志的读者, 如果已经做了出来, 并且个人想加入百度, 请在评论中回复URL并说明你的意愿, 我会主动联系你. 或者你可以把程序打包发给我.</strong></p>
<p><span id="more-585"></span><br />
&#8212;&#8212;&#8212;-</p>
<ul style="font-size:15px;background:#dfd;">
<li><a href="http://www.ideawu.net/blog/archives/536.html"><strong>应届生如何成功应聘百度</strong></a></li>
<li><a href="http://www.ideawu.net/blog/archives/481.html"><strong>PHP和百度招聘</strong></a></li>
</ul>
Note: There is a poll embedded within this post, please visit the site to participate in this post's poll.


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/351.html' rel='bookmark' title='Permanent Link: 史上最强大的PHP MySQL操作类'>史上最强大的PHP MySQL操作类</a></li>
<li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
<li><a href='http://www.ideawu.net/blog/archives/399.html' rel='bookmark' title='Permanent Link: JavaScript+jQuery两栏选择控件'>JavaScript+jQuery两栏选择控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/93.html' rel='bookmark' title='Permanent Link: 国内外一些计算机学习资源的链接'>国内外一些计算机学习资源的链接</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/585.html" title="史上最强大的PHP Web面试题(会做就能进百度)">史上最强大的PHP Web面试题(会做就能进百度)</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.ideawu.net/blog/wp-content/uploads/2011/03/cat_tree.jpg" alt="" title="cat_tree" width="246" height="364" class="alignright size-full wp-image-586" /></p>
<blockquote><p>
<strong>注:</strong> 只要你会做了这道题目, 你的能力已经可以进入百度了! 如果别的部门不要你, 请你给我发邮件, 我一定尽我所能强烈推荐你! 如果你不想加入百度, 而别的公司又不要你, 只能说明那家公司瞎眼了.
</p></blockquote>
<p><strong>题目:</strong> 见图片, 该图是某网页的一个区域的截图, 用于显示商品或者其它信息的分类. 该分类的每一项可以折叠和收起(展开和收缩, 如果有子分类的话). 分类的级数不固定. 现有一个PHP变量:</p>
<pre>
$cats = array(
    array(
        'id' => 1,
        'name' => '学术和教育',
        'children' => array(
            array(
                'id' => 2,
                'name' => '自然科学',
                'children' => null,
            ),
            // ...
        ),
    ),
    // ...
);
</pre>
<p>请写一段PHP代码, 将该数组所包含的分类数据生成一段能实现如图片所示功能的HTML/JavaScript代码, 可不考虑CSS样式.</p>
<p>&#8212;&#8212;&#8212;-</p>
<p><strong>注解:</strong> 这道题目考察的范围非常广, 包括<a href="http://www.ideawu.net/blog/category/web/php">PHP</a>, HTML, <a href="http://www.ideawu.net/blog/tag/javascript">JavaScript</a>, CSS, <strong>递归</strong>, 只有真正掌握了如上几种全部技能, 才能实现完整的功能, 否则必须依赖分工. 应聘者所能实现的程度越大, 得分就越高.</p>
<p>如果应聘者的应聘职位不包括HTML/JS/CSS, 那么题目可改为: 把上面的PHP数据用缩进换行文本的形式保存到文件, 并读取文件生成一个同样的PHP数组.(自定义格式的序列化和反序列化)</p>
<p><strong>看到这篇日志的读者, 如果已经做了出来, 并且个人想加入百度, 请在评论中回复URL并说明你的意愿, 我会主动联系你. 或者你可以把程序打包发给我.</strong></p>
<p><span id="more-585"></span><br />
&#8212;&#8212;&#8212;-</p>
<ul style="font-size:15px;background:#dfd;">
<li><a href="http://www.ideawu.net/blog/archives/536.html"><strong>应届生如何成功应聘百度</strong></a></li>
<li><a href="http://www.ideawu.net/blog/archives/481.html"><strong>PHP和百度招聘</strong></a></li>
</ul>
Note: There is a poll embedded within this post, please visit the site to participate in this post's poll.


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/351.html' rel='bookmark' title='Permanent Link: 史上最强大的PHP MySQL操作类'>史上最强大的PHP MySQL操作类</a></li>
<li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
<li><a href='http://www.ideawu.net/blog/archives/399.html' rel='bookmark' title='Permanent Link: JavaScript+jQuery两栏选择控件'>JavaScript+jQuery两栏选择控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/93.html' rel='bookmark' title='Permanent Link: 国内外一些计算机学习资源的链接'>国内外一些计算机学习资源的链接</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/585.html" title="史上最强大的PHP Web面试题(会做就能进百度)">史上最强大的PHP Web面试题(会做就能进百度)</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/585.html/feed</wfw:commentRss>
		<slash:comments>52</slash:comments>
		</item>
		<item>
		<title>主要排序算法的比较(精炼)</title>
		<link>http://www.ideawu.net/blog/archives/580.html</link>
		<comments>http://www.ideawu.net/blog/archives/580.html#comments</comments>
		<pubDate>Thu, 17 Feb 2011 08:57:21 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/580.html</guid>
		<description><![CDATA[<p>来自: <a href="http://en.wikipedia.org/wiki/Heapsort#Comparison_with_other_sorts">Wikipedia</a></p>
<blockquote>
<p>Heapsort primarily competes with <a href="/wiki/Quicksort">quicksort</a>, another very efficient general purpose nearly-in-place comparison-based sort algorithm.</p>
<p>Quicksort is typically somewhat faster, due to better cache behavior and other factors, but the worst-case running time for quicksort is <a href="/wiki/Big_O_notation" title="Big O notation">O</a>(<i>n</i><sup>2</sup>), which is unacceptable for large data sets and can be deliberately triggered given enough knowledge of the implementation, creating a security risk. See <a href="/wiki/Quicksort">quicksort</a> for a detailed discussion of this problem, and possible solutions.</p>
<p>Thus, because of the O(<i>n</i> log <i>n</i>) upper bound on heapsort&#8217;s running time and constant upper bound on its auxiliary storage, embedded systems with real-time constraints or systems concerned with security often use heapsort.</p>
<p>Heapsort also competes with <a href="/wiki/Merge_sort">merge sort</a>, which has the same time bounds, but requires Ω(n) auxiliary space, whereas heapsort requires only a constant amount. Heapsort also typically runs more quickly in practice on machines with small or slow <a href="/wiki/Data_cache" title="Data cache" class="mw-redirect">data caches</a>. On the other hand, merge sort has several advantages over heapsort:</p>
<ul>
<li>Like quicksort, merge sort on arrays has considerably better data cache performance, often outperforming heapsort on a modern desktop PC, because it accesses the elements in order.</li>
<li>Merge sort is a <a href="/wiki/Stable_sort" class="mw-redirect" title="Stable sort">stable sort</a>.</li>
<li>Merge sort <a href="/wiki/Parallel_algorithm" title="Parallel algorithm">parallelizes better</a>; the most trivial way of parallelizing merge sort achieves close to <a href="/wiki/Linear_speedup" class="mw-redirect" title="Linear speedup">linear speedup</a>, while there is no obvious way to parallelize heapsort at all.</li>
<li>Merge sort can be easily adapted to operate on <a href="/wiki/Linked_list" title="Linked list">linked lists</a> (with O(1) extra space<sup id="cite_ref-6" class="reference"><a href="#cite_note-6"><span>[</span>7<span>]</span></a></sup>) and very large lists stored on slow-to-access media such as <a href="/wiki/Disk_storage">disk storage</a> or <a href="/wiki/Network_attached_storage" class="mw-redirect" title="Network attached storage">network attached storage</a>. Heapsort relies strongly on <a href="/wiki/Random_access">random access</a>, and its poor <a href="/wiki/Locality_of_reference">locality of reference</a> makes it very slow on media with long access times. (Note: Heapsort can also be applied to doubly linked lists with only O(1) extra space overhead)</li>
</ul>
<p><a href="/wiki/Introsort">Introsort</a> is an interesting alternative to heapsort that combines quicksort and heapsort to retain advantages of both: worst case speed of heapsort and average speed of quicksort.</p>
</blockquote>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/329.html' rel='bookmark' title='Permanent Link: 一种有趣的编程模型'>一种有趣的编程模型</a></li>
<li><a href='http://www.ideawu.net/blog/archives/365.html' rel='bookmark' title='Permanent Link: C#环形缓冲'>C#环形缓冲</a></li>
<li><a href='http://www.ideawu.net/blog/archives/202.html' rel='bookmark' title='Permanent Link: 写自己的 http_build_query'>写自己的 http_build_query</a></li>
<li><a href='http://www.ideawu.net/blog/archives/114.html' rel='bookmark' title='Permanent Link: 艾薇儿Avril Lavigne的照片'>艾薇儿Avril Lavigne的照片</a></li>
<li><a href='http://www.ideawu.net/blog/archives/503.html' rel='bookmark' title='Permanent Link: 请提供Fuck-All选项'>请提供Fuck-All选项</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/580.html" title="主要排序算法的比较(精炼)">主要排序算法的比较(精炼)</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>来自: <a href="http://en.wikipedia.org/wiki/Heapsort#Comparison_with_other_sorts">Wikipedia</a></p>
<blockquote>
<p>Heapsort primarily competes with <a href="/wiki/Quicksort">quicksort</a>, another very efficient general purpose nearly-in-place comparison-based sort algorithm.</p>
<p>Quicksort is typically somewhat faster, due to better cache behavior and other factors, but the worst-case running time for quicksort is <a href="/wiki/Big_O_notation" title="Big O notation">O</a>(<i>n</i><sup>2</sup>), which is unacceptable for large data sets and can be deliberately triggered given enough knowledge of the implementation, creating a security risk. See <a href="/wiki/Quicksort">quicksort</a> for a detailed discussion of this problem, and possible solutions.</p>
<p>Thus, because of the O(<i>n</i> log <i>n</i>) upper bound on heapsort&#8217;s running time and constant upper bound on its auxiliary storage, embedded systems with real-time constraints or systems concerned with security often use heapsort.</p>
<p>Heapsort also competes with <a href="/wiki/Merge_sort">merge sort</a>, which has the same time bounds, but requires Ω(n) auxiliary space, whereas heapsort requires only a constant amount. Heapsort also typically runs more quickly in practice on machines with small or slow <a href="/wiki/Data_cache" title="Data cache" class="mw-redirect">data caches</a>. On the other hand, merge sort has several advantages over heapsort:</p>
<ul>
<li>Like quicksort, merge sort on arrays has considerably better data cache performance, often outperforming heapsort on a modern desktop PC, because it accesses the elements in order.</li>
<li>Merge sort is a <a href="/wiki/Stable_sort" class="mw-redirect" title="Stable sort">stable sort</a>.</li>
<li>Merge sort <a href="/wiki/Parallel_algorithm" title="Parallel algorithm">parallelizes better</a>; the most trivial way of parallelizing merge sort achieves close to <a href="/wiki/Linear_speedup" class="mw-redirect" title="Linear speedup">linear speedup</a>, while there is no obvious way to parallelize heapsort at all.</li>
<li>Merge sort can be easily adapted to operate on <a href="/wiki/Linked_list" title="Linked list">linked lists</a> (with O(1) extra space<sup id="cite_ref-6" class="reference"><a href="#cite_note-6"><span>[</span>7<span>]</span></a></sup>) and very large lists stored on slow-to-access media such as <a href="/wiki/Disk_storage">disk storage</a> or <a href="/wiki/Network_attached_storage" class="mw-redirect" title="Network attached storage">network attached storage</a>. Heapsort relies strongly on <a href="/wiki/Random_access">random access</a>, and its poor <a href="/wiki/Locality_of_reference">locality of reference</a> makes it very slow on media with long access times. (Note: Heapsort can also be applied to doubly linked lists with only O(1) extra space overhead)</li>
</ul>
<p><a href="/wiki/Introsort">Introsort</a> is an interesting alternative to heapsort that combines quicksort and heapsort to retain advantages of both: worst case speed of heapsort and average speed of quicksort.</p>
</blockquote>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/329.html' rel='bookmark' title='Permanent Link: 一种有趣的编程模型'>一种有趣的编程模型</a></li>
<li><a href='http://www.ideawu.net/blog/archives/365.html' rel='bookmark' title='Permanent Link: C#环形缓冲'>C#环形缓冲</a></li>
<li><a href='http://www.ideawu.net/blog/archives/202.html' rel='bookmark' title='Permanent Link: 写自己的 http_build_query'>写自己的 http_build_query</a></li>
<li><a href='http://www.ideawu.net/blog/archives/114.html' rel='bookmark' title='Permanent Link: 艾薇儿Avril Lavigne的照片'>艾薇儿Avril Lavigne的照片</a></li>
<li><a href='http://www.ideawu.net/blog/archives/503.html' rel='bookmark' title='Permanent Link: 请提供Fuck-All选项'>请提供Fuck-All选项</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/580.html" title="主要排序算法的比较(精炼)">主要排序算法的比较(精炼)</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/580.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>以浏览器为核心的客户端软件的安全问题</title>
		<link>http://www.ideawu.net/blog/archives/542.html</link>
		<comments>http://www.ideawu.net/blog/archives/542.html#comments</comments>
		<pubDate>Wed, 22 Sep 2010 03:19:39 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/542.html</guid>
		<description><![CDATA[<p>以浏览器为核心的客户端软件具有开发快速, 并且能使用浏览器的各种特性(如js脚本, flash插件等), 所以越来越多的客户端软件开始应用浏览器作为软件的界面渲染引擎.</p>
<p>但是, 浏览器也是安全问题最多的软件之一. 因其应用广泛, 导致攻击方法层出不穷. 前段时间, QQ客户端的某个版本就遇到了这个问题. 这个版本的QQ使用IE作为聊天记录的界面引擎, 似乎由于疏忽的原因, 没有对聊天信息中的HTML标签进行过滤, 导致用户可以通过在聊天信息中包含JavaScript脚本, 从而在对方机器上执行.</p>
<p>例如:</p>
<pre>
&lt;script type="text/javascript"&gt;alert('hahaha');&lt;/script&gt;
</pre>
<p>用户打开聊天历史记录时, 便会弹出一个窗口, 显示&#8221;hahaha&#8221;. 还有嵌入iframe的:</p>
<pre>
&lt;iframe src="http://some" width="100%" height="400"&gt;&lt;/iframe&gt;
</pre>
<p>这样, 用户在打开聊天历史记录时, 却看到了一个网页, 而这个网页可能是挂马的.</p>
<p>所以, 使用浏览器为核心的客户端软件, 必须重视安全问题, 要对发给浏览器渲染的所有字符进行过滤. 最好的方法是使用一种模板语言, 简单的如ubb, 而不是直接使用HTML.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/611.html' rel='bookmark' title='Permanent Link: 强大的纯JS数据图工具-flot'>强大的纯JS数据图工具-flot</a></li>
<li><a href='http://www.ideawu.net/blog/archives/212.html' rel='bookmark' title='Permanent Link: [转]一个叫做家的地方'>[转]一个叫做家的地方</a></li>
<li><a href='http://www.ideawu.net/blog/archives/219.html' rel='bookmark' title='Permanent Link: 用Javascript生成弹出窗口'>用Javascript生成弹出窗口</a></li>
<li><a href='http://www.ideawu.net/blog/archives/399.html' rel='bookmark' title='Permanent Link: JavaScript+jQuery两栏选择控件'>JavaScript+jQuery两栏选择控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/542.html" title="以浏览器为核心的客户端软件的安全问题">以浏览器为核心的客户端软件的安全问题</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>以浏览器为核心的客户端软件具有开发快速, 并且能使用浏览器的各种特性(如js脚本, flash插件等), 所以越来越多的客户端软件开始应用浏览器作为软件的界面渲染引擎.</p>
<p>但是, 浏览器也是安全问题最多的软件之一. 因其应用广泛, 导致攻击方法层出不穷. 前段时间, QQ客户端的某个版本就遇到了这个问题. 这个版本的QQ使用IE作为聊天记录的界面引擎, 似乎由于疏忽的原因, 没有对聊天信息中的HTML标签进行过滤, 导致用户可以通过在聊天信息中包含JavaScript脚本, 从而在对方机器上执行.</p>
<p>例如:</p>
<pre>
&lt;script type="text/javascript"&gt;alert('hahaha');&lt;/script&gt;
</pre>
<p>用户打开聊天历史记录时, 便会弹出一个窗口, 显示&#8221;hahaha&#8221;. 还有嵌入iframe的:</p>
<pre>
&lt;iframe src="http://some" width="100%" height="400"&gt;&lt;/iframe&gt;
</pre>
<p>这样, 用户在打开聊天历史记录时, 却看到了一个网页, 而这个网页可能是挂马的.</p>
<p>所以, 使用浏览器为核心的客户端软件, 必须重视安全问题, 要对发给浏览器渲染的所有字符进行过滤. 最好的方法是使用一种模板语言, 简单的如ubb, 而不是直接使用HTML.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/611.html' rel='bookmark' title='Permanent Link: 强大的纯JS数据图工具-flot'>强大的纯JS数据图工具-flot</a></li>
<li><a href='http://www.ideawu.net/blog/archives/212.html' rel='bookmark' title='Permanent Link: [转]一个叫做家的地方'>[转]一个叫做家的地方</a></li>
<li><a href='http://www.ideawu.net/blog/archives/219.html' rel='bookmark' title='Permanent Link: 用Javascript生成弹出窗口'>用Javascript生成弹出窗口</a></li>
<li><a href='http://www.ideawu.net/blog/archives/399.html' rel='bookmark' title='Permanent Link: JavaScript+jQuery两栏选择控件'>JavaScript+jQuery两栏选择控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/606.html' rel='bookmark' title='Permanent Link: 关系数据库应用设计基础'>关系数据库应用设计基础</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/542.html" title="以浏览器为核心的客户端软件的安全问题">以浏览器为核心的客户端软件的安全问题</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/542.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>没见过比svn更难用的工具</title>
		<link>http://www.ideawu.net/blog/archives/540.html</link>
		<comments>http://www.ideawu.net/blog/archives/540.html#comments</comments>
		<pubDate>Thu, 09 Sep 2010 05:35:12 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/540.html</guid>
		<description><![CDATA[<p>我的需求很简单, diff 某个版本和我当前的代码, 正常应该是</p>
<p>svn diff url_xxx .(这样操作方式和diff命令一致)</p>
<p>url_xxx 就是那个版本的路径, 点号&#8221;.&#8221;就是当前目录, 没想到竟然不行! 太弱智的东西了! 真正的用法是:</p>
<p>svn diff &#8211;new url_xxx &#8211;old .<strong>(这样不对, 因为顺序弄反了!)</strong></p>
<p><strong>正确的是</strong></p>
<p>svn diff &#8211;old url_xxx &#8211;new .</p>
<p>svn 从来就是这么弱智, 比如这一篇文章: <a href="http://www.ideawu.net/blog/archives/503.html"> 请提供Fuck-All选项</a></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/432.html' rel='bookmark' title='Permanent Link: 如何为Linux生成和打上patch'>如何为Linux生成和打上patch</a></li>
<li><a href='http://www.ideawu.net/blog/archives/116.html' rel='bookmark' title='Permanent Link: 告诉我应该选择哪一个Linux发行版'>告诉我应该选择哪一个Linux发行版</a></li>
<li><a href='http://www.ideawu.net/blog/archives/415.html' rel='bookmark' title='Permanent Link: CVS笔记'>CVS笔记</a></li>
<li><a href='http://www.ideawu.net/blog/archives/503.html' rel='bookmark' title='Permanent Link: 请提供Fuck-All选项'>请提供Fuck-All选项</a></li>
<li><a href='http://www.ideawu.net/blog/archives/264.html' rel='bookmark' title='Permanent Link: 通过 HTTP POST 发送二进制数据'>通过 HTTP POST 发送二进制数据</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/540.html" title="没见过比svn更难用的工具">没见过比svn更难用的工具</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>我的需求很简单, diff 某个版本和我当前的代码, 正常应该是</p>
<p>svn diff url_xxx .(这样操作方式和diff命令一致)</p>
<p>url_xxx 就是那个版本的路径, 点号&#8221;.&#8221;就是当前目录, 没想到竟然不行! 太弱智的东西了! 真正的用法是:</p>
<p>svn diff &#8211;new url_xxx &#8211;old .<strong>(这样不对, 因为顺序弄反了!)</strong></p>
<p><strong>正确的是</strong></p>
<p>svn diff &#8211;old url_xxx &#8211;new .</p>
<p>svn 从来就是这么弱智, 比如这一篇文章: <a href="http://www.ideawu.net/blog/archives/503.html"> 请提供Fuck-All选项</a></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/432.html' rel='bookmark' title='Permanent Link: 如何为Linux生成和打上patch'>如何为Linux生成和打上patch</a></li>
<li><a href='http://www.ideawu.net/blog/archives/116.html' rel='bookmark' title='Permanent Link: 告诉我应该选择哪一个Linux发行版'>告诉我应该选择哪一个Linux发行版</a></li>
<li><a href='http://www.ideawu.net/blog/archives/415.html' rel='bookmark' title='Permanent Link: CVS笔记'>CVS笔记</a></li>
<li><a href='http://www.ideawu.net/blog/archives/503.html' rel='bookmark' title='Permanent Link: 请提供Fuck-All选项'>请提供Fuck-All选项</a></li>
<li><a href='http://www.ideawu.net/blog/archives/264.html' rel='bookmark' title='Permanent Link: 通过 HTTP POST 发送二进制数据'>通过 HTTP POST 发送二进制数据</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/540.html" title="没见过比svn更难用的工具">没见过比svn更难用的工具</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/540.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Lighttpd mod_fastcgi源码分析</title>
		<link>http://www.ideawu.net/blog/archives/537.html</link>
		<comments>http://www.ideawu.net/blog/archives/537.html#comments</comments>
		<pubDate>Sun, 29 Aug 2010 10:00:51 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[高性能Web架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/537.html</guid>
		<description><![CDATA[<p>最近在设计一种网络服务器架构, 最重要的一点是把耗时操作委托给工作进程(或者线程)来做, 所以考察一下 <a href="http://www.fastcgi.com/">fastcgi</a>. 大概看了下 <a href="http://www.lighttpd.net/">lighttpd</a> 的 mod_fastcgi 的源码, 没想到立即被卡住了. 根据我的想法, PHP 等 fastcgi 程序(php-cgi 进程)监听网络, 然后 mod_fastcgi 只需要 connect 这些进程即可, 奇怪的是, 我竟然看到了 listen! -</p>
<pre>
fcgi_spawn_connection() 函数:

fcgi_fd = socket(socket_type, SOCK_STREAM, 0);

if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
    close(fcgi_fd);
    fcgi_fd = socket(socket_type, SOCK_STREAM, 0);
    /* create socket */
    bind(fcgi_fd, fcgi_addr, servlen);
    <b>listen(fcgi_fd, 1024);</b>

    switch ((child = fork())) {
    case 0: {
        // child process
        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
            close(FCGI_LISTENSOCK_FILENO);
            <b>dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);</b>
            close(fcgi_fd);
        }
        /* exec the cgi */
        <b>execve</b>(arg.ptr[0], arg.ptr, env.ptr);
        exit(errno);
    }
}
</pre>
<p>我很奇怪, mod_fastcgi 为什么要监听网络连接? 谁会连接它? 问了同事, 同事说可能是 fastcgi 进程要连接它, 可问题是 fastcgi 进程怎么知道连接什么地方, 更不用说, fastcgi 协议里没有提到要 fastcgi 进程主动连接 Web Server 一说.</p>
<p><span id="more-537"></span>再看一遍代码, 我注意到了 <a href="http://linux.die.net/man/2/dup2">dup2</a>() 调用, 会不会是 lighttpd 为 php-cgi 进程创建了一个监听 socket? 于是看了下 PHP fastcgi 的代码, 如下解析命令行参数的一段:</p>
<pre>
"  -b &lt;address:port&gt;|&lt;port&gt; Bind Path for external FASTCGI Server mode\n"
/* if we're started on command line, check to see if
   we are being started as an 'external' fastcgi
   server by accepting a bindpath parameter. */
case 'b':
...
if (bindpath) {
    fcgi_fd = fcgi_listen(bindpath, 128);
}
</pre>
<p>也就是说, 如果指定了 -b 选项, php-cgi 就会创建监听进程, 如果没有的话, fcgi_fd 就是默认的 0(标准输入的文件描述符), 也就是 FCGI_LISTENSOCK_FILENO.</p>
<p>所以, lighttpd mod_fastcgi 的逻辑是这样, 如果需要 spawn php-cgi 进程, 它会创建一个监听的 socket, 然后把该 socket dup2 到 标准输入的 fd, 接着 fork 并用 <a href="http://linux.die.net/man/2/execve">execve</a>() 函数执行 php-cgi 程序, 这样, php-cgi 程序就可以使用该监听 socket 来接受 mod_fastcgi 的网络连接了.</p>
<p>只要知道了这个逻辑, 细节问题不必深究.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
<li><a href='http://www.ideawu.net/blog/archives/290.html' rel='bookmark' title='Permanent Link: Ideawu.P2P API 简介'>Ideawu.P2P API 简介</a></li>
<li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/537.html" title="Lighttpd mod_fastcgi源码分析">Lighttpd mod_fastcgi源码分析</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>最近在设计一种网络服务器架构, 最重要的一点是把耗时操作委托给工作进程(或者线程)来做, 所以考察一下 <a href="http://www.fastcgi.com/">fastcgi</a>. 大概看了下 <a href="http://www.lighttpd.net/">lighttpd</a> 的 mod_fastcgi 的源码, 没想到立即被卡住了. 根据我的想法, PHP 等 fastcgi 程序(php-cgi 进程)监听网络, 然后 mod_fastcgi 只需要 connect 这些进程即可, 奇怪的是, 我竟然看到了 listen! -</p>
<pre>
fcgi_spawn_connection() 函数:

fcgi_fd = socket(socket_type, SOCK_STREAM, 0);

if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
    close(fcgi_fd);
    fcgi_fd = socket(socket_type, SOCK_STREAM, 0);
    /* create socket */
    bind(fcgi_fd, fcgi_addr, servlen);
    <b>listen(fcgi_fd, 1024);</b>

    switch ((child = fork())) {
    case 0: {
        // child process
        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
            close(FCGI_LISTENSOCK_FILENO);
            <b>dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);</b>
            close(fcgi_fd);
        }
        /* exec the cgi */
        <b>execve</b>(arg.ptr[0], arg.ptr, env.ptr);
        exit(errno);
    }
}
</pre>
<p>我很奇怪, mod_fastcgi 为什么要监听网络连接? 谁会连接它? 问了同事, 同事说可能是 fastcgi 进程要连接它, 可问题是 fastcgi 进程怎么知道连接什么地方, 更不用说, fastcgi 协议里没有提到要 fastcgi 进程主动连接 Web Server 一说.</p>
<p><span id="more-537"></span>再看一遍代码, 我注意到了 <a href="http://linux.die.net/man/2/dup2">dup2</a>() 调用, 会不会是 lighttpd 为 php-cgi 进程创建了一个监听 socket? 于是看了下 PHP fastcgi 的代码, 如下解析命令行参数的一段:</p>
<pre>
"  -b &lt;address:port&gt;|&lt;port&gt; Bind Path for external FASTCGI Server mode\n"
/* if we're started on command line, check to see if
   we are being started as an 'external' fastcgi
   server by accepting a bindpath parameter. */
case 'b':
...
if (bindpath) {
    fcgi_fd = fcgi_listen(bindpath, 128);
}
</pre>
<p>也就是说, 如果指定了 -b 选项, php-cgi 就会创建监听进程, 如果没有的话, fcgi_fd 就是默认的 0(标准输入的文件描述符), 也就是 FCGI_LISTENSOCK_FILENO.</p>
<p>所以, lighttpd mod_fastcgi 的逻辑是这样, 如果需要 spawn php-cgi 进程, 它会创建一个监听的 socket, 然后把该 socket dup2 到 标准输入的 fd, 接着 fork 并用 <a href="http://linux.die.net/man/2/execve">execve</a>() 函数执行 php-cgi 程序, 这样, php-cgi 程序就可以使用该监听 socket 来接受 mod_fastcgi 的网络连接了.</p>
<p>只要知道了这个逻辑, 细节问题不必深究.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
<li><a href='http://www.ideawu.net/blog/archives/290.html' rel='bookmark' title='Permanent Link: Ideawu.P2P API 简介'>Ideawu.P2P API 简介</a></li>
<li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/537.html" title="Lighttpd mod_fastcgi源码分析">Lighttpd mod_fastcgi源码分析</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/537.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Master-Workers 模式处理高负载</title>
		<link>http://www.ideawu.net/blog/archives/535.html</link>
		<comments>http://www.ideawu.net/blog/archives/535.html#comments</comments>
		<pubDate>Sun, 22 Aug 2010 08:03:57 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[P2P/Network]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=535</guid>
		<description><![CDATA[<p>对于高负载的网络服务器, 瓶颈几乎总是在等待 IO, 而 CPU 的计算能力往往不是最先遇到的问题. 你的服务器程序, 接收客户端的请求, 可能还要连接另一台网络服务器, 一起合作处理客户端的请求. 很多情况下, 你无法把客户端的连接以及与另一台服务器的连接统一处理, 不可避免地要出现等待. 这时, 只能使用多进程或者多线程.</p>
<p>Master-Workers(管理者-工作者)模式是处理这种情况的主要方式, 只要有 IO 等待或者其它耗时的操作, 都交互若干个工作者之一处理, 这样, 后续的请求不会被阻塞, 从而实现高负载.</p>
<p><b>目录:</b></p>
<ul>
<li><a href="#h-1">单进程(单线程)网络服务器的结构</a></li>
<li>
		<a href="#h-2">多进程工作者模式(Master-Workers)</a></p>
<ul>
<li><a href="#h-2-1">Master-Workers 双向通信(长连接之一)</a></li>
<li><a href="#h-2-2">Master-Workers 单向通信(短连接)</a></li>
<li><a href="#h-2-3">Master-Workers 双向通信(长连接之二)</a></li>
</ul>
</li>
</ul>
<p>下文中有时用&#8221;进程&#8221;一词同时指代进程和线程, 它们的区别主要考虑的是通信方式.<br />
<span id="more-535"></span></p>
<h2><a name="h-1">1. 单进程(单线程)网络服务器的结构</a></h2>
<p>单进程网络服务器使用 IO 多路利用接口 &#8211; select(<a href="http://linux.die.net/man/2/select">doc</a>)/<a href="http://www.xmailserver.org/linux-patches/nio-improve.html">epoll</a>(<a href="http://linux.die.net/man/4/epoll">doc</a>)/kqueue(<a href="http://www.freebsd.org/cgi/man.cgi?query=kqueue&#038;sektion=2">doc</a>) 等 &#8211; 等待网络连接的信号, 收到读信号后, 接收一个应用层报文(如HTTP请求或者其它自定义的报文), 处理, 然后返回响应. 结构如下:</p>
<pre>
// 主循环
while(1){
    events = select.wait(timeout=100ms)
    foreach(events as e){
        req = e.sock.recv()
        resp = server.process(req)
        e.sock.send(resp)
    }
}
</pre>
<p>很明显, 如果 process 方法处理的时间较长的话, 那么并发量就很小了, 因为下一个请求必须等待前一个被处理完毕之后才能处理. 这时候, 只能使用多进程或者多线程, 创建所谓的工作者(Worker)进程.</p>
<h2><a name="h-2">2. 多进程工作者模式(Master-Workers)</a></h2>
<p>首先有一个 IO 进程(称为 Master), 也就是循环执行 select 的那个进程. 另有若干个工作者进程(称为 worker), 等待 IO 进程把报文给它们. 这也是一种&#8221;生产者-消费者&#8221;的模型. 具体上, 到底 IO 进程应该把哪一层次的数据交给工作者, 是简单的字节数组, 还是应用层的报文, 不同的应用不同设计. 现在假设传递的是完整的应用层报文, 也就是说, IO 进程负责报文解析, 如果报文的解析只消耗极少的资源, 这是最佳的方式.</p>
<h3><a name="h-2-1">2.1 Master-Workers 双向通信(长连接之一)</a></h3>
<pre>
// 启动 10 个工作者
Workers = start_Workers(num=10)
// 主循环
while(1){
    resps = Workers.wait(Workers_timeout=10ms);
    if(resps.count > 0){
        foreach(resps as resp){
            resps.sock.send(resp)
        }
    }

    events = select.wait(select_timeout=10ms)
    if(events > 0){
        foreach(events as e){
            req = e.sock.recv()
            // 仅仅是委托, 会立即返回. 以后通过 Workers.wait() 获取响应.
            Workers.delegate(req)
        }
    }
}
</pre>
<p>Workers 的工作模式是:</p>
<pre>
while(1){
    req = req_queue.pop();
    resp = process(req)
    // 响应被加入到发送队列中
    resp_queue.push(resp)
}
</pre>
<p>wokers.wait 是等待工作者的处理结果事件(从响应队列中读取响应), 而 select.wait 是等待网络事件. 两者逻辑上相同. Workers 和 select 应该等待多久(即 timeout 的取值是多少)? 如果 Workers_timeout 太大, 那么就会导致 Workers_timeout 时间内即使有新的请求进来, 也无法及时处理, 因为 select.wait 还没被执行到. 相对比, 如果 select_timeout 太大, 那么又会导致 select_timeout 时间内响应无法及时发出, 因为程序阻塞在了 select.wait.</p>
<h3><a name="h-2-2">2.2 Master-Workers 单向通信(短连接)</a></h3>
<p>短连接是指一次请求响应后便关闭的连接, 而不是时间长短.</p>
<p>那么, 能不能让 Workers.wait(及其对应的网络 send 操作) 和 select.wait(及其对应的网络 recv 操作) 运行在两个不同的线程里? 答案是可以的. 但是, 把同一个连接用两个线程(一个是 select.wait, 另一个是 Workers.wait)来操作, 有时很难处理多线程问题. 还有一个重要的问题, 如果把网络发送放在工作者线程里, 那么一个连接的网络发送阻塞, 会导致其中一整个线程完全失去效用, 仅仅是因为阻塞. 我们不仅要考虑网络读阻塞, 也要考虑网络写阻塞的问题. 不过, 如果是基于短连接的模式, 是可以这么做的, 如果一个响应不会超过 socket 发送缓冲大小的话, send 永远不会阻塞. 程序的结构改变为:</p>
<pre>
// 启动 10 个工作者
Workers = start_Workers(num=10)
// 主循环
while(1){
    events = select.wait(select_timeout=10ms)
    if(events > 0){
        foreach(events as e){
            req = e.sock.recv()
            // 仅仅是委托, 会立即返回. 不关心响应.
            Workers.delegate(req)
        }
    }
}
</pre>
<p>Workers 的工作模式是:</p>
<pre>
while(1){
    req = req_queue.pop();
    resp = process(req)
    // 响应这里发送给客户端
    resp.send()
    resp.close()
}
</pre>
<p>对于短连接, 这种工作模式非常好. 因为 resp.send() 和 resp.close() 非常快, 操作系统保证调用它们几乎不会阻塞. 但是, 这种模式无法扩展到多台机器.</p>
<h3><a name="h-2-3">2.3 Master-Workers 双向通信(长连接之二)</a></h3>
<p>对于长连接, 是否还有更好的处理方法呢? 有的, 那就是把 Worker 做成可 select 的(Selectable), 比如 Master 和 Worker 通过网络通信, 那么就可以 select 处理结果了. 程序结构如下:</p>
<pre>
// 启动 10 个工作者
Workers = start_Workers(num=10)
// 主循环
while(1){
    events = select.wait(select_timeout=10ms)
    if(events > 0){
        foreach(events as e){
            if(req.type == USER_REQ){
                req = e.sock.recv()
                // 仅仅是委托, 会立即返回. 会通过 select 得到响应.
                Workers.delegate(req)
            }else if(req.type == WORKER_RESPONSE){
                resp = req;
                resp.sock.send(resp)
            }
        }
    }
}
</pre>
<p>在主循环中只有一个地方会等待, 无论是网络事件, 还是工作者事件, 都会立即唤醒 select.wait, 使事件得到及时得到响应.</p>
<p>这种方式是得到普遍应用的, 比如 <a href="http://www.lighttpd.net/">lighttpd</a> 的<del datetime="2010-08-26T12:37:21+00:00">主循环</del>IO 进程和 <a href="http://www.fastcgi.com/">fastcgi</a> 的通信就是这种方式. 当 Master 和 Worker 的通信使用的是网络 socket 的话, 可扩展性比 PIPE 更高.</p>
<p><b>欢迎讨论!</b></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/244.html' rel='bookmark' title='Permanent Link: 数据传输中的停止等待机制的实现'>数据传输中的停止等待机制的实现</a></li>
<li><a href='http://www.ideawu.net/blog/archives/508.html' rel='bookmark' title='Permanent Link: Windows Python select标准输入输出'>Windows Python select标准输入输出</a></li>
<li><a href='http://www.ideawu.net/blog/archives/98.html' rel='bookmark' title='Permanent Link: Linux下整合Apache和Tomcat'>Linux下整合Apache和Tomcat</a></li>
<li><a href='http://www.ideawu.net/blog/archives/319.html' rel='bookmark' title='Permanent Link: 数据通信与传输协议基础'>数据通信与传输协议基础</a></li>
<li><a href='http://www.ideawu.net/blog/archives/438.html' rel='bookmark' title='Permanent Link: PHP中使用foreach和引用导致程序BUG'>PHP中使用foreach和引用导致程序BUG</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/535.html" title="Master-Workers 模式处理高负载">Master-Workers 模式处理高负载</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>对于高负载的网络服务器, 瓶颈几乎总是在等待 IO, 而 CPU 的计算能力往往不是最先遇到的问题. 你的服务器程序, 接收客户端的请求, 可能还要连接另一台网络服务器, 一起合作处理客户端的请求. 很多情况下, 你无法把客户端的连接以及与另一台服务器的连接统一处理, 不可避免地要出现等待. 这时, 只能使用多进程或者多线程.</p>
<p>Master-Workers(管理者-工作者)模式是处理这种情况的主要方式, 只要有 IO 等待或者其它耗时的操作, 都交互若干个工作者之一处理, 这样, 后续的请求不会被阻塞, 从而实现高负载.</p>
<p><b>目录:</b></p>
<ul>
<li><a href="#h-1">单进程(单线程)网络服务器的结构</a></li>
<li>
		<a href="#h-2">多进程工作者模式(Master-Workers)</a></p>
<ul>
<li><a href="#h-2-1">Master-Workers 双向通信(长连接之一)</a></li>
<li><a href="#h-2-2">Master-Workers 单向通信(短连接)</a></li>
<li><a href="#h-2-3">Master-Workers 双向通信(长连接之二)</a></li>
</ul>
</li>
</ul>
<p>下文中有时用&#8221;进程&#8221;一词同时指代进程和线程, 它们的区别主要考虑的是通信方式.<br />
<span id="more-535"></span></p>
<h2><a name="h-1">1. 单进程(单线程)网络服务器的结构</a></h2>
<p>单进程网络服务器使用 IO 多路利用接口 &#8211; select(<a href="http://linux.die.net/man/2/select">doc</a>)/<a href="http://www.xmailserver.org/linux-patches/nio-improve.html">epoll</a>(<a href="http://linux.die.net/man/4/epoll">doc</a>)/kqueue(<a href="http://www.freebsd.org/cgi/man.cgi?query=kqueue&#038;sektion=2">doc</a>) 等 &#8211; 等待网络连接的信号, 收到读信号后, 接收一个应用层报文(如HTTP请求或者其它自定义的报文), 处理, 然后返回响应. 结构如下:</p>
<pre>
// 主循环
while(1){
    events = select.wait(timeout=100ms)
    foreach(events as e){
        req = e.sock.recv()
        resp = server.process(req)
        e.sock.send(resp)
    }
}
</pre>
<p>很明显, 如果 process 方法处理的时间较长的话, 那么并发量就很小了, 因为下一个请求必须等待前一个被处理完毕之后才能处理. 这时候, 只能使用多进程或者多线程, 创建所谓的工作者(Worker)进程.</p>
<h2><a name="h-2">2. 多进程工作者模式(Master-Workers)</a></h2>
<p>首先有一个 IO 进程(称为 Master), 也就是循环执行 select 的那个进程. 另有若干个工作者进程(称为 worker), 等待 IO 进程把报文给它们. 这也是一种&#8221;生产者-消费者&#8221;的模型. 具体上, 到底 IO 进程应该把哪一层次的数据交给工作者, 是简单的字节数组, 还是应用层的报文, 不同的应用不同设计. 现在假设传递的是完整的应用层报文, 也就是说, IO 进程负责报文解析, 如果报文的解析只消耗极少的资源, 这是最佳的方式.</p>
<h3><a name="h-2-1">2.1 Master-Workers 双向通信(长连接之一)</a></h3>
<pre>
// 启动 10 个工作者
Workers = start_Workers(num=10)
// 主循环
while(1){
    resps = Workers.wait(Workers_timeout=10ms);
    if(resps.count > 0){
        foreach(resps as resp){
            resps.sock.send(resp)
        }
    }

    events = select.wait(select_timeout=10ms)
    if(events > 0){
        foreach(events as e){
            req = e.sock.recv()
            // 仅仅是委托, 会立即返回. 以后通过 Workers.wait() 获取响应.
            Workers.delegate(req)
        }
    }
}
</pre>
<p>Workers 的工作模式是:</p>
<pre>
while(1){
    req = req_queue.pop();
    resp = process(req)
    // 响应被加入到发送队列中
    resp_queue.push(resp)
}
</pre>
<p>wokers.wait 是等待工作者的处理结果事件(从响应队列中读取响应), 而 select.wait 是等待网络事件. 两者逻辑上相同. Workers 和 select 应该等待多久(即 timeout 的取值是多少)? 如果 Workers_timeout 太大, 那么就会导致 Workers_timeout 时间内即使有新的请求进来, 也无法及时处理, 因为 select.wait 还没被执行到. 相对比, 如果 select_timeout 太大, 那么又会导致 select_timeout 时间内响应无法及时发出, 因为程序阻塞在了 select.wait.</p>
<h3><a name="h-2-2">2.2 Master-Workers 单向通信(短连接)</a></h3>
<p>短连接是指一次请求响应后便关闭的连接, 而不是时间长短.</p>
<p>那么, 能不能让 Workers.wait(及其对应的网络 send 操作) 和 select.wait(及其对应的网络 recv 操作) 运行在两个不同的线程里? 答案是可以的. 但是, 把同一个连接用两个线程(一个是 select.wait, 另一个是 Workers.wait)来操作, 有时很难处理多线程问题. 还有一个重要的问题, 如果把网络发送放在工作者线程里, 那么一个连接的网络发送阻塞, 会导致其中一整个线程完全失去效用, 仅仅是因为阻塞. 我们不仅要考虑网络读阻塞, 也要考虑网络写阻塞的问题. 不过, 如果是基于短连接的模式, 是可以这么做的, 如果一个响应不会超过 socket 发送缓冲大小的话, send 永远不会阻塞. 程序的结构改变为:</p>
<pre>
// 启动 10 个工作者
Workers = start_Workers(num=10)
// 主循环
while(1){
    events = select.wait(select_timeout=10ms)
    if(events > 0){
        foreach(events as e){
            req = e.sock.recv()
            // 仅仅是委托, 会立即返回. 不关心响应.
            Workers.delegate(req)
        }
    }
}
</pre>
<p>Workers 的工作模式是:</p>
<pre>
while(1){
    req = req_queue.pop();
    resp = process(req)
    // 响应这里发送给客户端
    resp.send()
    resp.close()
}
</pre>
<p>对于短连接, 这种工作模式非常好. 因为 resp.send() 和 resp.close() 非常快, 操作系统保证调用它们几乎不会阻塞. 但是, 这种模式无法扩展到多台机器.</p>
<h3><a name="h-2-3">2.3 Master-Workers 双向通信(长连接之二)</a></h3>
<p>对于长连接, 是否还有更好的处理方法呢? 有的, 那就是把 Worker 做成可 select 的(Selectable), 比如 Master 和 Worker 通过网络通信, 那么就可以 select 处理结果了. 程序结构如下:</p>
<pre>
// 启动 10 个工作者
Workers = start_Workers(num=10)
// 主循环
while(1){
    events = select.wait(select_timeout=10ms)
    if(events > 0){
        foreach(events as e){
            if(req.type == USER_REQ){
                req = e.sock.recv()
                // 仅仅是委托, 会立即返回. 会通过 select 得到响应.
                Workers.delegate(req)
            }else if(req.type == WORKER_RESPONSE){
                resp = req;
                resp.sock.send(resp)
            }
        }
    }
}
</pre>
<p>在主循环中只有一个地方会等待, 无论是网络事件, 还是工作者事件, 都会立即唤醒 select.wait, 使事件得到及时得到响应.</p>
<p>这种方式是得到普遍应用的, 比如 <a href="http://www.lighttpd.net/">lighttpd</a> 的<del datetime="2010-08-26T12:37:21+00:00">主循环</del>IO 进程和 <a href="http://www.fastcgi.com/">fastcgi</a> 的通信就是这种方式. 当 Master 和 Worker 的通信使用的是网络 socket 的话, 可扩展性比 PIPE 更高.</p>
<p><b>欢迎讨论!</b></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/244.html' rel='bookmark' title='Permanent Link: 数据传输中的停止等待机制的实现'>数据传输中的停止等待机制的实现</a></li>
<li><a href='http://www.ideawu.net/blog/archives/508.html' rel='bookmark' title='Permanent Link: Windows Python select标准输入输出'>Windows Python select标准输入输出</a></li>
<li><a href='http://www.ideawu.net/blog/archives/98.html' rel='bookmark' title='Permanent Link: Linux下整合Apache和Tomcat'>Linux下整合Apache和Tomcat</a></li>
<li><a href='http://www.ideawu.net/blog/archives/319.html' rel='bookmark' title='Permanent Link: 数据通信与传输协议基础'>数据通信与传输协议基础</a></li>
<li><a href='http://www.ideawu.net/blog/archives/438.html' rel='bookmark' title='Permanent Link: PHP中使用foreach和引用导致程序BUG'>PHP中使用foreach和引用导致程序BUG</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/535.html" title="Master-Workers 模式处理高负载">Master-Workers 模式处理高负载</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/535.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>TCP协议思想和技术的广泛应用</title>
		<link>http://www.ideawu.net/blog/archives/528.html</link>
		<comments>http://www.ideawu.net/blog/archives/528.html#comments</comments>
		<pubDate>Wed, 07 Jul 2010 04:16:47 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[P2P/Network]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/528.html</guid>
		<description><![CDATA[<p>TCP 协议是大量重要的网络和通讯的思想和技术的集合体. 这些思想和技术被应用在 TCP 身上, 另一方面, 学习 TCP 可以了解这些思想和技术. 通讯的思想和技术不仅仅可以应用狭义的数据通讯上, 也可以应用在广义的信息通讯上, 后者一般可以理解为应用层的交互协议, 例如即时通讯(IM)的聊天协议.</p>
<p>首先, TCP 协议是一种可靠的传输协议. 这种可靠性可以从两方面理解: 1. TCP 保证数据的有序性和无差错; 2. TCP 尽最大努力确保数据被接收.</p>
<p>有序和无差错可能比较好理解, 但&#8221;最大努力&#8221;则和我们一般理解的&#8221;可靠&#8221;有较大差别. 首先, TCP 尽最大努力传输数据, 一旦发送方无法保证数据传输到接收方, 它将通过断开连接(使连接失效)来声明这一点. 其次, TCP 可以明确地告诉一个数据分段已经被对方接收, 但无法准确的断定未被确认的数据没有被对方接收, 也就是说, 数据可能没有被对方接收, 也能已经被对方接收. 这种对传输失败的不确定性, 显然是对可靠性的一个重大打击. &#8220;<a href="http://en.wikipedia.org/wiki/Two_Generals'_Problem">两军队问题(Two Army Problem)</a>&#8220;说明了这一点, 事实上, 我们无法判断一个确认(ACK)是丢失了还是没有发出.</p>
<p><span id="more-528"></span>大部分可靠协议使用&#8221;带重传的正面确认(PAR, Positive Acknowledgment with Re-Transmission)&#8221;机制, TCP 协议也不例外. TCP 的如下特点可以在我们设计可靠传输协议时参考:</p>
<h3>1. 连接建立</h3>
<p>连接的建立是面向连接的协议所必须的. 连接建立的过程双方可进行某些变量的协商, 如序号. 更高层次的应用层协议还协商版本号, 处理速度等.</p>
<h3>2. 分段和序号</h3>
<p>分段也即是一般所说的&#8221;分包&#8221;, 也即消息和报文的概念. 序号是为了保证消息的有序性, 用于乱序重排.</p>
<p>分段方式有3种: 1. 固定长度; 2. 报文自声明长度; 3. 分隔符.</p>
<p>基于 TCP 这样可靠传输的协议而设计的上层协议往往不需要序号机制, 但分段大部分情况都是必须的. 序号也是确认和重传的基础. 基于 TCP 的 HTTP, FTP, SMTP 等协议, 没有序号概念. 这是因为, 底层的 TCP 已经保证了有序和数据不会丢失. 基于 TCP 设计的协议也可能需要序号机制, 使用 TCP 的协议需要序号机制的条件为: 1. 协议不依赖连接, 一次上层的会话可能经历 TCP 的断开和重连; 2. 协议不是停止等待式的&#8221;请求-响应&#8221;模式.</p>
<h3>3. 确认和重传</h3>
<p>确认和重传消息报文丢失影响的方法. 确认有立即确认和延时确认. 重传的触发时机不仅仅是超时, TCP 还设计了立即重传机制.</p>
<h3>4. 滑动窗口</h3>
<p>简单的停止等待机制是一种退化了的滑动窗口. TCP 的最大传输速度是 wnd_size/rtt, 因为 RTT 一般主要受物理条件影响, 所以通过增加窗口大小来提高 TCP 的速度.</p>
<p>发送方至少有 4 个变量: snd_una, snd_nxt, snd_max, snd_wnd.</p>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg" alt="" title="tcp接收窗口示意图" width="500" height="164" class="alignnone size-full wp-image-529" /></a></p>
<p>snd_una: 未被确认的第一个序号. TCP 的 ACK 确认的是已收到的最大序号+1.<br />
snd_nxt: 下一个要进行发送(包括重传)的序号, 如果不是重传, 则与 snd_max 相等.<br />
snd_max: 下一个要进行第一次发送的序号, 即已发送的最大序号+1.<br />
snd_wnd: 窗口大小.</p>
<p>接收方至少有 2 个变量: rcv_nxt, rcv_wnd.</p>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg" alt="" title="tcp接收窗口示意图" width="500" height="164" class="alignnone size-full wp-image-529" /></a></p>
<p>rcv_nxt: 下一个要接收的序号, 也即要发送(或已发送的 ACK).<br />
rcv_wnd: 窗口大小.</p>
<h3>5. 更多</h3>
<p>拥塞控制, 流量控制, 选择ACK, 序号回绕等等, 都是可以学习的东西.</p>
<h3>关于 IM 软件的一些问题</h3>
<p>IM 的聊天协议需要面向连接吗? 以腾讯 QQ 为例, 它并没有使用应用层的面向连接机制(即会话机制), 而是发送方确保发送到中转服务器, 中转服务器确保发送到接收方.</p>
<p>腾讯的 QQ 缺少序号机制, 无法保证有序性(可完全避免). 而且缺少完善的应用层的确认和重传机制, 常常出现发送方提示发送失败, 但接收方事实上已经收到了的现象(无法完全避免但可减少出现概率到极小).</p>
<p>我认为, QQ 应该解决消息的无序性问题, 并且完善确认和重传机制. 聊天消息应该实现这些状态: 发送中, 取消中, 发送成功, 未发送.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/245.html' rel='bookmark' title='Permanent Link: 滑动窗口机制简单理解'>滑动窗口机制简单理解</a></li>
<li><a href='http://www.ideawu.net/blog/archives/281.html' rel='bookmark' title='Permanent Link: 使用流水线来实现并发'>使用流水线来实现并发</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
<li><a href='http://www.ideawu.net/blog/archives/303.html' rel='bookmark' title='Permanent Link: TCP/IP 指数增长和线性增长的编程实现'>TCP/IP 指数增长和线性增长的编程实现</a></li>
<li><a href='http://www.ideawu.net/blog/archives/280.html' rel='bookmark' title='Permanent Link: 异步, 同步, 连接建立, 连接断开, 通信'>异步, 同步, 连接建立, 连接断开, 通信</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/528.html" title="TCP协议思想和技术的广泛应用">TCP协议思想和技术的广泛应用</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>TCP 协议是大量重要的网络和通讯的思想和技术的集合体. 这些思想和技术被应用在 TCP 身上, 另一方面, 学习 TCP 可以了解这些思想和技术. 通讯的思想和技术不仅仅可以应用狭义的数据通讯上, 也可以应用在广义的信息通讯上, 后者一般可以理解为应用层的交互协议, 例如即时通讯(IM)的聊天协议.</p>
<p>首先, TCP 协议是一种可靠的传输协议. 这种可靠性可以从两方面理解: 1. TCP 保证数据的有序性和无差错; 2. TCP 尽最大努力确保数据被接收.</p>
<p>有序和无差错可能比较好理解, 但&#8221;最大努力&#8221;则和我们一般理解的&#8221;可靠&#8221;有较大差别. 首先, TCP 尽最大努力传输数据, 一旦发送方无法保证数据传输到接收方, 它将通过断开连接(使连接失效)来声明这一点. 其次, TCP 可以明确地告诉一个数据分段已经被对方接收, 但无法准确的断定未被确认的数据没有被对方接收, 也就是说, 数据可能没有被对方接收, 也能已经被对方接收. 这种对传输失败的不确定性, 显然是对可靠性的一个重大打击. &#8220;<a href="http://en.wikipedia.org/wiki/Two_Generals'_Problem">两军队问题(Two Army Problem)</a>&#8220;说明了这一点, 事实上, 我们无法判断一个确认(ACK)是丢失了还是没有发出.</p>
<p><span id="more-528"></span>大部分可靠协议使用&#8221;带重传的正面确认(PAR, Positive Acknowledgment with Re-Transmission)&#8221;机制, TCP 协议也不例外. TCP 的如下特点可以在我们设计可靠传输协议时参考:</p>
<h3>1. 连接建立</h3>
<p>连接的建立是面向连接的协议所必须的. 连接建立的过程双方可进行某些变量的协商, 如序号. 更高层次的应用层协议还协商版本号, 处理速度等.</p>
<h3>2. 分段和序号</h3>
<p>分段也即是一般所说的&#8221;分包&#8221;, 也即消息和报文的概念. 序号是为了保证消息的有序性, 用于乱序重排.</p>
<p>分段方式有3种: 1. 固定长度; 2. 报文自声明长度; 3. 分隔符.</p>
<p>基于 TCP 这样可靠传输的协议而设计的上层协议往往不需要序号机制, 但分段大部分情况都是必须的. 序号也是确认和重传的基础. 基于 TCP 的 HTTP, FTP, SMTP 等协议, 没有序号概念. 这是因为, 底层的 TCP 已经保证了有序和数据不会丢失. 基于 TCP 设计的协议也可能需要序号机制, 使用 TCP 的协议需要序号机制的条件为: 1. 协议不依赖连接, 一次上层的会话可能经历 TCP 的断开和重连; 2. 协议不是停止等待式的&#8221;请求-响应&#8221;模式.</p>
<h3>3. 确认和重传</h3>
<p>确认和重传消息报文丢失影响的方法. 确认有立即确认和延时确认. 重传的触发时机不仅仅是超时, TCP 还设计了立即重传机制.</p>
<h3>4. 滑动窗口</h3>
<p>简单的停止等待机制是一种退化了的滑动窗口. TCP 的最大传输速度是 wnd_size/rtt, 因为 RTT 一般主要受物理条件影响, 所以通过增加窗口大小来提高 TCP 的速度.</p>
<p>发送方至少有 4 个变量: snd_una, snd_nxt, snd_max, snd_wnd.</p>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg" alt="" title="tcp接收窗口示意图" width="500" height="164" class="alignnone size-full wp-image-529" /></a></p>
<p>snd_una: 未被确认的第一个序号. TCP 的 ACK 确认的是已收到的最大序号+1.<br />
snd_nxt: 下一个要进行发送(包括重传)的序号, 如果不是重传, 则与 snd_max 相等.<br />
snd_max: 下一个要进行第一次发送的序号, 即已发送的最大序号+1.<br />
snd_wnd: 窗口大小.</p>
<p>接收方至少有 2 个变量: rcv_nxt, rcv_wnd.</p>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/07/tcp接收窗口示意图.jpg" alt="" title="tcp接收窗口示意图" width="500" height="164" class="alignnone size-full wp-image-529" /></a></p>
<p>rcv_nxt: 下一个要接收的序号, 也即要发送(或已发送的 ACK).<br />
rcv_wnd: 窗口大小.</p>
<h3>5. 更多</h3>
<p>拥塞控制, 流量控制, 选择ACK, 序号回绕等等, 都是可以学习的东西.</p>
<h3>关于 IM 软件的一些问题</h3>
<p>IM 的聊天协议需要面向连接吗? 以腾讯 QQ 为例, 它并没有使用应用层的面向连接机制(即会话机制), 而是发送方确保发送到中转服务器, 中转服务器确保发送到接收方.</p>
<p>腾讯的 QQ 缺少序号机制, 无法保证有序性(可完全避免). 而且缺少完善的应用层的确认和重传机制, 常常出现发送方提示发送失败, 但接收方事实上已经收到了的现象(无法完全避免但可减少出现概率到极小).</p>
<p>我认为, QQ 应该解决消息的无序性问题, 并且完善确认和重传机制. 聊天消息应该实现这些状态: 发送中, 取消中, 发送成功, 未发送.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/245.html' rel='bookmark' title='Permanent Link: 滑动窗口机制简单理解'>滑动窗口机制简单理解</a></li>
<li><a href='http://www.ideawu.net/blog/archives/281.html' rel='bookmark' title='Permanent Link: 使用流水线来实现并发'>使用流水线来实现并发</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
<li><a href='http://www.ideawu.net/blog/archives/303.html' rel='bookmark' title='Permanent Link: TCP/IP 指数增长和线性增长的编程实现'>TCP/IP 指数增长和线性增长的编程实现</a></li>
<li><a href='http://www.ideawu.net/blog/archives/280.html' rel='bookmark' title='Permanent Link: 异步, 同步, 连接建立, 连接断开, 通信'>异步, 同步, 连接建立, 连接断开, 通信</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/528.html" title="TCP协议思想和技术的广泛应用">TCP协议思想和技术的广泛应用</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/528.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>以浏览器引擎为核心的软件架构</title>
		<link>http://www.ideawu.net/blog/archives/526.html</link>
		<comments>http://www.ideawu.net/blog/archives/526.html#comments</comments>
		<pubDate>Tue, 06 Jul 2010 02:34:22 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/526.html</guid>
		<description><![CDATA[<p>我在 <a href="http://www.ideawu.net/blog/archives/59.html">2006 年</a>的时候, 曾经提出过用 HTML/CSS 来做桌面应用程序的界面的想法, 但更早之前(2001年), 著名游戏开发者, 网易的游戏工程师<a href="http://blog.codingnow.com/">云风</a>便在其公司的&#8221;大话西游&#8221;网站游戏中应用了嵌入<a href="http://blog.codingnow.com/2008/05/passed_days_7.html">浏览器做界面</a>的方法.</p>
<p>Windows 控制面板里的&#8221;添加/删除应用程序&#8221;应该是较早的利用浏览器来做程序界面的一个程序, 当然, 微软肯定还有更早的程序. 后来的 Google Talk, 又是一个经典的利用浏览器做界面的一个软件.</p>
<p><span id="more-526"></span>通过分析, 可以发现 Google Talk(gtalk)的程序使用了 mshtml.dll 动态链接库, 这个库就是 IE 引擎. 而且, <a href="http://www.ideawu.net/blog/archives/299.html">gtalk 的界面的一部分就是纯 HTML</a>, 用户可以自己修改并生效.</p>
<p>所以说, 使用浏览器引擎作为软件的界面引擎和桌面软件整个架构的核心, 这种技术已经非常成熟了. 以浏览器引擎为核心, 其实是一种更为纯粹的 MVC, 或者说 C/S 模式. 软件界面和逻辑层的通信主要有如下几种:</p>
<h3>1. HTTP 网络通信</h3>
<p>这种方式, 不仅嵌入浏览器引擎, 而且还嵌入 Web 服务器(如果不做成单纯的 Web 应用的话). 软件界面这时成为一个重新包装了外壳的浏览器. 例如, 用户点击了&#8221;计算&#8221;按钮, 程序将向嵌入的 Web 服务器提交一个表单, 并读取服务器的计算结果显示出来.</p>
<p>这种方式并不常用, 应该它直接使用浏览器的 Web 应用没有太大区别. 网络延时会成为问题.</p>
<h3>2. 使用浏览器控件的 API</h3>
<p>浏览器控件(以 MSHTML 为例)提供了 API, 既可让浏览器中的代码(界面)调用宿主程序的代码(后端逻辑), 也可以反之. 这种接口一般就是一个函数, 比如宿主程序可能这样调用界面脚本中的 js_func 函数:</p>
<pre>
mshtml.InvokeScript('js_func', args);
</pre>
<p>而浏览器中的代码可能这样调用宿主程序中的 Add 函数:</p>
<pre>
window.external.Add(1, 2);
</pre>
<p>仅仅使用这个 API 还是太原始, 如果要做更复杂的程序, 应该自定义一套界面和逻辑的交互协议.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/299.html' rel='bookmark' title='Permanent Link: Google Talk 界面开发分析'>Google Talk 界面开发分析</a></li>
<li><a href='http://www.ideawu.net/blog/archives/301.html' rel='bookmark' title='Permanent Link: Google Talk Developer Home 中文翻译'>Google Talk Developer Home 中文翻译</a></li>
<li><a href='http://www.ideawu.net/blog/archives/144.html' rel='bookmark' title='Permanent Link: 使用Gaim连接Gtalk'>使用Gaim连接Gtalk</a></li>
<li><a href='http://www.ideawu.net/blog/archives/148.html' rel='bookmark' title='Permanent Link: 安装和使用Google Earth &#8211; Linux'>安装和使用Google Earth &#8211; Linux</a></li>
<li><a href='http://www.ideawu.net/blog/archives/514.html' rel='bookmark' title='Permanent Link: endlessssh &#8211; SSH 代理工具'>endlessssh &#8211; SSH 代理工具</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/526.html" title="以浏览器引擎为核心的软件架构">以浏览器引擎为核心的软件架构</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>我在 <a href="http://www.ideawu.net/blog/archives/59.html">2006 年</a>的时候, 曾经提出过用 HTML/CSS 来做桌面应用程序的界面的想法, 但更早之前(2001年), 著名游戏开发者, 网易的游戏工程师<a href="http://blog.codingnow.com/">云风</a>便在其公司的&#8221;大话西游&#8221;网站游戏中应用了嵌入<a href="http://blog.codingnow.com/2008/05/passed_days_7.html">浏览器做界面</a>的方法.</p>
<p>Windows 控制面板里的&#8221;添加/删除应用程序&#8221;应该是较早的利用浏览器来做程序界面的一个程序, 当然, 微软肯定还有更早的程序. 后来的 Google Talk, 又是一个经典的利用浏览器做界面的一个软件.</p>
<p><span id="more-526"></span>通过分析, 可以发现 Google Talk(gtalk)的程序使用了 mshtml.dll 动态链接库, 这个库就是 IE 引擎. 而且, <a href="http://www.ideawu.net/blog/archives/299.html">gtalk 的界面的一部分就是纯 HTML</a>, 用户可以自己修改并生效.</p>
<p>所以说, 使用浏览器引擎作为软件的界面引擎和桌面软件整个架构的核心, 这种技术已经非常成熟了. 以浏览器引擎为核心, 其实是一种更为纯粹的 MVC, 或者说 C/S 模式. 软件界面和逻辑层的通信主要有如下几种:</p>
<h3>1. HTTP 网络通信</h3>
<p>这种方式, 不仅嵌入浏览器引擎, 而且还嵌入 Web 服务器(如果不做成单纯的 Web 应用的话). 软件界面这时成为一个重新包装了外壳的浏览器. 例如, 用户点击了&#8221;计算&#8221;按钮, 程序将向嵌入的 Web 服务器提交一个表单, 并读取服务器的计算结果显示出来.</p>
<p>这种方式并不常用, 应该它直接使用浏览器的 Web 应用没有太大区别. 网络延时会成为问题.</p>
<h3>2. 使用浏览器控件的 API</h3>
<p>浏览器控件(以 MSHTML 为例)提供了 API, 既可让浏览器中的代码(界面)调用宿主程序的代码(后端逻辑), 也可以反之. 这种接口一般就是一个函数, 比如宿主程序可能这样调用界面脚本中的 js_func 函数:</p>
<pre>
mshtml.InvokeScript('js_func', args);
</pre>
<p>而浏览器中的代码可能这样调用宿主程序中的 Add 函数:</p>
<pre>
window.external.Add(1, 2);
</pre>
<p>仅仅使用这个 API 还是太原始, 如果要做更复杂的程序, 应该自定义一套界面和逻辑的交互协议.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/299.html' rel='bookmark' title='Permanent Link: Google Talk 界面开发分析'>Google Talk 界面开发分析</a></li>
<li><a href='http://www.ideawu.net/blog/archives/301.html' rel='bookmark' title='Permanent Link: Google Talk Developer Home 中文翻译'>Google Talk Developer Home 中文翻译</a></li>
<li><a href='http://www.ideawu.net/blog/archives/144.html' rel='bookmark' title='Permanent Link: 使用Gaim连接Gtalk'>使用Gaim连接Gtalk</a></li>
<li><a href='http://www.ideawu.net/blog/archives/148.html' rel='bookmark' title='Permanent Link: 安装和使用Google Earth &#8211; Linux'>安装和使用Google Earth &#8211; Linux</a></li>
<li><a href='http://www.ideawu.net/blog/archives/514.html' rel='bookmark' title='Permanent Link: endlessssh &#8211; SSH 代理工具'>endlessssh &#8211; SSH 代理工具</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/526.html" title="以浏览器引擎为核心的软件架构">以浏览器引擎为核心的软件架构</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/526.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>if-else对优化代码冗余度的反作用</title>
		<link>http://www.ideawu.net/blog/archives/518.html</link>
		<comments>http://www.ideawu.net/blog/archives/518.html#comments</comments>
		<pubDate>Tue, 22 Jun 2010 02:52:44 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/518.html</guid>
		<description><![CDATA[<p>有些程序员可能过于追求 if-else 对代码优化的效果, 却忽略了其带来的对代码清晰度的反作用. 假设这样一个功能, 根据用户的等级显示不同的页面. 如果用户的等级大于等于 5, 他能看到的东西和普通用户(等级小于5)不同, 代码如下:</p>
<pre>
echo "欢迎您, ";
if(level &gt; 5){
	echo "高级用户!";
}else{
	echo "用户!"
}
// ... 大段代码
echo '&lt;a href="#"&gt;个人信息&lt;/a&gt;';
if(level &gt; 5){
	echo "审核文章!";
}else{
	echo "发表文章!"
}
echo "...";
</pre>
<p><span id="more-518"></span>我们看到, 随着功能的继续, 不断地出现 if-else, 可能是十几个. 虽然在 if-else 之外的代码得到了重用, 也即冗余度降低了, 但是, 充斥各处的判断不是也极大地影响了代码的清晰度吗?</p>
<p>如果我 copy-paste 一份公用代码(不可过于极端地反对复制粘贴), 就可以只使用一个 if-else:</p>
<pre>
if(level &gt; 5){
	echo "欢迎您, 高级用户!";
	// ... 大段代码
	echo '&lt;a href="#"&gt;个人信息&lt;/a&gt;';
	echo "审核文章!";
	echo "...";
}else{
	echo "欢迎您, 用户!";
	// ... 大段代码
	echo '&lt;a href="#"&gt;个人信息&lt;/a&gt;';
	echo "发表文章!";
	echo "...";
}
</pre>
<p>这样, 优化后全部的代码只有一个分支, 才是符合人思维的逻辑, 虽然代码量扩大了近一倍. 而且, &#8220;大段代码&#8221;可以封装成函数, 优化后的代码在行数和冗余度上不一定增加.</p>
<p>所以, 不要把冗余度作为代码优化的唯一条件, 更不要把 if-else 作为代码重用的唯一方法!</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/619.html' rel='bookmark' title='Permanent Link: PHP浮点数显示和转成字符串'>PHP浮点数显示和转成字符串</a></li>
<li><a href='http://www.ideawu.net/blog/archives/367.html' rel='bookmark' title='Permanent Link: Wordpress分页代码'>Wordpress分页代码</a></li>
<li><a href='http://www.ideawu.net/blog/archives/624.html' rel='bookmark' title='Permanent Link: Python logging 标准配置'>Python logging 标准配置</a></li>
<li><a href='http://www.ideawu.net/blog/archives/464.html' rel='bookmark' title='Permanent Link: 用PHP去除重复图片文件'>用PHP去除重复图片文件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/621.html' rel='bookmark' title='Permanent Link: Shell循环'>Shell循环</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/518.html" title="if-else对优化代码冗余度的反作用">if-else对优化代码冗余度的反作用</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>有些程序员可能过于追求 if-else 对代码优化的效果, 却忽略了其带来的对代码清晰度的反作用. 假设这样一个功能, 根据用户的等级显示不同的页面. 如果用户的等级大于等于 5, 他能看到的东西和普通用户(等级小于5)不同, 代码如下:</p>
<pre>
echo "欢迎您, ";
if(level &gt; 5){
	echo "高级用户!";
}else{
	echo "用户!"
}
// ... 大段代码
echo '&lt;a href="#"&gt;个人信息&lt;/a&gt;';
if(level &gt; 5){
	echo "审核文章!";
}else{
	echo "发表文章!"
}
echo "...";
</pre>
<p><span id="more-518"></span>我们看到, 随着功能的继续, 不断地出现 if-else, 可能是十几个. 虽然在 if-else 之外的代码得到了重用, 也即冗余度降低了, 但是, 充斥各处的判断不是也极大地影响了代码的清晰度吗?</p>
<p>如果我 copy-paste 一份公用代码(不可过于极端地反对复制粘贴), 就可以只使用一个 if-else:</p>
<pre>
if(level &gt; 5){
	echo "欢迎您, 高级用户!";
	// ... 大段代码
	echo '&lt;a href="#"&gt;个人信息&lt;/a&gt;';
	echo "审核文章!";
	echo "...";
}else{
	echo "欢迎您, 用户!";
	// ... 大段代码
	echo '&lt;a href="#"&gt;个人信息&lt;/a&gt;';
	echo "发表文章!";
	echo "...";
}
</pre>
<p>这样, 优化后全部的代码只有一个分支, 才是符合人思维的逻辑, 虽然代码量扩大了近一倍. 而且, &#8220;大段代码&#8221;可以封装成函数, 优化后的代码在行数和冗余度上不一定增加.</p>
<p>所以, 不要把冗余度作为代码优化的唯一条件, 更不要把 if-else 作为代码重用的唯一方法!</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/619.html' rel='bookmark' title='Permanent Link: PHP浮点数显示和转成字符串'>PHP浮点数显示和转成字符串</a></li>
<li><a href='http://www.ideawu.net/blog/archives/367.html' rel='bookmark' title='Permanent Link: Wordpress分页代码'>Wordpress分页代码</a></li>
<li><a href='http://www.ideawu.net/blog/archives/624.html' rel='bookmark' title='Permanent Link: Python logging 标准配置'>Python logging 标准配置</a></li>
<li><a href='http://www.ideawu.net/blog/archives/464.html' rel='bookmark' title='Permanent Link: 用PHP去除重复图片文件'>用PHP去除重复图片文件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/621.html' rel='bookmark' title='Permanent Link: Shell循环'>Shell循环</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/518.html" title="if-else对优化代码冗余度的反作用">if-else对优化代码冗余度的反作用</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/518.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>endlessssh &#8211; SSH 代理工具</title>
		<link>http://www.ideawu.net/blog/archives/514.html</link>
		<comments>http://www.ideawu.net/blog/archives/514.html#comments</comments>
		<pubDate>Sun, 06 Jun 2010 07:17:22 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[P2P/Network]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/514.html</guid>
		<description><![CDATA[<p>新建了一个开源项目 endlessssh, 用于 SSH 代理(不是 SSH 作为代理, 而是 SSH 使用代理), 放在 Google Project Hosting. 工具有两个特点:</p>
<p>1. Tunneling SSH over REAL HTTP(完善中)</p>
<p>让 SSH 工作在 HTTP 协议上, 从而穿越防火墙.</p>
<p>2. 持续的会话</p>
<p>即使 TCP 网络连接断开(这时, SSH 会话会失效), SSH 会话仍然保持, 直到网络重连后, 会话继续.</p>
<p>项目地址: <a href="http://code.google.com/p/endlessssh/">http://code.google.com/p/endlessssh/</a></p>
<p><strong>补充:</strong></p>
<p>谢谢评论中 Zealot 朋友的推荐.</p>
<p>大概看了下类似的一个 GNU 项目 httptunnel(http://www.nocrew.org/software/httptunnel.html). 这个项目所使用的交互过程更像是 HTTP 交互, 在一个 HTTP 报文中包含自己的多个报文. httptunnel 没有确认机制, 也没有会话保持机制. 不过, httptunnel 可以值得借鉴.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/301.html' rel='bookmark' title='Permanent Link: Google Talk Developer Home 中文翻译'>Google Talk Developer Home 中文翻译</a></li>
<li><a href='http://www.ideawu.net/blog/archives/482.html' rel='bookmark' title='Permanent Link: 开发爬虫友好的Ajax网站'>开发爬虫友好的Ajax网站</a></li>
<li><a href='http://www.ideawu.net/blog/archives/611.html' rel='bookmark' title='Permanent Link: 强大的纯JS数据图工具-flot'>强大的纯JS数据图工具-flot</a></li>
<li><a href='http://www.ideawu.net/blog/archives/357.html' rel='bookmark' title='Permanent Link: MySQL 查询使用 Group By 的注意点'>MySQL 查询使用 Group By 的注意点</a></li>
<li><a href='http://www.ideawu.net/blog/archives/299.html' rel='bookmark' title='Permanent Link: Google Talk 界面开发分析'>Google Talk 界面开发分析</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/514.html" title="endlessssh &#8211; SSH 代理工具">endlessssh &#8211; SSH 代理工具</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>新建了一个开源项目 endlessssh, 用于 SSH 代理(不是 SSH 作为代理, 而是 SSH 使用代理), 放在 Google Project Hosting. 工具有两个特点:</p>
<p>1. Tunneling SSH over REAL HTTP(完善中)</p>
<p>让 SSH 工作在 HTTP 协议上, 从而穿越防火墙.</p>
<p>2. 持续的会话</p>
<p>即使 TCP 网络连接断开(这时, SSH 会话会失效), SSH 会话仍然保持, 直到网络重连后, 会话继续.</p>
<p>项目地址: <a href="http://code.google.com/p/endlessssh/">http://code.google.com/p/endlessssh/</a></p>
<p><strong>补充:</strong></p>
<p>谢谢评论中 Zealot 朋友的推荐.</p>
<p>大概看了下类似的一个 GNU 项目 httptunnel(http://www.nocrew.org/software/httptunnel.html). 这个项目所使用的交互过程更像是 HTTP 交互, 在一个 HTTP 报文中包含自己的多个报文. httptunnel 没有确认机制, 也没有会话保持机制. 不过, httptunnel 可以值得借鉴.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/301.html' rel='bookmark' title='Permanent Link: Google Talk Developer Home 中文翻译'>Google Talk Developer Home 中文翻译</a></li>
<li><a href='http://www.ideawu.net/blog/archives/482.html' rel='bookmark' title='Permanent Link: 开发爬虫友好的Ajax网站'>开发爬虫友好的Ajax网站</a></li>
<li><a href='http://www.ideawu.net/blog/archives/611.html' rel='bookmark' title='Permanent Link: 强大的纯JS数据图工具-flot'>强大的纯JS数据图工具-flot</a></li>
<li><a href='http://www.ideawu.net/blog/archives/357.html' rel='bookmark' title='Permanent Link: MySQL 查询使用 Group By 的注意点'>MySQL 查询使用 Group By 的注意点</a></li>
<li><a href='http://www.ideawu.net/blog/archives/299.html' rel='bookmark' title='Permanent Link: Google Talk 界面开发分析'>Google Talk 界面开发分析</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/514.html" title="endlessssh &#8211; SSH 代理工具">endlessssh &#8211; SSH 代理工具</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/514.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>endless_tcp &#8211; 一种适应极端网络环境的网络软件架构</title>
		<link>http://www.ideawu.net/blog/archives/511.html</link>
		<comments>http://www.ideawu.net/blog/archives/511.html#comments</comments>
		<pubDate>Thu, 03 Jun 2010 14:12:04 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[P2P/Network]]></category>
		<category><![CDATA[TCP]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/511.html</guid>
		<description><![CDATA[<p>TCP 是一种可靠连接的协议, 即使在恶劣的网络环境中(如丢包率高), 也能实现数据的可靠传输. 可以简单地和 UDP 对比. 使用 UDP 发出一份数据, 你无法通过 UDP 本身判断数据是否已经被对方收到. 但是使用 TCP, 你可以判断, 因为如果 TCP 无法保证对端收到数据, 连接便会使自己失败, 从而你得到一个通知.</p>
<p>TCP 会话依赖于 IP 和端口, 也就是说, 一旦双方的任意一方的 IP 和端口发生了改变, TCP 连接就失效了. 另外, 虽然 TCP 有重传机制, 但重传失效的次数和时限用户转难控制. 为解决这两个问题, 需要实现一种不依赖于 IP/Port, 适应极其恶劣(超过 TCP 的容忍范围)的网络环境的连接协议, 称为 endless_tcp.</p>
<p><span id="more-511"></span>为了避免实现&#8221;另一个 TCP&#8221;, 这个协议基于 TCP 协议, 主要的特点是隧道和会话恢复机制.</p>
<p>假设有这样的一个不稳定网络:</p>
<pre>
     |               |
Node | ~~ network ~~ | Node
     |               |
</pre>
<p>两个节点之间通过 TCP 进行连接, 但因为网络状况极差, 所以 TCP 连接经常断开, 应用程序频繁显示&#8221;Connection reset by peer&#8221;. 如果应用程序的会话依赖于一条持续的 TCP 连接, 那么这个程序的使用就非常糟糕了. 我们在使用 SSH 的时候就常遇到这个问题, 当我们的电脑从有线网络切换到无线网络, 或者从某个无线网络区域移动到了另一个无线网络区域, SSH 会话都会失效, 必须重连.</p>
<p>解决这个问题的一种考虑是使用一种不会话不依赖于连接的协议, 如 HTTP. 对于 HTTP, 当你的电脑从办公室移动到家里时, 你在网络的登录会话还是有效的. 对于 SSH, 改变协议不太现实. 解决的思路是实现更健壮的连接协议. 如何在 TCP 不稳定的网络中建立起稳定的连接, 而这种连接又是基于 TCP 的呢? 首先, 我们使用隧道技术, 把 SSH 的会话数据转到隧道中. 系统被改成下面的结构:</p>
<pre>
     |               |
Node |               | Node
 ||  |               |  ||
Proxy| ~~ tunnel ~~  |Proxy
     |               |
</pre>
<p>虽然网络不稳定, 但 Node 和 Proxy 之间的网络是非常稳定的, 比如两者在同一台机器上. Proxy 之间的会话不依赖连接, 所以可以基于 TCP 实现更健壮的连接.</p>
<p>对于 SSH, ProxyCommand 选项提供了非常简便的 SSH 客户端与隧道的接口, 使用该选项, SSH 客户端使用标准输入输出, 而不是 socket. 一个 Python 语言开发的程序, 证明了这种思路的正确性和可行性.</p>
<p>如果隧道使用了 HTTP 协议, 则可以穿越防火墙. 反过来, 建立于其上的 SSH, 也可以被用来进行加密通信.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
<li><a href='http://www.ideawu.net/blog/archives/505.html' rel='bookmark' title='Permanent Link: PHP解析HTML和loadHTML乱码'>PHP解析HTML和loadHTML乱码</a></li>
<li><a href='http://www.ideawu.net/blog/archives/313.html' rel='bookmark' title='Permanent Link: C# 版的 SimpleXML'>C# 版的 SimpleXML</a></li>
<li><a href='http://www.ideawu.net/blog/archives/625.html' rel='bookmark' title='Permanent Link: Chrome浏览器必装的插件'>Chrome浏览器必装的插件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/514.html' rel='bookmark' title='Permanent Link: endlessssh &#8211; SSH 代理工具'>endlessssh &#8211; SSH 代理工具</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/511.html" title="endless_tcp &#8211; 一种适应极端网络环境的网络软件架构">endless_tcp &#8211; 一种适应极端网络环境的网络软件架构</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>TCP 是一种可靠连接的协议, 即使在恶劣的网络环境中(如丢包率高), 也能实现数据的可靠传输. 可以简单地和 UDP 对比. 使用 UDP 发出一份数据, 你无法通过 UDP 本身判断数据是否已经被对方收到. 但是使用 TCP, 你可以判断, 因为如果 TCP 无法保证对端收到数据, 连接便会使自己失败, 从而你得到一个通知.</p>
<p>TCP 会话依赖于 IP 和端口, 也就是说, 一旦双方的任意一方的 IP 和端口发生了改变, TCP 连接就失效了. 另外, 虽然 TCP 有重传机制, 但重传失效的次数和时限用户转难控制. 为解决这两个问题, 需要实现一种不依赖于 IP/Port, 适应极其恶劣(超过 TCP 的容忍范围)的网络环境的连接协议, 称为 endless_tcp.</p>
<p><span id="more-511"></span>为了避免实现&#8221;另一个 TCP&#8221;, 这个协议基于 TCP 协议, 主要的特点是隧道和会话恢复机制.</p>
<p>假设有这样的一个不稳定网络:</p>
<pre>
     |               |
Node | ~~ network ~~ | Node
     |               |
</pre>
<p>两个节点之间通过 TCP 进行连接, 但因为网络状况极差, 所以 TCP 连接经常断开, 应用程序频繁显示&#8221;Connection reset by peer&#8221;. 如果应用程序的会话依赖于一条持续的 TCP 连接, 那么这个程序的使用就非常糟糕了. 我们在使用 SSH 的时候就常遇到这个问题, 当我们的电脑从有线网络切换到无线网络, 或者从某个无线网络区域移动到了另一个无线网络区域, SSH 会话都会失效, 必须重连.</p>
<p>解决这个问题的一种考虑是使用一种不会话不依赖于连接的协议, 如 HTTP. 对于 HTTP, 当你的电脑从办公室移动到家里时, 你在网络的登录会话还是有效的. 对于 SSH, 改变协议不太现实. 解决的思路是实现更健壮的连接协议. 如何在 TCP 不稳定的网络中建立起稳定的连接, 而这种连接又是基于 TCP 的呢? 首先, 我们使用隧道技术, 把 SSH 的会话数据转到隧道中. 系统被改成下面的结构:</p>
<pre>
     |               |
Node |               | Node
 ||  |               |  ||
Proxy| ~~ tunnel ~~  |Proxy
     |               |
</pre>
<p>虽然网络不稳定, 但 Node 和 Proxy 之间的网络是非常稳定的, 比如两者在同一台机器上. Proxy 之间的会话不依赖连接, 所以可以基于 TCP 实现更健壮的连接.</p>
<p>对于 SSH, ProxyCommand 选项提供了非常简便的 SSH 客户端与隧道的接口, 使用该选项, SSH 客户端使用标准输入输出, 而不是 socket. 一个 Python 语言开发的程序, 证明了这种思路的正确性和可行性.</p>
<p>如果隧道使用了 HTTP 协议, 则可以穿越防火墙. 反过来, 建立于其上的 SSH, 也可以被用来进行加密通信.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/510.html' rel='bookmark' title='Permanent Link: SSH ProxyCommand及其思想'>SSH ProxyCommand及其思想</a></li>
<li><a href='http://www.ideawu.net/blog/archives/505.html' rel='bookmark' title='Permanent Link: PHP解析HTML和loadHTML乱码'>PHP解析HTML和loadHTML乱码</a></li>
<li><a href='http://www.ideawu.net/blog/archives/313.html' rel='bookmark' title='Permanent Link: C# 版的 SimpleXML'>C# 版的 SimpleXML</a></li>
<li><a href='http://www.ideawu.net/blog/archives/625.html' rel='bookmark' title='Permanent Link: Chrome浏览器必装的插件'>Chrome浏览器必装的插件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/514.html' rel='bookmark' title='Permanent Link: endlessssh &#8211; SSH 代理工具'>endlessssh &#8211; SSH 代理工具</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/511.html" title="endless_tcp &#8211; 一种适应极端网络环境的网络软件架构">endless_tcp &#8211; 一种适应极端网络环境的网络软件架构</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/511.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSH ProxyCommand及其思想</title>
		<link>http://www.ideawu.net/blog/archives/510.html</link>
		<comments>http://www.ideawu.net/blog/archives/510.html#comments</comments>
		<pubDate>Mon, 31 May 2010 16:47:42 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[P2P/Network]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/510.html</guid>
		<description><![CDATA[<p>OpenSSH 的客户端有一个 ProxyCommand 的选项, 用于 SSH 客户端与服务器之间的隧道通信(tunneling). 所谓的隧道技术, 也称代理技术, 是网络通信技术的一个普遍概念, 就是把一条信道建立于另外一条信道之上.</p>
<p>SSH 会话基于一个 TCP 连接. 如果我们把连接的两个端口各自的出口(也即入口)进行截获, 就可以用其它的信道来传输. 而且 SSH 仍然认为它用的是和另一端连接一条 TCP 连接.</p>
<p><span id="more-510"></span>ProxyCommand 指定一个命令(或程序, 称为 Proxy), SSH 客户端将通过标准输入输出和这个命令启动后的进程进行正常的 SSH 通信, 而 Proxy 连接着 SSH 服务器(一般是一个 Server Proxy, 再由该 Server Proxy 连接服务器). Proxy 和 Server Proxy 之间组成了一条隧道. 如果两者之间用 HTTP 协议进行通信, 则整个系统便称为&#8221;tunneling SSH over HTTP&#8221;, 当然也可以使用 UDP, TCP, IP 以及其它任意的可行的协议.</p>
<p>SSH ProxyCommand 相对于 SOCKS, HTTP 或者其它的 Proxy 技术, 更简单. 因为它工作在进程间的文件 IO 通信, 用任何支持 socket 的编程语言, 都能轻易地编写出一个可用的 Proxy. 复杂度只落在隧道本身. 想一想, 如果没有 ProxyCommand, 你需要改变或侵入操作系统的 TCP 子系统才能实现 SSH 隧道. ProxyCommand 提供了方便应用隧道的接口, 网络程序都应该提供这样的接口, 而不是完全依赖于 socket.</p>
<p>因为一个会话就会启动一个 ProxyCommand 进程, 所以, 只有在会话依赖于连接的协议上才能使用这种技术.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/511.html' rel='bookmark' title='Permanent Link: endless_tcp &#8211; 一种适应极端网络环境的网络软件架构'>endless_tcp &#8211; 一种适应极端网络环境的网络软件架构</a></li>
<li><a href='http://www.ideawu.net/blog/archives/537.html' rel='bookmark' title='Permanent Link: Lighttpd mod_fastcgi源码分析'>Lighttpd mod_fastcgi源码分析</a></li>
<li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/290.html' rel='bookmark' title='Permanent Link: Ideawu.P2P API 简介'>Ideawu.P2P API 简介</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/510.html" title="SSH ProxyCommand及其思想">SSH ProxyCommand及其思想</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>OpenSSH 的客户端有一个 ProxyCommand 的选项, 用于 SSH 客户端与服务器之间的隧道通信(tunneling). 所谓的隧道技术, 也称代理技术, 是网络通信技术的一个普遍概念, 就是把一条信道建立于另外一条信道之上.</p>
<p>SSH 会话基于一个 TCP 连接. 如果我们把连接的两个端口各自的出口(也即入口)进行截获, 就可以用其它的信道来传输. 而且 SSH 仍然认为它用的是和另一端连接一条 TCP 连接.</p>
<p><span id="more-510"></span>ProxyCommand 指定一个命令(或程序, 称为 Proxy), SSH 客户端将通过标准输入输出和这个命令启动后的进程进行正常的 SSH 通信, 而 Proxy 连接着 SSH 服务器(一般是一个 Server Proxy, 再由该 Server Proxy 连接服务器). Proxy 和 Server Proxy 之间组成了一条隧道. 如果两者之间用 HTTP 协议进行通信, 则整个系统便称为&#8221;tunneling SSH over HTTP&#8221;, 当然也可以使用 UDP, TCP, IP 以及其它任意的可行的协议.</p>
<p>SSH ProxyCommand 相对于 SOCKS, HTTP 或者其它的 Proxy 技术, 更简单. 因为它工作在进程间的文件 IO 通信, 用任何支持 socket 的编程语言, 都能轻易地编写出一个可用的 Proxy. 复杂度只落在隧道本身. 想一想, 如果没有 ProxyCommand, 你需要改变或侵入操作系统的 TCP 子系统才能实现 SSH 隧道. ProxyCommand 提供了方便应用隧道的接口, 网络程序都应该提供这样的接口, 而不是完全依赖于 socket.</p>
<p>因为一个会话就会启动一个 ProxyCommand 进程, 所以, 只有在会话依赖于连接的协议上才能使用这种技术.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/511.html' rel='bookmark' title='Permanent Link: endless_tcp &#8211; 一种适应极端网络环境的网络软件架构'>endless_tcp &#8211; 一种适应极端网络环境的网络软件架构</a></li>
<li><a href='http://www.ideawu.net/blog/archives/537.html' rel='bookmark' title='Permanent Link: Lighttpd mod_fastcgi源码分析'>Lighttpd mod_fastcgi源码分析</a></li>
<li><a href='http://www.ideawu.net/blog/archives/556.html' rel='bookmark' title='Permanent Link: lighttpd配置HTTPS(SSL)'>lighttpd配置HTTPS(SSL)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/447.html' rel='bookmark' title='Permanent Link: Linux下编译安装Apache/Lighttpd+PHP+MySQL'>Linux下编译安装Apache/Lighttpd+PHP+MySQL</a></li>
<li><a href='http://www.ideawu.net/blog/archives/290.html' rel='bookmark' title='Permanent Link: Ideawu.P2P API 简介'>Ideawu.P2P API 简介</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/510.html" title="SSH ProxyCommand及其思想">SSH ProxyCommand及其思想</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/510.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows Python select标准输入输出</title>
		<link>http://www.ideawu.net/blog/archives/508.html</link>
		<comments>http://www.ideawu.net/blog/archives/508.html#comments</comments>
		<pubDate>Sun, 30 May 2010 11:21:24 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[IO多路复用]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=508</guid>
		<description><![CDATA[<p>Windows 版本的 Python, select() 函数只能接受 socket, <a href="http://docs.python.org/library/select.html#select.select">不接受 File Object</a>, 所以不能 select 标准输入输出.</p>
<p>为此, 我开发了 win_stdio, 让 select 也能对 stdin/stdout 进行操作. 核心思想就是用 <a href="http://docs.python.org/library/socket.html">socket</a> 作为 stdin/stdout 的代理. 结构示意如下:</p>
<pre>
stdin -&gt; stdin_sock -&gt; my_stdin
stdout &lt;- stdout_sock &lt;- my_stdout
</pre>
<p><span id="more-508"></span>my_stdin 和 my_stdout 是 socket, 所以它们的 fileno 就可以用于 select 了.</p>
<p>首先一个线程读取 stdin, 写入 stdin_sock:</p>
<pre>
while True:
	data = os.read(sys.stdin.fileno(), 1024)
	if not data:
		break
	stdin_sock.send(data)
</pre>
<p>另一个线程读取 stdout_sock, 写入 stdout:</p>
<pre>
fd = sys.stdout.fileno()
while True:
	data = my_stdout.recv(1024)
	if not data:
		break
	os.write(sys.stdout.fileno(), data)
</pre>
<p>win_stdio 的一个实际例子如下:</p>
<pre>
from stdio import stdio
stdio.write('hello world')
data = stdio.read()
print stdio.STDIN_FILENO
print stdio.STDOUT_FILENO
</pre>
<p>下载: <a href='http://www.ideawu.net/blog/wp-content/uploads/2010/05/win_stdio.zip'>win_stdio.zip</a></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
<li><a href='http://www.ideawu.net/blog/archives/624.html' rel='bookmark' title='Permanent Link: Python logging 标准配置'>Python logging 标准配置</a></li>
<li><a href='http://www.ideawu.net/blog/archives/267.html' rel='bookmark' title='Permanent Link: 软件体系结构模式-层'>软件体系结构模式-层</a></li>
<li><a href='http://www.ideawu.net/blog/archives/270.html' rel='bookmark' title='Permanent Link: 使用Python POST任意的HTTP数据以及使用Cookie'>使用Python POST任意的HTTP数据以及使用Cookie</a></li>
<li><a href='http://www.ideawu.net/blog/archives/582.html' rel='bookmark' title='Permanent Link: PHP的continue 2'>PHP的continue 2</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/508.html" title="Windows Python select标准输入输出">Windows Python select标准输入输出</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>Windows 版本的 Python, select() 函数只能接受 socket, <a href="http://docs.python.org/library/select.html#select.select">不接受 File Object</a>, 所以不能 select 标准输入输出.</p>
<p>为此, 我开发了 win_stdio, 让 select 也能对 stdin/stdout 进行操作. 核心思想就是用 <a href="http://docs.python.org/library/socket.html">socket</a> 作为 stdin/stdout 的代理. 结构示意如下:</p>
<pre>
stdin -&gt; stdin_sock -&gt; my_stdin
stdout &lt;- stdout_sock &lt;- my_stdout
</pre>
<p><span id="more-508"></span>my_stdin 和 my_stdout 是 socket, 所以它们的 fileno 就可以用于 select 了.</p>
<p>首先一个线程读取 stdin, 写入 stdin_sock:</p>
<pre>
while True:
	data = os.read(sys.stdin.fileno(), 1024)
	if not data:
		break
	stdin_sock.send(data)
</pre>
<p>另一个线程读取 stdout_sock, 写入 stdout:</p>
<pre>
fd = sys.stdout.fileno()
while True:
	data = my_stdout.recv(1024)
	if not data:
		break
	os.write(sys.stdout.fileno(), data)
</pre>
<p>win_stdio 的一个实际例子如下:</p>
<pre>
from stdio import stdio
stdio.write('hello world')
data = stdio.read()
print stdio.STDIN_FILENO
print stdio.STDOUT_FILENO
</pre>
<p>下载: <a href='http://www.ideawu.net/blog/wp-content/uploads/2010/05/win_stdio.zip'>win_stdio.zip</a></p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
<li><a href='http://www.ideawu.net/blog/archives/624.html' rel='bookmark' title='Permanent Link: Python logging 标准配置'>Python logging 标准配置</a></li>
<li><a href='http://www.ideawu.net/blog/archives/267.html' rel='bookmark' title='Permanent Link: 软件体系结构模式-层'>软件体系结构模式-层</a></li>
<li><a href='http://www.ideawu.net/blog/archives/270.html' rel='bookmark' title='Permanent Link: 使用Python POST任意的HTTP数据以及使用Cookie'>使用Python POST任意的HTTP数据以及使用Cookie</a></li>
<li><a href='http://www.ideawu.net/blog/archives/582.html' rel='bookmark' title='Permanent Link: PHP的continue 2'>PHP的continue 2</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/508.html" title="Windows Python select标准输入输出">Windows Python select标准输入输出</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/508.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PyPy &#8211; 吞下自己尾巴的小蟒蛇</title>
		<link>http://www.ideawu.net/blog/archives/499.html</link>
		<comments>http://www.ideawu.net/blog/archives/499.html#comments</comments>
		<pubDate>Sun, 09 May 2010 13:30:01 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[PyPy]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/archives/499.html</guid>
		<description><![CDATA[<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/05/snake-eat-itself.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/05/snake-eat-itself.jpg" alt="" title="snake-eat-itself" width="128" height="128" class="alignright size-full wp-image-498" /></a></p>
<p><a href="http://www.pypy.org/">PyPy</a> 项目可能会颠覆老学究和初学者的逻辑, 因为 PyPy 用 Python 语言来实现 <a href="http://docs.python.org/reference/">Python</a> 语言, 就像一只小蟒蛇吞下自己的尾巴. 也许你没见过, 但它确实存在.</p>
<p>你可能会疑惑, 既然已经有了 Python, 那么为什么还用 Python 来实现 Python(PyPy)? 后者到底是什么东西?</p>
<p>其实, 这其中的逻辑并不复杂. 比如 C 语言, C 语言的第一个编译器肯定不是用 C 语言来编写的, 但之后, C 编译器(如 GCC)就没有理由不用 C 来编写了. 所以, 用 Python 语言编写, 并用已存在的 Python 编译器(解释器, 执行环境)来做一个实现 Python 语言并没有什么奇怪.</p>
<p><span id="more-499"></span><a href="http://www.pypy.org/"><img src="http://pypy.org/image/pypy-logo.png" alt="[pypy-logo]" /></a></p>
<p>简单地说, PyPy 是用 Python 语言写了一个工具, 将 Python 代码转成 C, .NET, Java 等语言和平台的代码. PHP 也有类似的项目 &#8211; <a href="http://www.hiphop-php.com/">HipHop-PHP</a>, 把 PHP 代码转成 C++ 代码.</p>
<p>为什么要将一种语言转成另一种语言? 首先是目标语言可能在性能(如C语言)和/或跨平台(如 .NET, Java)等方面具有优势. 其次, 在转换的过程, 可以进行代码优化或加入新技术, 比如 PyPy 应用的 Just-in-Time(JIT) 技术, 能让 Python (事实上是转换后的目标代码)的执行速度更快.</p>
<p>PyPy 和许多编译器, 解释器, 翻译器不同, 它不关心 Python 代码的词法分析和语法树. 因为它是用 Python 语言写的, 所以它直接利用 Python 语言的 <a href="http://docs.python.org/reference/datamodel.html">Code Object</a>. Code Object 是 Python 字节码的表示. 也就是说, PyPy <a href="http://codespeak.net/pypy/trunk/pypy/doc/architecture.html#id12">直接分析 Python 代码所对应的字节码</a>, 这些字节码即不是以字符形式也不是以某种二进制格式保存在文件中, 而在 Python 运行环境中.</p>
<p>越来越多的编程语言被设计成解释型, 但考虑到性能时, 几乎不约而同地想到转换成 C 语言. C 语言已经成为一个标杆, 任何编程语言都可以根据其距离 C 语言的远近来分类.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/269.html' rel='bookmark' title='Permanent Link: 开始学习 Python'>开始学习 Python</a></li>
<li><a href='http://www.ideawu.net/blog/archives/497.html' rel='bookmark' title='Permanent Link: 用脚本语言开发网游 &#8211; C整合Python'>用脚本语言开发网游 &#8211; C整合Python</a></li>
<li><a href='http://www.ideawu.net/blog/archives/508.html' rel='bookmark' title='Permanent Link: Windows Python select标准输入输出'>Windows Python select标准输入输出</a></li>
<li><a href='http://www.ideawu.net/blog/archives/357.html' rel='bookmark' title='Permanent Link: MySQL 查询使用 Group By 的注意点'>MySQL 查询使用 Group By 的注意点</a></li>
<li><a href='http://www.ideawu.net/blog/archives/334.html' rel='bookmark' title='Permanent Link: 小巧且强大的集成开发环境(IDE) &#8211; Code::Blocks'>小巧且强大的集成开发环境(IDE) &#8211; Code::Blocks</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/499.html" title="PyPy &#8211; 吞下自己尾巴的小蟒蛇">PyPy &#8211; 吞下自己尾巴的小蟒蛇</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/05/snake-eat-itself.jpg"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/05/snake-eat-itself.jpg" alt="" title="snake-eat-itself" width="128" height="128" class="alignright size-full wp-image-498" /></a></p>
<p><a href="http://www.pypy.org/">PyPy</a> 项目可能会颠覆老学究和初学者的逻辑, 因为 PyPy 用 Python 语言来实现 <a href="http://docs.python.org/reference/">Python</a> 语言, 就像一只小蟒蛇吞下自己的尾巴. 也许你没见过, 但它确实存在.</p>
<p>你可能会疑惑, 既然已经有了 Python, 那么为什么还用 Python 来实现 Python(PyPy)? 后者到底是什么东西?</p>
<p>其实, 这其中的逻辑并不复杂. 比如 C 语言, C 语言的第一个编译器肯定不是用 C 语言来编写的, 但之后, C 编译器(如 GCC)就没有理由不用 C 来编写了. 所以, 用 Python 语言编写, 并用已存在的 Python 编译器(解释器, 执行环境)来做一个实现 Python 语言并没有什么奇怪.</p>
<p><span id="more-499"></span><a href="http://www.pypy.org/"><img src="http://pypy.org/image/pypy-logo.png" alt="[pypy-logo]" /></a></p>
<p>简单地说, PyPy 是用 Python 语言写了一个工具, 将 Python 代码转成 C, .NET, Java 等语言和平台的代码. PHP 也有类似的项目 &#8211; <a href="http://www.hiphop-php.com/">HipHop-PHP</a>, 把 PHP 代码转成 C++ 代码.</p>
<p>为什么要将一种语言转成另一种语言? 首先是目标语言可能在性能(如C语言)和/或跨平台(如 .NET, Java)等方面具有优势. 其次, 在转换的过程, 可以进行代码优化或加入新技术, 比如 PyPy 应用的 Just-in-Time(JIT) 技术, 能让 Python (事实上是转换后的目标代码)的执行速度更快.</p>
<p>PyPy 和许多编译器, 解释器, 翻译器不同, 它不关心 Python 代码的词法分析和语法树. 因为它是用 Python 语言写的, 所以它直接利用 Python 语言的 <a href="http://docs.python.org/reference/datamodel.html">Code Object</a>. Code Object 是 Python 字节码的表示. 也就是说, PyPy <a href="http://codespeak.net/pypy/trunk/pypy/doc/architecture.html#id12">直接分析 Python 代码所对应的字节码</a>, 这些字节码即不是以字符形式也不是以某种二进制格式保存在文件中, 而在 Python 运行环境中.</p>
<p>越来越多的编程语言被设计成解释型, 但考虑到性能时, 几乎不约而同地想到转换成 C 语言. C 语言已经成为一个标杆, 任何编程语言都可以根据其距离 C 语言的远近来分类.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/269.html' rel='bookmark' title='Permanent Link: 开始学习 Python'>开始学习 Python</a></li>
<li><a href='http://www.ideawu.net/blog/archives/497.html' rel='bookmark' title='Permanent Link: 用脚本语言开发网游 &#8211; C整合Python'>用脚本语言开发网游 &#8211; C整合Python</a></li>
<li><a href='http://www.ideawu.net/blog/archives/508.html' rel='bookmark' title='Permanent Link: Windows Python select标准输入输出'>Windows Python select标准输入输出</a></li>
<li><a href='http://www.ideawu.net/blog/archives/357.html' rel='bookmark' title='Permanent Link: MySQL 查询使用 Group By 的注意点'>MySQL 查询使用 Group By 的注意点</a></li>
<li><a href='http://www.ideawu.net/blog/archives/334.html' rel='bookmark' title='Permanent Link: 小巧且强大的集成开发环境(IDE) &#8211; Code::Blocks'>小巧且强大的集成开发环境(IDE) &#8211; Code::Blocks</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/499.html" title="PyPy &#8211; 吞下自己尾巴的小蟒蛇">PyPy &#8211; 吞下自己尾巴的小蟒蛇</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/499.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>一对多关系的不稳定性</title>
		<link>http://www.ideawu.net/blog/archives/391.html</link>
		<comments>http://www.ideawu.net/blog/archives/391.html#comments</comments>
		<pubDate>Fri, 12 Jun 2009 10:24:04 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>
		<category><![CDATA[数据库设计]]></category>
		<category><![CDATA[架构]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=391</guid>
		<description><![CDATA[<p>经典的对象关系模型有三个: 一对一(one-to-one), 一对多(one-to-many), 多对多(many-to-many). 事实上, 一对多只是一种游离的中间状态, 任何设计中一旦使用了一对多关系, 迟早会发现只有多对多才能满足业务的变更. 对象关系要么是一对一, 要么是多对多, 没有一对多.</p>
<p>以博客程序作为例子, 想当然地, 认为博客作者只能是一个人, 所以用户和博客文章的关系是一对多的. 但是, 如果不把博客当为个人的日记本来使用, 把博客当做文章发布平台, 这时, 这个模型就不能使用了, 因为文章的作者是可以有多人的.</p>
<p>这只是其中一个例子, 你可能认为有真正的文章发布平台, 不应该把博客程序当做文章发布系统. 想想, 人们会本能地认为一个部门只能属于一个公司, 一个小组只能属于一个部门, 但是, 多个公司合办的交流部门呢? 两个部门合作的小组呢? 这种例子数不胜数.</p>
<p>根据我的经验, 一旦有人设计对象关系模型(如数据库设计)时使用出了一对多关系模型, 我们应该像看到了想抢我们饭碗的人一样警惕起来: 真的是一对多关系吗? 就跟我们问一个从天而降的不明类人生物: 你是地球人吗?</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/610.html' rel='bookmark' title='Permanent Link: 概率选取的实现'>概率选取的实现</a></li>
<li><a href='http://www.ideawu.net/blog/archives/580.html' rel='bookmark' title='Permanent Link: 主要排序算法的比较(精炼)'>主要排序算法的比较(精炼)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/526.html' rel='bookmark' title='Permanent Link: 以浏览器引擎为核心的软件架构'>以浏览器引擎为核心的软件架构</a></li>
<li><a href='http://www.ideawu.net/blog/archives/358.html' rel='bookmark' title='Permanent Link: Mesh: 对象的多对多关系'>Mesh: 对象的多对多关系</a></li>
<li><a href='http://www.ideawu.net/blog/archives/281.html' rel='bookmark' title='Permanent Link: 使用流水线来实现并发'>使用流水线来实现并发</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/391.html" title="一对多关系的不稳定性">一对多关系的不稳定性</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p>经典的对象关系模型有三个: 一对一(one-to-one), 一对多(one-to-many), 多对多(many-to-many). 事实上, 一对多只是一种游离的中间状态, 任何设计中一旦使用了一对多关系, 迟早会发现只有多对多才能满足业务的变更. 对象关系要么是一对一, 要么是多对多, 没有一对多.</p>
<p>以博客程序作为例子, 想当然地, 认为博客作者只能是一个人, 所以用户和博客文章的关系是一对多的. 但是, 如果不把博客当为个人的日记本来使用, 把博客当做文章发布平台, 这时, 这个模型就不能使用了, 因为文章的作者是可以有多人的.</p>
<p>这只是其中一个例子, 你可能认为有真正的文章发布平台, 不应该把博客程序当做文章发布系统. 想想, 人们会本能地认为一个部门只能属于一个公司, 一个小组只能属于一个部门, 但是, 多个公司合办的交流部门呢? 两个部门合作的小组呢? 这种例子数不胜数.</p>
<p>根据我的经验, 一旦有人设计对象关系模型(如数据库设计)时使用出了一对多关系模型, 我们应该像看到了想抢我们饭碗的人一样警惕起来: 真的是一对多关系吗? 就跟我们问一个从天而降的不明类人生物: 你是地球人吗?</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/610.html' rel='bookmark' title='Permanent Link: 概率选取的实现'>概率选取的实现</a></li>
<li><a href='http://www.ideawu.net/blog/archives/580.html' rel='bookmark' title='Permanent Link: 主要排序算法的比较(精炼)'>主要排序算法的比较(精炼)</a></li>
<li><a href='http://www.ideawu.net/blog/archives/526.html' rel='bookmark' title='Permanent Link: 以浏览器引擎为核心的软件架构'>以浏览器引擎为核心的软件架构</a></li>
<li><a href='http://www.ideawu.net/blog/archives/358.html' rel='bookmark' title='Permanent Link: Mesh: 对象的多对多关系'>Mesh: 对象的多对多关系</a></li>
<li><a href='http://www.ideawu.net/blog/archives/281.html' rel='bookmark' title='Permanent Link: 使用流水线来实现并发'>使用流水线来实现并发</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/391.html" title="一对多关系的不稳定性">一对多关系的不稳定性</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/391.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>基于列的数据库</title>
		<link>http://www.ideawu.net/blog/archives/388.html</link>
		<comments>http://www.ideawu.net/blog/archives/388.html#comments</comments>
		<pubDate>Thu, 28 May 2009 04:44:57 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false">http://www.ideawu.net/blog/?p=388</guid>
		<description><![CDATA[<p><strong>模糊想法, 请忽略.</strong></p>
<p>基于行的数据库可以通过一对多关系的表很容易地表示树形结构的对象. 但是, 基于列的数据库, 如何表示呢?</p>
<p>假设有一个对象实例, 它的某个字段是其它类型对象的列表. 这时, 如何用列的实例表示这个对象?</p>
<p>首先, 基于列的数据库, 任何对象的实例都可以用一个id列表, 该id一般设计为整数.</p>
<p>列实例(称为字段)不直接声明自己属于哪一个对象, 通过单独的存储对象和列实例的关系来表示原始对象(raw), 这种对象的每一个字段都是原始数据类型.</p>
<p>如果对象的某个字段是其它对象的列表, 如何表示?</p>
<p>这里使用对象与对象的关系表来存储.</p>
<p><span id="more-388"></span>* 对象定义, row&lt;name&gt;<br />
* 列定义, column&lt;name, type&gt;</p>
<p>* 对象表&lt;id&gt;<br />
* 字段表&lt;id, value&gt;<br />
* 对象与字段关系表&lt;oid, fid&gt;<br />
* 对象与对象关系表&lt;oid, oid&gt;</p>
<p>对象查询操作语言:</p>
<p>select column/object<br />
where &lt;condition&gt;</p>
<pre>
struct row{
	int id;
	char name[256];
};

struct column{
	int id;
	int type;
	char name[256];
};

struct object{
	int id;
	int row_id;
};

struct field{
	int id;
	int col_id;

	struct{
		int len;
		union{
			double number;
			char *bytes;
		};
	}value;
};

struct of_item{
	int oid;
	int fid;
};

struct oo_item{
	int id1;
	int id2;
};
</pre>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/399.html' rel='bookmark' title='Permanent Link: JavaScript+jQuery两栏选择控件'>JavaScript+jQuery两栏选择控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/508.html' rel='bookmark' title='Permanent Link: Windows Python select标准输入输出'>Windows Python select标准输入输出</a></li>
<li><a href='http://www.ideawu.net/blog/archives/412.html' rel='bookmark' title='Permanent Link: JavaScript分页控件'>JavaScript分页控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/388.html" title="基于列的数据库">基于列的数据库</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p><strong>模糊想法, 请忽略.</strong></p>
<p>基于行的数据库可以通过一对多关系的表很容易地表示树形结构的对象. 但是, 基于列的数据库, 如何表示呢?</p>
<p>假设有一个对象实例, 它的某个字段是其它类型对象的列表. 这时, 如何用列的实例表示这个对象?</p>
<p>首先, 基于列的数据库, 任何对象的实例都可以用一个id列表, 该id一般设计为整数.</p>
<p>列实例(称为字段)不直接声明自己属于哪一个对象, 通过单独的存储对象和列实例的关系来表示原始对象(raw), 这种对象的每一个字段都是原始数据类型.</p>
<p>如果对象的某个字段是其它对象的列表, 如何表示?</p>
<p>这里使用对象与对象的关系表来存储.</p>
<p><span id="more-388"></span>* 对象定义, row&lt;name&gt;<br />
* 列定义, column&lt;name, type&gt;</p>
<p>* 对象表&lt;id&gt;<br />
* 字段表&lt;id, value&gt;<br />
* 对象与字段关系表&lt;oid, fid&gt;<br />
* 对象与对象关系表&lt;oid, oid&gt;</p>
<p>对象查询操作语言:</p>
<p>select column/object<br />
where &lt;condition&gt;</p>
<pre>
struct row{
	int id;
	char name[256];
};

struct column{
	int id;
	int type;
	char name[256];
};

struct object{
	int id;
	int row_id;
};

struct field{
	int id;
	int col_id;

	struct{
		int len;
		union{
			double number;
			char *bytes;
		};
	}value;
};

struct of_item{
	int oid;
	int fid;
};

struct oo_item{
	int id1;
	int id2;
};
</pre>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/399.html' rel='bookmark' title='Permanent Link: JavaScript+jQuery两栏选择控件'>JavaScript+jQuery两栏选择控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/508.html' rel='bookmark' title='Permanent Link: Windows Python select标准输入输出'>Windows Python select标准输入输出</a></li>
<li><a href='http://www.ideawu.net/blog/archives/412.html' rel='bookmark' title='Permanent Link: JavaScript分页控件'>JavaScript分页控件</a></li>
<li><a href='http://www.ideawu.net/blog/archives/434.html' rel='bookmark' title='Permanent Link: 最简单的JavaScript两级联动示例'>最简单的JavaScript两级联动示例</a></li>
<li><a href='http://www.ideawu.net/blog/archives/535.html' rel='bookmark' title='Permanent Link: Master-Workers 模式处理高负载'>Master-Workers 模式处理高负载</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/388.html" title="基于列的数据库">基于列的数据库</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/388.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于每一个数据库表都应该有一个单一的字段作为主键的讨论</title>
		<link>http://www.ideawu.net/blog/archives/366.html</link>
		<comments>http://www.ideawu.net/blog/archives/366.html#comments</comments>
		<pubDate>Wed, 11 Mar 2009 12:03:07 +0000</pubDate>
		<dc:creator>ideawu</dc:creator>
				<category><![CDATA[Computer System]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[<p><strong>2010年5月6日更新: 只有真正懂得了这个道理的人, 才算真正理解了关系数据库. 如何才算懂得了这个道理? &#8211; 即使你有一百个理由要用关联主键, 你也能找到这唯一的一个理由放弃, 改而使用单一字段做主键.</strong></p>
<p>&#8212;&#8212;</p>
<p>在数据库设计中, 每一个表都应该有一个字段作为主键. 这个字段一般是自增整数字段, 或者某些数据库支持的自动产生不重复字符串的字段, 也可以是程序自己产生的唯一标识. 总之, 每一个数据库表都应该有一个单一的字段作为主键.</p>
<p>使用单一的字段作为表的主键, 有许多优点. 最重要的一条是可以通过一个原子属性(如整数, 字符串)来标识一行记录. 一旦可以方便地标识一行记录, 那么数据的查询, 更新, 删除也都非常简单.</p>
<p>如果一个表没有主键, 那么必须通过一行记录本身才能标识一行记录. 也就是, 你必须知道一行记录的每一个字段的值, 才能在 SQL 语句中操作这条记录.<br />
<span id="more-366"></span><br />
数据库表支持联合主键, 也就是使用表的至少2个字段作为主键. 使用联合主键的缺点和不使用主键的缺点有很大的相似性, 因为当联合主键所使用的字段越多, 联合主键的缺点就越来越趋近于不使用主键, 直到表的所有字段作为主键时, 和不使用主键几乎是完全相同的 &#8211; 除了前者不能存在重复行, </p>
<p>作为主键的字段一般使用自增整数字段, 因为绝大多数关系型数据库管理系统都支持这种字段类型, 而且速度快, 占用空间少. 一个害怕使用自增整数字段作为主键的理由是自增整数会回绕从而导致重复. 但这种担心是没有必要的. 对于最普通的32位无符号整数, 其最大值是在 Mysql 中是 4294967295(43亿) , 如果数据库表以每秒1条的速度保存记录, 那么一天也只能 86400 条(约10万条)记录, 需要 49710 天(约136年)之后才能发生重复. 幸运的是, 绝大多数系统产生数据的速度比这个假设慢得多了. 如果系统产生数据的速度确实足够快速, 则可以使用 64 位的长整型整数.</p>
<p>如果确实需要联合主键, 则可以使用 UNIQUE 索引来代替. 任何不得不使用联合主键的需求, 都是基于对关系数据库的错误理解而产生的. 并不是要用&quot;单一主键&quot;来覆盖&quot;复合主键&quot;的需求, 而是&quot;在表设计中, 单一主键是必须的, 用联合唯一索引来覆盖&#8217;复合主键&#8217;的需求&quot;.</p>
<p><strong>一个例子:</strong></p>
<p>表1: 使用联合主键(只是作为反面例子出现, 它应该被联合唯一索引代替)</p>
<p>table_a{<br />
&nbsp;&nbsp;&nbsp; field_a: PK;<br />
&nbsp;&nbsp;&nbsp; field_b: PK;<br />
&nbsp;&nbsp;&nbsp; field_&#8230;: PK<br />
&nbsp;&nbsp;&nbsp; field_c;<br />
}</p>
<p>表2: 不使用联合主键</p>
<p>table_b{<br />
&nbsp;&nbsp;&nbsp; id: PK;<br />
&nbsp;&nbsp;&nbsp; field_a: UNIQUE;<br />
&nbsp;&nbsp;&nbsp; field_b: UNIQUE;<br />
&nbsp;&nbsp;&nbsp; field_&#8230;: UNIQUE<br />
&nbsp;&nbsp;&nbsp; field_c;<br />
}</p>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/05/sql-complexity.png"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/05/sql-complexity.png" alt="" title="sql-complexity" width="257" height="122" class="alignright size-full wp-image-496" /></a></p>
<p><strong>* 联合主键导致数据操作复杂化</strong></p>
<p>这两种表定义都能反映相同的业务模型. 使用联合主键对保存数据的程序代码影响不大, 情况1通过联合主键保证不会产生重复数据, 但情况2通过联合唯一索引保存不会产生重复数据. 但对查找操作有不良影响, 同时影响到使用了查找功能的更新和删除操作. 考虑查找特定几条记录的情况:</p>
<p>表1: 查找 (field_a, filed_b, &#8230;) = [(1, 2, ...), (1, 3, ...), (2, 4, ...), ...] 这几条记录.<br />
表2: 查找 id = [1, 2, 3, ...] 这几条记录.</p>
<p>显然, 表2的描述更简洁, 从而使程序代码和 SQL 语句更简洁. 如果把所有的字段都作为主键, 那么表1就不存在查找特定几条记录的功能了, &quot;因为已经知道, 所以不必再找&quot;. 这是一种最极端的联合主键的副作用, 联合主键的字段越多, 就越趋向于这种极端.</p>
<p><strong>* 联合主键不利于表示&quot;关系&quot;</strong></p>
<p>联合主键不利于表示&quot;关系&quot;, 是因为它会造成不必要的冗余. 考虑有另外两个表, 需要分别关联 table_a 和 table_b:</p>
<p>table_ac{<br />
&nbsp;&nbsp;&nbsp; id;<br />
&nbsp;&nbsp;&nbsp; table_a_field_a;<br />
&nbsp;&nbsp;&nbsp; table_b_field_b;<br />
&nbsp;&nbsp;&nbsp; &#8230;<br />
}</p>
<p>table_bc{<br />
&nbsp;&nbsp;&nbsp; id;<br />
&nbsp;&nbsp;&nbsp; table_b_id;<br />
}</p>
<p>显然, 不使用联合主键可以减少冗余. 如果使用所有字段作为联合主键, 将变成把 table_a 的数据保存两份, 一份在 table_a, 另一份包含在 table_ac. 个人认为, 联合主键是是关系数据库理论一种概念, 在实际中如果使用是&quot;反关系数据库模型&quot;的, 实际使用应该用联合唯一索引替代.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/542.html' rel='bookmark' title='Permanent Link: 以浏览器为核心的客户端软件的安全问题'>以浏览器为核心的客户端软件的安全问题</a></li>
<li><a href='http://www.ideawu.net/blog/archives/514.html' rel='bookmark' title='Permanent Link: endlessssh &#8211; SSH 代理工具'>endlessssh &#8211; SSH 代理工具</a></li>
<li><a href='http://www.ideawu.net/blog/archives/329.html' rel='bookmark' title='Permanent Link: 一种有趣的编程模型'>一种有趣的编程模型</a></li>
<li><a href='http://www.ideawu.net/blog/archives/302.html' rel='bookmark' title='Permanent Link: 生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论'>生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论</a></li>
<li><a href='http://www.ideawu.net/blog/archives/223.html' rel='bookmark' title='Permanent Link: AMD收购ATI 的意义'>AMD收购ATI 的意义</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/366.html" title="关于每一个数据库表都应该有一个单一的字段作为主键的讨论">关于每一个数据库表都应该有一个单一的字段作为主键的讨论</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></description>
			<content:encoded><![CDATA[<p><strong>2010年5月6日更新: 只有真正懂得了这个道理的人, 才算真正理解了关系数据库. 如何才算懂得了这个道理? &#8211; 即使你有一百个理由要用关联主键, 你也能找到这唯一的一个理由放弃, 改而使用单一字段做主键.</strong></p>
<p>&#8212;&#8212;</p>
<p>在数据库设计中, 每一个表都应该有一个字段作为主键. 这个字段一般是自增整数字段, 或者某些数据库支持的自动产生不重复字符串的字段, 也可以是程序自己产生的唯一标识. 总之, 每一个数据库表都应该有一个单一的字段作为主键.</p>
<p>使用单一的字段作为表的主键, 有许多优点. 最重要的一条是可以通过一个原子属性(如整数, 字符串)来标识一行记录. 一旦可以方便地标识一行记录, 那么数据的查询, 更新, 删除也都非常简单.</p>
<p>如果一个表没有主键, 那么必须通过一行记录本身才能标识一行记录. 也就是, 你必须知道一行记录的每一个字段的值, 才能在 SQL 语句中操作这条记录.<br />
<span id="more-366"></span><br />
数据库表支持联合主键, 也就是使用表的至少2个字段作为主键. 使用联合主键的缺点和不使用主键的缺点有很大的相似性, 因为当联合主键所使用的字段越多, 联合主键的缺点就越来越趋近于不使用主键, 直到表的所有字段作为主键时, 和不使用主键几乎是完全相同的 &#8211; 除了前者不能存在重复行, </p>
<p>作为主键的字段一般使用自增整数字段, 因为绝大多数关系型数据库管理系统都支持这种字段类型, 而且速度快, 占用空间少. 一个害怕使用自增整数字段作为主键的理由是自增整数会回绕从而导致重复. 但这种担心是没有必要的. 对于最普通的32位无符号整数, 其最大值是在 Mysql 中是 4294967295(43亿) , 如果数据库表以每秒1条的速度保存记录, 那么一天也只能 86400 条(约10万条)记录, 需要 49710 天(约136年)之后才能发生重复. 幸运的是, 绝大多数系统产生数据的速度比这个假设慢得多了. 如果系统产生数据的速度确实足够快速, 则可以使用 64 位的长整型整数.</p>
<p>如果确实需要联合主键, 则可以使用 UNIQUE 索引来代替. 任何不得不使用联合主键的需求, 都是基于对关系数据库的错误理解而产生的. 并不是要用&quot;单一主键&quot;来覆盖&quot;复合主键&quot;的需求, 而是&quot;在表设计中, 单一主键是必须的, 用联合唯一索引来覆盖&#8217;复合主键&#8217;的需求&quot;.</p>
<p><strong>一个例子:</strong></p>
<p>表1: 使用联合主键(只是作为反面例子出现, 它应该被联合唯一索引代替)</p>
<p>table_a{<br />
&nbsp;&nbsp;&nbsp; field_a: PK;<br />
&nbsp;&nbsp;&nbsp; field_b: PK;<br />
&nbsp;&nbsp;&nbsp; field_&#8230;: PK<br />
&nbsp;&nbsp;&nbsp; field_c;<br />
}</p>
<p>表2: 不使用联合主键</p>
<p>table_b{<br />
&nbsp;&nbsp;&nbsp; id: PK;<br />
&nbsp;&nbsp;&nbsp; field_a: UNIQUE;<br />
&nbsp;&nbsp;&nbsp; field_b: UNIQUE;<br />
&nbsp;&nbsp;&nbsp; field_&#8230;: UNIQUE<br />
&nbsp;&nbsp;&nbsp; field_c;<br />
}</p>
<p><a href="http://www.ideawu.net/blog/wp-content/uploads/2010/05/sql-complexity.png"><img src="http://www.ideawu.net/blog/wp-content/uploads/2010/05/sql-complexity.png" alt="" title="sql-complexity" width="257" height="122" class="alignright size-full wp-image-496" /></a></p>
<p><strong>* 联合主键导致数据操作复杂化</strong></p>
<p>这两种表定义都能反映相同的业务模型. 使用联合主键对保存数据的程序代码影响不大, 情况1通过联合主键保证不会产生重复数据, 但情况2通过联合唯一索引保存不会产生重复数据. 但对查找操作有不良影响, 同时影响到使用了查找功能的更新和删除操作. 考虑查找特定几条记录的情况:</p>
<p>表1: 查找 (field_a, filed_b, &#8230;) = [(1, 2, ...), (1, 3, ...), (2, 4, ...), ...] 这几条记录.<br />
表2: 查找 id = [1, 2, 3, ...] 这几条记录.</p>
<p>显然, 表2的描述更简洁, 从而使程序代码和 SQL 语句更简洁. 如果把所有的字段都作为主键, 那么表1就不存在查找特定几条记录的功能了, &quot;因为已经知道, 所以不必再找&quot;. 这是一种最极端的联合主键的副作用, 联合主键的字段越多, 就越趋向于这种极端.</p>
<p><strong>* 联合主键不利于表示&quot;关系&quot;</strong></p>
<p>联合主键不利于表示&quot;关系&quot;, 是因为它会造成不必要的冗余. 考虑有另外两个表, 需要分别关联 table_a 和 table_b:</p>
<p>table_ac{<br />
&nbsp;&nbsp;&nbsp; id;<br />
&nbsp;&nbsp;&nbsp; table_a_field_a;<br />
&nbsp;&nbsp;&nbsp; table_b_field_b;<br />
&nbsp;&nbsp;&nbsp; &#8230;<br />
}</p>
<p>table_bc{<br />
&nbsp;&nbsp;&nbsp; id;<br />
&nbsp;&nbsp;&nbsp; table_b_id;<br />
}</p>
<p>显然, 不使用联合主键可以减少冗余. 如果使用所有字段作为联合主键, 将变成把 table_a 的数据保存两份, 一份在 table_a, 另一份包含在 table_ac. 个人认为, 联合主键是是关系数据库理论一种概念, 在实际中如果使用是&quot;反关系数据库模型&quot;的, 实际使用应该用联合唯一索引替代.</p>


<h3>Related posts:</h3><ol><li><a href='http://www.ideawu.net/blog/archives/542.html' rel='bookmark' title='Permanent Link: 以浏览器为核心的客户端软件的安全问题'>以浏览器为核心的客户端软件的安全问题</a></li>
<li><a href='http://www.ideawu.net/blog/archives/514.html' rel='bookmark' title='Permanent Link: endlessssh &#8211; SSH 代理工具'>endlessssh &#8211; SSH 代理工具</a></li>
<li><a href='http://www.ideawu.net/blog/archives/329.html' rel='bookmark' title='Permanent Link: 一种有趣的编程模型'>一种有趣的编程模型</a></li>
<li><a href='http://www.ideawu.net/blog/archives/302.html' rel='bookmark' title='Permanent Link: 生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论'>生产者消费者模型中生产者的速度快于消费者时所产生的问题及其解决方法讨论</a></li>
<li><a href='http://www.ideawu.net/blog/archives/223.html' rel='bookmark' title='Permanent Link: AMD收购ATI 的意义'>AMD收购ATI 的意义</a></li>
</ol><div><p><img src="http://www.ideawu.net/favicon.ico" /> 你现在看的文章是: <a href="http://www.ideawu.net/blog/archives/366.html" title="关于每一个数据库表都应该有一个单一的字段作为主键的讨论">关于每一个数据库表都应该有一个单一的字段作为主键的讨论</a></p>

<div>
	<a href="http://www.benegg.com/linode-ad.php">
		Linode VPS - 美国虚拟主机
	</a>
	|
	<a href="http://www.udpwork.com/">
		IT牛人博客聚合网站
	</a>
</div></div>]]></content:encoded>
			<wfw:commentRss>http://www.ideawu.net/blog/archives/366.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

