<?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>IT妖怪 &#187; 服务端技术</title>
	<atom:link href="http://blog.ityao.com/archives/category/backend/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.ityao.com</link>
	<description>热爱生活，热爱程序</description>
	<lastBuildDate>Wed, 03 Aug 2011 02:56:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>闲谈分布式key-value存储服务nuclear及其他</title>
		<link>http://blog.ityao.com/archives/559</link>
		<comments>http://blog.ityao.com/archives/559#comments</comments>
		<pubDate>Mon, 29 Mar 2010 08:02:58 +0000</pubDate>
		<dc:creator>零蛋</dc:creator>
				<category><![CDATA[JAVA EE]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[服务端技术]]></category>
		<category><![CDATA[nuclear]]></category>
		<category><![CDATA[人人网]]></category>

		<guid isPermaLink="false">http://blog.ityao.com/?p=559</guid>
		<description><![CDATA[现在很多国内公司都纷纷开始了key-value的nosql存储方式，然而，从什么时候开始key-value会变得这么流行呢？是风靡一时，还是顺应时代的潮流？前后数一数，有豆瓣网的beandb、有新浪的SDD、小道消息还有腾讯的TDB以及人人网的nuclear。再数国外，吹起这阵风的原因是亚马逊的一篇文档，这篇文档讲述了在亚马逊的S3服务中所使用的存储系统dynamo实现方式，但遗憾的是dynamo并不开源。紧随其后，facebook来了位号称是当年亚马逊dynamo的开发人员之一的同志，实现了facebook的cassandra，并且值得表扬的是还将其开源了。与此同时，相同理论下产生的，还有linkedin的voldemort系统。 百家争鸣还是百家讲坛 分布式存储的目标，是解决大规模数据在数据量不断增长的情况下，让服务更加稳定，更容易扩展。 其主要具备以下几个特点： 1.高可靠性：系统能够长时间高效运行不迭机。严格的说即使坏了一部分机器也没事。 2.可扩展性：可以随意增加减少机器，不用担心额外的数据损失。 3.负载均衡：要保证每个节点的数据都是负载均衡的，不出现集中负载到一个节点的情况。 4.一致性：因为是分布式的节点，就需要保证节点与节点之间保存数据的一致。 鱼与熊掌不可兼得，这几点，往往完成了其中几点就会损失另外一点，要全部达到完美，是一件非常困难的事情。 在国内的几个存储来看，基本都是只实现了其中的一部分，再按照自己业务的需求，来加强其中更为关心的建设。 beansdb的最终一致性通过哈希树实现快速完整数据同步（短时间内数据可能不一致）；可以在不中断服务的情况下进行容量扩展；异步IO和高性能的KeyValue数据TokyoCabinet：通过N,W,R进行配置（这点其实是dynamo的文档里的方案，并非beansdb所创）；Memcache兼容协议，大量可用客户端。sdd也大同小异。 Nuclear完成了这些功能，并且可以适配到mysql\tc\bdb等存储引擎之上。 为什么已经有开源的项目，还要去自己实现呢？简单的说，twitter敢用，你敢用吗？ 分布式key-value存储之所以稳定的原因 从设计之初，注定这个系统会很稳定。为什么呢，主要是下面几点： 1.dynamo文档中的NWR的观点，可以让节点在损坏的情况下也能稳定如新。基本上这些系统都实现了。 2.dynamo文档中的两层数据节点的观点，可以让各节点在大负载的情况下负载均衡。部分实现了这一点。 3.底层存储的时候是key-value的读和取，只有一个维度的底层操作，对引擎来说，所有的操作都是可计算时间的。这一点的意思是说，假设都是MYSQL的底层存储，这个系统只会有一堆的select value form table where key=num这样的查询，而不会出现select * from table where key in(num1,num2,num3….)这样的查询，这两个查询不同的地方在于，如果都是1000次的查询，那么前一条的时间是可以准确预估的，而后一条取决于mysql底层实现的逻辑，而这个逻辑对上层是不可见的。 更多不明原因。。。 适合使用的范围 这套系统也不是放之四海而皆准的东西，如果说您的系统有如下的特征，可以考虑考虑： 1.数据插入后不需要各维度的查询。 2.数据不需要100%精确立即展示。 更多不明特点。 总结 其实这个系统，在过十亿的数据量下才有意思。 本文作者： 54chen(陈臻)，人人网分布式存储研究人员，业余时间混迹于各技术组织且乐此不疲。目前关注实施PHP培训。对flex等前端技术有一点研究。 个人技术站点:http://www.54chen.com/ 。可以通过电子邮件 czhttp@gmail.com 联系到他。 [文中所提及的链接] beansDB:http://code.google.com/p/beansdb/ SDD:http://code.google.com/p/sina-sdd/ Nuclear:http://ugc.renren.com S3:http://aws.amazon.com/s3/ dynamo:http://s3.amazonaws.com/AllThingsDistributed/sosp/amazon-dynamo-sosp2007.pdf cassandra:http://incubator.apache.org/cassandra/ voldemort:http://project-voldemort.com/]]></description>
			<content:encoded><![CDATA[<p>现在很多国内公司都纷纷开始了key-value的nosql存储方式，然而，从什么时候开始key-value会变得这么流行呢？是风靡一时，还是顺应时代的潮流？前后数一数，有豆瓣网的beandb、有新浪的SDD、小道消息还有腾讯的TDB以及人人网的nuclear。再数国外，吹起这阵风的原因是亚马逊的一篇文档，这篇文档讲述了在亚马逊的S3服务中所使用的存储系统dynamo实现方式，但遗憾的是dynamo并不开源。紧随其后，facebook来了位号称是当年亚马逊dynamo的开发人员之一的同志，实现了facebook的cassandra，并且值得表扬的是还将其开源了。与此同时，相同理论下产生的，还有linkedin的voldemort系统。<span id="more-559"></span></p>
<p><strong>百家争鸣还是百家讲坛</strong></p>
<p>分布式存储的目标，是解决大规模数据在数据量不断增长的情况下，让服务更加稳定，更容易扩展。</p>
<p>其主要具备以下几个特点：</p>
<p>1.高可靠性：系统能够长时间高效运行不迭机。严格的说即使坏了一部分机器也没事。</p>
<p>2.可扩展性：可以随意增加减少机器，不用担心额外的数据损失。</p>
<p>3.负载均衡：要保证每个节点的数据都是负载均衡的，不出现集中负载到一个节点的情况。</p>
<p>4.一致性：因为是分布式的节点，就需要保证节点与节点之间保存数据的一致。</p>
<p>鱼与熊掌不可兼得，这几点，往往完成了其中几点就会损失另外一点，要全部达到完美，是一件非常困难的事情。</p>
<p>在国内的几个存储来看，基本都是只实现了其中的一部分，再按照自己业务的需求，来加强其中更为关心的建设。</p>
<p>beansdb的最终一致性通过哈希树实现快速完整数据同步（短时间内数据可能不一致）；可以在不中断服务的情况下进行容量扩展；异步IO和高性能的KeyValue数据TokyoCabinet：通过N,W,R进行配置（这点其实是dynamo的文档里的方案，并非beansdb所创）；Memcache兼容协议，大量可用客户端。sdd也大同小异。</p>
<p>Nuclear完成了这些功能，并且可以适配到mysql\tc\bdb等存储引擎之上。</p>
<p>为什么已经有开源的项目，还要去自己实现呢？简单的说，twitter敢用，你敢用吗？</p>
<p><strong>分布式key-value存储之所以稳定的原因</strong></p>
<p>从设计之初，注定这个系统会很稳定。为什么呢，主要是下面几点：</p>
<p>1.dynamo文档中的NWR的观点，可以让节点在损坏的情况下也能稳定如新。基本上这些系统都实现了。</p>
<p>2.dynamo文档中的两层数据节点的观点，可以让各节点在大负载的情况下负载均衡。部分实现了这一点。</p>
<p>3.底层存储的时候是key-value的读和取，只有一个维度的底层操作，对引擎来说，所有的操作都是可计算时间的。这一点的意思是说，假设都是MYSQL的底层存储，这个系统只会有一堆的select value form table where key=num这样的查询，而不会出现select * from table where key in(num1,num2,num3….)这样的查询，这两个查询不同的地方在于，如果都是1000次的查询，那么前一条的时间是可以准确预估的，而后一条取决于mysql底层实现的逻辑，而这个逻辑对上层是不可见的。</p>
<p>更多不明原因。。。</p>
<p><strong>适合使用的范围</strong></p>
<p>这套系统也不是放之四海而皆准的东西，如果说您的系统有如下的特征，可以考虑考虑：</p>
<p>1.数据插入后不需要各维度的查询。</p>
<p>2.数据不需要100%精确立即展示。</p>
<p>更多不明特点。</p>
<p><strong>总结</strong></p>
<p>其实这个系统，在过十亿的数据量下才有意思。<br />
本文作者：<br />
54chen(陈臻)，人人网分布式存储研究人员，业余时间混迹于各技术组织且乐此不疲。目前关注实施PHP培训。对flex等前端技术有一点研究。<br />
个人技术站点:<a href="http://www.54chen.com/">http://www.54chen.com/</a> 。可以通过电子邮件 czhttp@gmail.com 联系到他。</p>
<p><strong>[文中所提及的链接]</strong></p>
<p>beansDB:http://code.google.com/p/beansdb/</p>
<p>SDD:http://code.google.com/p/sina-sdd/</p>
<p>Nuclear:http://ugc.renren.com</p>
<p>S3:http://aws.amazon.com/s3/</p>
<p>dynamo:http://s3.amazonaws.com/AllThingsDistributed/sosp/amazon-dynamo-sosp2007.pdf</p>
<p>cassandra:http://incubator.apache.org/cassandra/</p>
<p>voldemort:http://project-voldemort.com/</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/559/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Twisted]-Hello World</title>
		<link>http://blog.ityao.com/archives/450</link>
		<comments>http://blog.ityao.com/archives/450#comments</comments>
		<pubDate>Mon, 02 Nov 2009 04:12:35 +0000</pubDate>
		<dc:creator>Daniel Yang</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[twisted]]></category>

		<guid isPermaLink="false">http://blog.ityao.com/?p=450</guid>
		<description><![CDATA[使用一下twisted的getPage功能. 体会python语法特点. 代码: 说明: 1. python中, 注释一般是用 &#8221;&#8217; 这种方式 &#8221;&#8217; 的. 2. 没有{}来表示运行块, 用indent的深度来识别; 不适用分号来表示语句结束. 3. 指定encode的标记十分特别. 4. callback方式的. 5. Deferred对象来自于twisted.internet.defer.Deferred. 6.Python是case sensitive&#8230; 如果程序运行正常, 可以获得google首页所有的html代码.]]></description>
			<content:encoded><![CDATA[<p>使用一下twisted的getPage功能. 体会python语法特点.</p>
<p>代码:</p>
<pre class="brush: python; title: ; notranslate">
# -*- coding: utf-8 -*-

from twisted.web.client import getPage
from twisted.internet import reactor

def printContents(contents):

	print &quot;获得内容:&quot;
	print contents.upper()

	reactor.stop()

def errorHandler(error):
	print error

	reactor.stop()

#请求
deferred = getPage(&quot;http://localhost/test/Babel_s/yappr.php&quot;)

#添加回调
deferred.addCallback(printContents)
deferred.addErrback(errorHandler)

#反应堆~
reactor.run()
</pre>
<p>说明:<br />
1. python中, 注释一般是用 &#8221;&#8217; 这种方式 &#8221;&#8217; 的.<br />
2. 没有{}来表示运行块, 用indent的深度来识别; 不适用分号来表示语句结束.<br />
3. 指定encode的标记十分特别.<br />
4. callback方式的.<br />
5. Deferred对象来自于twisted.internet.defer.Deferred.<br />
6.Python是case sensitive&#8230;</p>
<p>如果程序运行正常, 可以获得google首页所有的html代码.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/450/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Twisted]基础介绍.安装</title>
		<link>http://blog.ityao.com/archives/448</link>
		<comments>http://blog.ityao.com/archives/448#comments</comments>
		<pubDate>Mon, 02 Nov 2009 04:10:50 +0000</pubDate>
		<dc:creator>Daniel Yang</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[twisted]]></category>

		<guid isPermaLink="false">http://blog.ityao.com/?p=448</guid>
		<description><![CDATA[介绍 twisted 是python下一个事件驱动的网络引擎库, 支持很多种的协议. 它包含了一个web服务, 多种IM客户端,服务端, 邮件服务协议. 由于规模庞大, twisted分成了几个sub-project. 一起或者分开发布. 稳定性 twisted并不是从0.1发展到8.1.0的. 是一下子跳到8的. 8.1.0是最新的stable的包. 从successful stories来看, 它的客户包括NASA这种级别的(http://twistedmatrix.com/trac/wiki/SuccessStories#NASA). 效率 twisted具有惊人的效率. 下面是一些twisted和Mina对比测试数据. http://blog.bluendo.com/ff/mina-and-twisted-matrix-benchmarks Leopard下的安装 下载, 运行. 建议是从源码安装。 windows下，可能需要安装openssl相关的库。]]></description>
			<content:encoded><![CDATA[<p>介绍<br />
twisted 是python下一个事件驱动的网络引擎库, 支持很多种的协议.<br />
它包含了一个web服务, 多种IM客户端,服务端, 邮件服务协议. 由于规模庞大, twisted分成了几个sub-project. 一起或者分开发布.<br />
<span id="more-448"></span></p>
<p>稳定性<br />
twisted并不是从0.1发展到8.1.0的. 是一下子跳到8的. 8.1.0是最新的stable的包.<br />
从successful stories来看, 它的客户包括NASA这种级别的(http://twistedmatrix.com/trac/wiki/SuccessStories#NASA). </p>
<p>效率<br />
twisted具有惊人的效率.<br />
下面是一些twisted和Mina对比测试数据.</p>
<p>http://blog.bluendo.com/ff/mina-and-twisted-matrix-benchmarks</p>
<p>Leopard下的安装<br />
下载, 运行.<br />
建议是从源码安装。<br />
windows下，可能需要安装openssl相关的库。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/448/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend AMF使用总结-服务端</title>
		<link>http://blog.ityao.com/archives/430</link>
		<comments>http://blog.ityao.com/archives/430#comments</comments>
		<pubDate>Mon, 28 Sep 2009 14:35:23 +0000</pubDate>
		<dc:creator>Daniel Yang</dc:creator>
				<category><![CDATA[Php]]></category>
		<category><![CDATA[Adobe Flex]]></category>
		<category><![CDATA[amf]]></category>
		<category><![CDATA[zend]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://blog.ityao.com/?p=430</guid>
		<description><![CDATA[Zend Framework是php框架中的战斗机。各种功能应有尽有，没有的网上也能找到插件，helper, filter&#8230;.而对于这样庞大的框架，最重要的就是配置了。 最近我作了一些尝试，在Zend Framework下使用AMF。现在把一些主要点共享给大家。 Tip 1，项目结构 这是刚接触ZF的同学们最头疼的。网上众说纷纭，其实很简单。 ZF发布的时候，bin目录下带有几个可运行的命令文件（包含各种系统了）。直接运行就可以了。 在这里，我是这样使用的(Mac Osx): 运行后，就会得到一个类似于这样的目录结构。 这里有个提示，尽管你可以把Zend文件夹（ZF的主要库文件）copy到刚才生成项目目录下的library里，我还是建议，一个服务器上维持一个ZF lib，这样升级起来容易。 现在可以把web服务器的服务地址只想我们生成目录bravo的public&#8212;这样，用户只能访问这个piblic目录中的文件，而程序文件是在application目录的，主要是安全。 好，打开浏览器，按照你配置的url来访问，应该能看到一个ZF生成的简单页面了。 Tip 2 index.php配置 ZF生成的public目录中，有一个index.php文件。这个文件是ZF应用的入口。这里的配置，主要是一些常量和ZF lib的位置。 比如我就是这样配置的： Tip 3 配置文件 ZF生成的application.ini文件位于/application/configs/下, 这个目录也经常会放其他配置文件，如route，i18n等。 配置文件一定不能乱了。我们按照dev, prod两种环境来配置。 Tip 4 AMF 服务的编写 这个很简单。 不需要继承任何类。 顺便说说gateway的提供。ZF中，gateway是一个controller。里面的内容比较常规： Tip 5 Bootstrap 最主要的是初始化name space和数据库连接 Tip 6 Value Object的传输 最让我头疼的。我现在的做法是，不使用ZF的Model, 直接用DbAdapter. 所以，我在Model里定义的其实是VO. 定义一个Base: 那么， User的Model就是： 在从数据库中取得数据后： 下一篇我们说客户端-应该是很简单了。]]></description>
			<content:encoded><![CDATA[<p><a href="http://framework.zend.com/" target="_blank">Zend Framework</a>是php框架中的战斗机。各种功能应有尽有，没有的网上也能找到插件，helper, filter&#8230;.而对于这样庞大的框架，最重要的就是配置了。</p>
<p>最近我作了一些尝试，在Zend Framework下使用AMF。现在把一些主要点共享给大家。</p>
<p><span id="more-430"></span></p>
<p>Tip 1，项目结构<br />
这是刚接触ZF的同学们最头疼的。网上众说纷纭，其实很简单。<br />
ZF发布的时候，bin目录下带有几个可运行的命令文件（包含各种系统了）。直接运行就可以了。<br />
在这里，我是这样使用的(Mac Osx):</p>
<pre class="brush: bash; title: ; notranslate">
Yang:~ daniel$ ./zf.sh create project website
</pre>
<p>运行后，就会得到一个类似于这样的目录结构。<br />
<a href="http://blog.ityao.com/wp-content/uploads/2009/09/Screen-shot-2009-09-28-at-5.43.30-PM.png"><img src="http://blog.ityao.com/wp-content/uploads/2009/09/Screen-shot-2009-09-28-at-5.43.30-PM.png" alt="Screen shot 2009-09-28 at 5.43.30 PM" title="Screen shot 2009-09-28 at 5.43.30 PM" width="221" height="505" class="alignnone size-full wp-image-432" /></a></p>
<p>这里有个提示，尽管你可以把Zend文件夹（ZF的主要库文件）copy到刚才生成项目目录下的library里，我还是建议，一个服务器上维持一个ZF lib，这样升级起来容易。</p>
<p>现在可以把web服务器的服务地址只想我们生成目录bravo的public&#8212;这样，用户只能访问这个piblic目录中的文件，而程序文件是在application目录的，主要是安全。<br />
好，打开浏览器，按照你配置的url来访问，应该能看到一个ZF生成的简单页面了。</p>
<p>Tip 2 index.php配置<br />
ZF生成的public目录中，有一个index.php文件。这个文件是ZF应用的入口。这里的配置，主要是一些常量和ZF lib的位置。<br />
比如我就是这样配置的：</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

//这个是amf service的目录
define('SERVICES_PATH', APPLICATION_PATH . '/services');

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../../library'),
    get_include_path(),
)));

/** Zend_Application */
require_once '../../library/Zend/Application.php';  

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);

$application-&gt;bootstrap()
            -&gt;run();
</pre>
<p>Tip 3 配置文件<br />
ZF生成的application.ini文件位于/application/configs/下, 这个目录也经常会放其他配置文件，如route，i18n等。<br />
配置文件一定不能乱了。我们按照dev, prod两种环境来配置。</p>
<pre class="brush: plain; title: ; notranslate">
[general]
;includePaths.library = APPLICATION_PATH &quot;/../../library&quot;
bootstrap.path = APPLICATION_PATH &quot;/Bootstrap.php&quot;
bootstrap.class = &quot;Bootstrap&quot;
resources.frontController.controllerDirectory = APPLICATION_PATH &quot;/controllers&quot;

;database
resources.db.adapter = &quot;PDO_MYSQL&quot;
resources.db.isdefaulttableadapter = true
resources.db.params.driver_options.1002 = &quot;SET NAMES UTF8;&quot;

[development : general]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

resources.db.params.host = localhost
resources.db.params.username = bravo
resources.db.params.password = Z4wL6h8pA4KS5yDZ
resources.db.params.dbname = bravo

[production : general]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

resources.db.params.host = 127.0.0.1
resources.db.params.username = test
resources.db.params.password = test
resources.db.params.dbname = test
</pre>
<p>Tip 4 AMF 服务的编写<br />
这个很简单。<br />
不需要继承任何类。</p>
<p>顺便说说gateway的提供。ZF中，gateway是一个controller。里面的内容比较常规：</p>
<pre class="brush: php; title: ; notranslate">

&lt;?php

	class GatewayController extends Zend_Controller_Action{

		public function init(){
			$this-&gt;getHelper('ViewRenderer')-&gt;setNoRender();
		}

		public function indexAction(){
			$server = new Zend_Amf_Server();
			$server-&gt;setSession('Bravo');
			Zend_Session::start(); //让amf服务支持session

			$server-&gt;addDirectory(SERVICES_PATH);//index.php中声明的，服务所在的目录
			//类的映射。
			$server-&gt;setClassMap('com.bravo.model.User', 'Brava_Model_User');

			echo($server-&gt;handle());
		}

	}

?&gt;
</pre>
<p>Tip 5 Bootstrap<br />
最主要的是初始化name space和数据库连接</p>
<pre class="brush: php; title: ; notranslate">
	protected function _initAutoload(){
		$autoloader = new Zend_Application_Module_Autoloader(array(
            'namespace' =&gt; 'Bravo',
            'basePath'  =&gt; dirname(__FILE__),
        ));
        return $autoloader;
	}

	protected function _initExtraConfig(){
		$resource = $this-&gt;getPluginResource('db');
		$db = $resource-&gt;getDbAdapter();
		Zend_Registry::set('db',$db);

		Zend_Registry::set('configSection',APPLICATION_ENV);

	}
</pre>
<p>Tip 6 Value Object的传输<br />
最让我头疼的。我现在的做法是，不使用ZF的Model, 直接用DbAdapter.<br />
所以，我在Model里定义的其实是VO.</p>
<p>定义一个Base:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

	class Bravo_Model_Base{

		public function setData($place){

			foreach($this as $key=&gt;$value){
				if( array_key_exists($key, $place)){
					$this-&gt;$key = $place[$key];
				}
			}
		}

	}

?&gt;
</pre>
<p>那么， User的Model就是：</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
	class Bravo_Model_User extends Bravo_Model_Base{
		public $_explicitType = 'com.bravo.model.User';

		public $id;
		public $email;
		public $nickname;
		public $passwd;
		public $avatar;

	}
?&gt;
</pre>
<p>在从数据库中取得数据后：</p>
<pre class="brush: php; title: ; notranslate">
		public function getPlace($i){
			$db = Zend_Registry::get('db');

			$select = $db-&gt;select();

			$select-&gt;from('place')
			-&gt;where('place.id='. $i);

			$p = $db-&gt;fetchRow($select);

			$pvo = new Bravo_Model_Place();
                        //就可以这样了
			$pvo-&gt;setData($p);
			return $pvo;
		}
</pre>
<p>下一篇我们说客户端-应该是很简单了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/430/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>“先进的互联互通技术”&#8211;使用ice联通php和java [part 1 server]</title>
		<link>http://blog.ityao.com/archives/426</link>
		<comments>http://blog.ityao.com/archives/426#comments</comments>
		<pubDate>Fri, 25 Sep 2009 03:34:10 +0000</pubDate>
		<dc:creator>零蛋</dc:creator>
				<category><![CDATA[JAVA EE]]></category>
		<category><![CDATA[Php]]></category>
		<category><![CDATA[web服务器]]></category>
		<category><![CDATA[五四陈科学院]]></category>

		<guid isPermaLink="false">http://blog.ityao.com/?p=426</guid>
		<description><![CDATA[PHP没有中间件，导致了对很多麻烦。比如，对数据库的操作必须要链接数据库，然后做SQL操作。WEB程序直接操作数据库的方法，这样会带来很多人为因素的事故隐患，以及管理上的麻烦，尤其是对大型的网站应用来说。规范的模式应该是，WEB程序传递参数到一个服务程序上，由该服务程序进行判断并最终操作数据库或者其它数据文件，这样做到了明确权限控制，和业务类型集中管理。去年伴随着ICE的推出，PHP终于有了可以使用的中间件。在PHP的发展史上，应该是一个里程碑。 ICE入门 ICE（Internet Communications Engine 网络通讯引擎），是由Corba原核心成员开发的一个开源中间件，据称其各种性能完全优于Corba。除此之外，我们第一次见到了直接支持PHP的中间件。 ICE的安装，去http://www.zeroc.com/download.html 下载一个Ice针对PHP的安装包，按照说明安装上。 ICE的使用：使用Slice（ICE的一种简单语法脚本），编写一个xx.ice文件。可以使用slice2cpp或slice2java等生成一个cpp或java的ICE框架程序，然后在这个框架程序中进行代码编写。ICE在PHP的应用继承了PHP的一贯传统——简单，只需要在php.ini中加载该xx.ice，在PHP中就可以使用了。 ICE在PHP应用中的缺点，无法使用PHP编写Server端，其实这也是PHP的一个缺陷——没有完善的多进程和多线程管理机制。因此，Server端可以采用ICE所支持的其它语言进行编写，比如JAVA/C++/VB/PYTHON等。 开始传说中的“互联互通” 本例以 Ice 3.2.1为例 下载的位置和参考的文档都在下面 http://www.zeroc.com/download_3_2_1.html http://www.zeroc.com/doc/Ice-3.2.1/manual/Slice.5.10.html#50592 ICE其实是一个网络框架，入门说明中说了，PHP不能用来做服务端，在这里我们使用java来做服务端，用php来连java，达到传说中的“互联互通”。 我们的服务端用Linux，客户端也用Linux（纯废话）。JAVA环境的搭建不在表述了。 在下载可以看出来，服务器支持yum或者是rpm是多么幸福的一件事情，或者搞一份tar.gz的包下来configure make make install，大概也就是这样。好了这样子就表示安装结束了。。。 安装之后的Ice相关路径: slice2cpp,slice2java在/usr/bin/下 Ice.jar 存储于 /usr/share/java/下 相关的Ice的库存储于/usr/lib下. 第1步，建立服务器端的demo.ice的文件（注意代码里的半全角，如果是全角自行转成半角）： module Demo{ interface test{ string   execute(string mth,string cmd); }; }; 第2步，执行: slice2java demo.ice 生成一堆文件。。。 第3步，动手干活 上一步执行完会在当前目录产生一个Demo目录,目录下自动生成: -rw-r&#8211;r&#8211;  1 root root 2316  4月 15 17:01 _testDelD.java [...]]]></description>
			<content:encoded><![CDATA[<p>PHP没有中间件，导致了对很多麻烦。比如，对数据库的操作必须要链接数据库，然后做SQL操作。WEB程序直接操作数据库的方法，这样会带来很多人为因素的事故隐患，以及管理上的麻烦，尤其是对大型的网站应用来说。规范的模式应该是，WEB程序传递参数到一个服务程序上，由该服务程序进行判断并最终操作数据库或者其它数据文件，这样做到了明确权限控制，和业务类型集中管理。去年伴随着ICE的推出，<a href="http://www.54chen.com/611-%e5%8e%9f%e5%88%9bdiscuz-bbs%e7%bc%93%e5%ad%98%e6%95%b4%e4%bd%93%e6%96%b9%e6%a1%88/">PHP</a>终于有了可以使用的中间件。在PHP的发展史上，应该是一个里程碑。</p>
<p><span id="more-426"></span></p>
<p><strong>ICE入门</strong></p>
<p>ICE（Internet Communications Engine 网络通讯引擎），是由Corba原核心成员开发的一个开源中间件，据称其各种性能完全优于Corba。除此之外，我们第一次见到了直接支持PHP的中间件。</p>
<p>ICE的安装，去http://www.zeroc.com/download.html 下载一个Ice针对PHP的安装包，按照说明安装上。</p>
<p>ICE的使用：使用Slice（ICE的一种简单语法脚本），编写一个xx.ice文件。可以使用slice2cpp或slice2java等生成一个cpp或java的ICE框架程序，然后在这个框架程序中进行代码编写。ICE在PHP的应用继承了PHP的一贯传统——简单，只需要在php.ini中加载该xx.ice，在PHP中就可以使用了。</p>
<blockquote><p>ICE在PHP应用中的缺点，无法使用PHP编写Server端，其实这也是PHP的一个缺陷——没有完善的多进程和多线程管理机制。因此，Server端可以采用ICE所支持的其它语言进行编写，比如JAVA/C++/VB/PYTHON等。</p></blockquote>
<p><strong>开始传说中的“互联互通”</strong></p>
<blockquote><p><strong><span style="color: #ff0000">本例以 Ice 3.2.1为例 下载的位置和参考的文档都在下面</span></strong></p>
<p><a href="http://www.zeroc.com/download_3_2_1.html">http://www.zeroc.com/download_3_2_1.html</a></p>
<p><a href="http://www.zeroc.com/doc/Ice-3.2.1/manual/Slice.5.10.html#50592">http://www.zeroc.com/doc/Ice-3.2.1/manual/Slice.5.10.html#50592</a></p></blockquote>
<p>ICE其实是一个网络框架，入门说明中说了，PHP不能用来做服务端，在这里我们使用java来做服务端，用php来连java，达到传说中的“互联互通”。</p>
<p>我们的服务端用Linux，客户端也用Linux（纯废话）。JAVA环境的搭建不在表述了。</p>
<p>在下载可以看出来，服务器支持yum或者是rpm是多么幸福的一件事情，或者搞一份tar.gz的包下来configure make make install，大概也就是这样。好了这样子就表示安装结束了。。。</p>
<blockquote><p>安装之后的Ice相关路径:</p>
<p>slice2cpp,slice2java在/usr/bin/下</p>
<p>Ice.jar 存储于 /usr/share/java/下</p>
<p>相关的Ice的库存储于/usr/lib下.</p></blockquote>
<p>第1步，建立<a href="http://www.54chen.com/736-dynamo-based-systems-designed-linkin-voldemort-voldemort-design-chinese-documents-i-am-a-chan-academy-of-sciences-translation-finalized/">服务器</a>端的demo.<span>ice</span>的文件（注意代码里的半全角，如果是全角自行转成半角）：</p>
<blockquote><p>module Demo{</p>
<p>interface test{</p>
<p>string   execute(string mth,string cmd);</p>
<p>};</p>
<p>};</p></blockquote>
<p>第2步，执行: <span>slice2java</span> demo.<span>ice</span> 生成一堆文件。。。</p>
<p>第3步，动手干活</p>
<p>上一步执行完会在当前目录产生一个Demo目录,目录下自动生成:<br />
-rw-r&#8211;r&#8211;  1 root root 2316  4月 15 17:01 _testDelD.java<br />
-rw-r&#8211;r&#8211;  1 root root  560  4月 15 17:01 _testDel.java<br />
-rw-r&#8211;r&#8211;  1 root root 1929  4月 15 17:01 _testDelM.java<br />
-rw-r&#8211;r&#8211;  1 root root 4177  4月 15 17:01 _testDisp.java<br />
-rw-r&#8211;r&#8211;  1 root root 1070  4月 15 17:01 testHolder.java<br />
-rw-r&#8211;r&#8211;  1 root root  488  4月 15 17:01 test.java<br />
-rw-r&#8211;r&#8211;  1 root root  481  4月 15 17:01 _testOperations.java<br />
-rw-r&#8211;r&#8211;  1 root root  460  4月 15 17:01 _testOperationsNC.java<br />
-rw-r&#8211;r&#8211;  1 root root 5418  4月 15 17:01 testPrxHelper.java<br />
-rw-r&#8211;r&#8211;  1 root root  569  4月 15 17:01 testPrxHolder.java<br />
-rw-r&#8211;r&#8211;  1 root root  567  4月 15 17:01 testPrx.java<br />
到目前为止,demo.<span>ice</span>所以<span>Ice</span>接口部分的定义以及相关依赖都已经自动生成.</p>
<p>我们要实现自己的execute方法,覆盖testPrx.java的同名<a href="http://www.54chen.com/272-%e5%a6%82%e4%bd%95%e5%af%b9%e4%bb%98%e6%97%a0%e8%89%af%e6%87%92%e6%83%b0ops%e7%9a%84%e5%8f%af%e8%80%bb%e7%9a%84%e9%99%90%e6%b5%81%e6%8e%aa%e6%96%bd/">方法</a>:</p>
<blockquote><p>//TestImp.java</p>
<p>package Demo;</p>
<p>import Ice.Current;</p>
<p>public class TestImp extends _testDisp{</p>
<p>public String execute(String mth, String cmd, Current __current) {</p>
<p>// TODO Auto-generated method stub</p>
<p>return mth+cmd;</p>
<p>}</p>
<p>}</p></blockquote>
<p>第4步，建立一个Server服务在10000<a href="http://www.54chen.com/264-%e7%94%a8iptables%e5%81%9a%e4%b8%a4%e6%9c%ba%e4%b9%8b%e9%97%b4%e7%9a%84%e7%ab%af%e5%8f%a3%e8%bd%ac%e5%8f%91/">端口</a>进行侦听</p>
<blockquote><p>//Server.java</p>
<p>package Demo;</p>
<p>public class Server {</p>
<p>public static void main(String[] args) {</p>
<p>int status = 0;</p>
<p>Ice.Communicator ic = null;</p>
<p>try {</p>
<p>ic = Ice.Util.initialize(args);</p>
<p>Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints(</p>
<p>&#8220;TestAdapter&#8221;, &#8220;default -p 10000&#8243;);</p>
<p>Ice.Object object = new TestImp();</p>
<p>adapter.add(object, ic.stringToIdentity(&#8220;TestAdapter&#8221;));</p>
<p>adapter.activate();</p>
<p>ic.waitForShutdown();</p>
<p>} catch (Ice.LocalException e) {</p>
<p>e.printStackTrace();</p>
<p>status = 1;</p>
<p>} catch (Exception e) {</p>
<p>System.err.println(e.getMessage());</p>
<p>status = 1;</p>
<p>}</p>
<p>if (ic != null) {</p>
<p>// Clean up</p>
<p>//</p>
<p>try {</p>
<p>ic.destroy();</p>
<p>} catch (Exception e) {</p>
<p>System.err.println(e.getMessage());</p>
<p>status = 1;</p>
<p>}</p>
<p>}</p>
<p>System.exit(status);</p>
<p>}</p>
<p>}</p></blockquote>
<p>以上大部分代码都是框架生成，你只需要在里面填写TODO。把这个代码拖回来用eclipse打成jar包，注意，需要依赖ice.jar这个包，这个包可以在<a href="http://www.54chen.com">官方</a>网站下载到。<a href="http://www.zeroc.com/download_3_2_1.html">http://www.zeroc.com/download_3_2_1.html</a></p>
<p>生成DemoServer.ajr后传到服务器，运行java -cp ./:Ice.jar:DemoServer.jar Demo.Server</p>
<p>运行成功的条件是Ice.jar和DemoServer.jar都在一个目录里。（Ice.jar从下载地址下载）</p>
<p>Server运行之后监听于10000端口，需要修改iptables，允许其他机器可以连接。<br />
编辑 iptables<br />
vi /etc/sysconfig/iptables</p>
<blockquote><p><span>-A RH-Firewall-</span><span>1</span><span>-INPUT -m state &#8211;state NEW -m tcp -p tcp &#8211;dport </span><span>10000</span><span> -j ACCEPT</span></p></blockquote>
<p><strong>继续深入互联互通</strong></p>
<p>这一节完成了Server，一个10000端口的Server在等待着我们用PHP来联通中。下一节，我们将讲述：IcePHP环境的搭建，PHP调用Ice如何与JAVA互联互通，以及一个完整的Demo，保存好本节的代码，后面还有用处。[未完待续]</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/426/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[五四陈]java项目管理神兵利器maven和nexus使用手记</title>
		<link>http://blog.ityao.com/archives/314</link>
		<comments>http://blog.ityao.com/archives/314#comments</comments>
		<pubDate>Tue, 15 Sep 2009 04:42:39 +0000</pubDate>
		<dc:creator>零蛋</dc:creator>
				<category><![CDATA[JAVA EE]]></category>
		<category><![CDATA[服务端技术]]></category>

		<guid isPermaLink="false">http://blog.ityao.com/?p=314</guid>
		<description><![CDATA["尽管 Ant 对于构建 Java 程序而言是事实上的标准工具，但这个工具在许多方面都不胜任项目管理任务。相反，Ant 提供的东西，Maven（出自 Apache Jakarta 项目的高级项目管理工具）都能提供，而且更多。" --转自IBM开发者网络

适用场景

如果你的项目互相有jar包的依赖，WEB-INF/lib下有大量杂乱的jar包，svn里lib目录下时常要更新东西，并且你为此伤透了脑筋，团队战斗力无法提升，那么，你就需要这两样利器了。]]></description>
			<content:encoded><![CDATA[<p>&#8220;尽管 Ant 对于构建 Java 程序而言是事实上的标准工具，但这个工具在许多方面都不胜任项目管理任务。相反，Ant 提供的东西，Maven（出自 Apache Jakarta 项目的高级项目管理工具）都能提供，而且更多。&#8221; &#8211;转自IBM开发者网络<br />
<span id="more-314"></span><br />
<strong>适用场景</strong></p>
<p>如果你的项目互相有jar包的依赖，WEB-INF/lib下有大量杂乱的jar包，svn里lib目录下时常要更新东西，并且你为此伤透了脑筋，团队战斗力无法提升，那么，你就需要这两样利器了。</p>
<p><strong>主角出场 windows环境居多</strong></p>
<p><a href="http://maven.apache.org/">http://maven.apache.org/</a> 项目的主页，有洋文</p>
<p><a href="http://maven.apache.org/download.html">http://maven.apache.org/download.html</a> 下载的地方</p>
<p>安装的说明-好yy的居然有中文！</p>
<p><a href="http://www.sonatype.com/books/maven-book/reference_zh/installation.html">http://www.sonatype.com/books/maven-book/reference_zh/installation.html</a></p>
<p>大概意思就是下一个包然后设置环境变量。主要目的就是让你的本地环境能够执行mvn。</p>
<p><strong>跑龙套的出场 linux环境犹佳</strong></p>
<p><a href="http://nexus.sonatype.org/">http://nexus.sonatype.org/</a> 项目的主页，有洋文</p>
<p><a href="http://nexus.sonatype.org/downloads/">http://nexus.sonatype.org/downloads/</a> 下载的地方</p>
<p>安装的说明</p>
<p><a href="http://www.sonatype.com/books/nexus-book/reference/install.html">http://www.sonatype.com/books/nexus-book/reference/install.html</a></p>
<p>就是下一个包然后以webserver方式运行下。主要目录是让你的jar包能有个放处。</p>
<p>类似 ./bin/jsw/macosx-universal-32/nexus start</p>
<p>安装的视频</p>
<p>全屏才能看清楚.</p>
<p>跑龙套的近照 默认密码是 admin/admin123</p>
<p><a href="http://www.sonatype.com/books/nexus-book/reference/figs/web/repository-manager_nexus-login.png"><img class="alignnone" src="http://www.sonatype.com/books/nexus-book/reference/figs/web/repository-manager_nexus-login.png" alt="" width="803" height="457" /></a></p>
<p><strong>剧本</strong></p>
<p>主角其实是个客户端工具，所有的功能都集中于一个命令：mvn</p>
<p>例如：运行cmd 进入项目文件夹 mvn package 将项目打包  mvn install 将项目包安装到本地仓库 mvn deploy 向包布到跑龙套那个东东上面。</p>
<p>mvn命令还有很多强大的功能，具体见 <a href="http://www.sonatype.com/books/maven-book/reference_zh/public-book.html">http://www.sonatype.com/books/maven-book/reference_zh/public-book.html</a></p>
<p>跑龙套那个其实才算得上第二主角，它是一个强大的服务器端，它管理着你所有原来在svn里的lib下的所有jar包。并且很重要的一点，它能通过web界面搜索。</p>
<p>这样，只要大家都使用和发布snapshot版本的jar包，不需要再另行通知更新jar包，开发的人搞好直接mvn deploy，使用的人在mvn -U clean package 自然就拖下最新的包，默契不在话下。</p>
<p>这一切，都来源于pom组织的强大定义。【全剧终】</p>
<p><strong>鸣谢</strong></p>
<p>党和人民</p>
<p>老毛子精细的技术活</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/314/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>[五四陈小技巧]全站换域名时利用nginx和javascript做简单友好的换域名跳转通知</title>
		<link>http://blog.ityao.com/archives/114</link>
		<comments>http://blog.ityao.com/archives/114#comments</comments>
		<pubDate>Wed, 09 Sep 2009 08:41:14 +0000</pubDate>
		<dc:creator>零蛋</dc:creator>
				<category><![CDATA[web服务器]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[域名]]></category>

		<guid isPermaLink="false">http://blog.cnflex.org/?p=114</guid>
		<description><![CDATA[在经过上一波的xiaonei.com转renren.com后，昨夜再次迎来新一波的kaixin-&#62;renren code的过程，期间有域名要求用新的域名，并且要老域名有跳转有提示，于是采用了下面的办法。 老域名是 old.com 新域名是 new.com 迁移挂维护的过程就略过了，直接说重点， 第一步，修改nginx.conf，删除原来old.com的定义，增加： server { listen 80; server_name old.com; location / { root   /old; if (!-e $request_filename){ rewrite ^/(.*)?$ /index.html?t=$1 last; } } } 第二步，在/old下放进一个index.html，代码如下： &#60;div&#62; &#60;h1&#62;&#60;span&#62;old换名啦！&#60;/span&#62; &#60;br&#62; 原来old更名为new，请放心不会影响您的使用，新的地址为&#60;a href=&#8221;http://new.com&#8221; id=&#8221;link&#8221;&#62;new.c om&#60;/a&#62;谢谢您的支持！ &#60;/h1&#62; &#60;p&#62; 2秒之后自动跳转到新的地址&#8230; &#60;/p&#62; &#60;/div&#62; &#60;script type=&#8221;text/javascript&#8221;&#62; document.getElementById(&#8220;link&#8221;).href = location.href.replace(&#8220;old.com&#8221;,&#8221;new.com&#8221;); setTimeout(function(){ location.href =  location.href.replace(&#8220;old.com&#8221;,&#8221;new.com&#8221;); }, 2000) &#60;/script&#62; 第三步，关机，回家睡觉]]></description>
			<content:encoded><![CDATA[<p>在经过上一波的xiaonei.com转renren.com后，昨夜再次迎来新一波的kaixin-&gt;renren code的过程，期间有域名要求用新的域名，并且要老域名有跳转有提示，于是采用了下面的办法。<br />
<span id="more-114"></span><br />
老域名是 old.com</p>
<p>新域名是 new.com</p>
<p>迁移挂维护的过程就略过了，直接说重点，</p>
<p>第一步，修改nginx.conf，删除原来old.com的定义，增加：</p>
<blockquote><p>server {<br />
listen 80;<br />
server_name old.com;</p>
<p>location / {<br />
root   /old;<br />
if (!-e $request_filename){<br />
rewrite ^/(.*)?$ /index.html?t=$1 last;<br />
}<br />
}<br />
}</p></blockquote>
<p>第二步，在/old下放进一个index.html，<a href="http://www.54chen.com/576-54%e9%99%88%e7%a7%91%e5%ad%a6%e9%99%a28021x%e6%ba%90%e4%bb%a3%e7%a0%81%e4%b8%8b%e8%bd%bd/">代码</a>如下：</p>
<blockquote><p>&lt;div&gt;</p>
<p>&lt;h1&gt;&lt;span&gt;old换名啦！&lt;/span&gt;<br />
&lt;br&gt;<br />
原来old更名为new，请放心不会影响您的使用，新的地址为&lt;a href=&#8221;http://new.com&#8221; id=&#8221;link&#8221;&gt;new.c<br />
om&lt;/a&gt;谢谢您的支持！<br />
&lt;/h1&gt;<br />
&lt;p&gt;<br />
2秒之后自动跳转到新的地址&#8230;<br />
&lt;/p&gt;<br />
&lt;/div&gt;</p>
<p>&lt;script type=&#8221;text/javascript&#8221;&gt;<br />
document.getElementById(&#8220;link&#8221;).href = location.href.replace(&#8220;old.com&#8221;,&#8221;new.com&#8221;);<br />
setTimeout(function(){<br />
location.href =  location.href.replace(&#8220;old.com&#8221;,&#8221;new.com&#8221;);<br />
}, 2000)<br />
&lt;/script&gt;</p></blockquote>
<p>第三步，关机，回家睡觉</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/114/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Twisted下的Flash文件上传</title>
		<link>http://blog.ityao.com/archives/59</link>
		<comments>http://blog.ityao.com/archives/59#comments</comments>
		<pubDate>Tue, 08 Sep 2009 14:22:49 +0000</pubDate>
		<dc:creator>Daniel Yang</dc:creator>
				<category><![CDATA[Adobe Flex]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[twisted.web2]]></category>
		<category><![CDATA[文件上传]]></category>

		<guid isPermaLink="false">http://blog.cnflex.org/?p=59</guid>
		<description><![CDATA[Flash Player的文件上传很是让人憋火。除了PHP，CF，Asp.net和它配合良好--不会有差错。
Python下就没有那么方便了。
我曾经在web.py下，试了几天，后来没法子用Django才搞定的。
总是有莫名其妙的问题。]]></description>
			<content:encoded><![CDATA[<p>Flash Player的文件上传很是让人憋火。除了PHP，CF，Asp.net和它配合良好&#8211;不会有差错。<br />
Python下就没有那么方便了。<br />
我曾经在web.py下，试了几天，后来没法子用Django才搞定的。<br />
总是有莫名其妙的问题。<br />
<span id="more-59"></span><br />
我在Twisted的邮件列表里发了一通：</p>
<p>I&#8217;ve been trying to upload files to twisted.web2 backend(FileSaver) with Adobe Flex and I am always getting IOError.<br />
(code see below)<br />
After some sniffing work, I found the error messages returned by twisted.web2:</p>
<p>Unexpected data on same line as boundary: &#8216;&#8211;&#8217;</p>
<p>I believe this flex app works with php backend. So this might be with twisted.web2 or flash player&#8217;s malformed post data.</p>
<p>It seems the twisted error comes from fileupload.py:<br />
(I added 2 prints)</p>
<pre class="brush: plain; title: ; notranslate">
    def _readBoundaryLine(self):
        print &quot;_readBoundaryLine&quot;
        line = self.stream.readline(size=1024)
        if isinstance(line, defer.Deferred):
            line = defer.waitForDeferred(line)
            yield line
            line = line.getResult()
        print line
        if line == &quot;--\r\n&quot;:
            # THE END!
            yield False
            return
        elif line != &quot;\r\n&quot;:
            raise MimeFormatError(&quot;Unexpected data on same line as boundary: %r&quot; % (line,))
        yield True
        return
    _readBoundaryLine = defer.deferredGenerator(_readBoundaryLine)
</pre>
<p>with html uploading form, it outputs:</p>
<p>2009-08-20 23:06:08+0800 [-] _readBoundaryLine<br />
2009-08-20 23:06:08+0800 [-] &#8211;<br />
2009-08-20 23:06:08+0800 [-]<br />
2009-08-20 23:06:08+0800 [-] <POST /upload (1, 1)> &#8212;&#8212;&#8211;<br />
2009-08-20 23:06:08+0800 [-] FileUpload</p>
<p>but with flex uploading:</p>
<p>2009-08-20 23:06:27+0800 [-] _readBoundaryLine<br />
2009-08-20 23:06:27+0800 [-]<br />
2009-08-20 23:06:27+0800 [-]<br />
2009-08-20 23:06:27+0800 [-] _readBoundaryLine<br />
2009-08-20 23:06:27+0800 [-]<br />
2009-08-20 23:06:27+0800 [-]<br />
2009-08-20 23:06:27+0800 [-] _readBoundaryLine<br />
2009-08-20 23:06:27+0800 [-] &#8211;</p>
<p>Same file, different posted data.</p>
<p>Any ideas?</p>
<p>Does this happen to be a bug, or is there any way to walk around this?</p>
<p>My testing code:</p>
<p>python code:</p>
<pre class="brush: plain; title: ; notranslate">
from twisted.web2 import http_headers, resource, \
	static, server, channel, http, responsecode
from twisted.python import util

FORMHTML = &quot;&quot;&quot;
&lt;html&gt;
&lt;p&gt;for test&lt;/p&gt;
&lt;form action=&quot;/upload&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
	&lt;input type=&quot;file&quot; name=&quot;FileUpload&quot; /&gt;
	&lt;input type=&quot;submit&quot; value=&quot;Upload&quot;/&gt;
&lt;/form&gt;
&lt;/html&gt;
&quot;&quot;&quot;

class MyFileSaver(static.FileSaver):
	&quot;&quot;&quot;for test only&quot;&quot;&quot;
	def render(self, req):
		print req, '--------'
		if req.files:
			for fieldName in req.files:
				print fieldName

		return http.Response(responsecode.OK, {}, stream='ok')

class Toplevel(resource.Resource):
  addSlash = True
  def render(self, ctx):
	return http.Response(stream=FORMHTML)

  child_upload = MyFileSaver(util.sibpath(__file__, ''),
  	expectedFields=['FileUpload'],
  		allowedTypes=(
  			http_headers.MimeType('image', 'jpeg'),
  			http_headers.MimeType('image', 'png'),
  			http_headers.MimeType('image', 'gif'),
  		)
  	)
  child_swf = static.File(util.sibpath(__file__, 'FileUpload.swf'))
site = server.Site(Toplevel())

# Standard twisted application Boilerplate
from twisted.application import service, strports
application = service.Application(&quot;demoserver&quot;)
s = strports.service('tcp:8080', channel.HTTPFactory(site))
s.setServiceParent(application)
</pre>
<p>My flex code:</p>
<pre class="brush: plain; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!-- http://blog.flexexamples.com/2007/09/21/uploading-files-in-flex-using-the-filereference-class/ --&gt;
&lt;mx:Application xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot;
        layout=&quot;vertical&quot;
        verticalAlign=&quot;middle&quot;
        backgroundColor=&quot;white&quot;
        creationComplete=&quot;init();&quot;&gt;

    &lt;mx:Script&gt;
        &lt;![CDATA[
            private var fileRef:FileReference;

            private const FILE_UPLOAD_URL:String = &quot;http://127.0.0.1:8080/upload&quot;;

            private function init():void {
                fileRef = new FileReference();
                fileRef.addEventListener(Event.SELECT, fileRef_select);
                fileRef.addEventListener(ProgressEvent.PROGRESS, fileRef_progress);
                fileRef.addEventListener(Event.COMPLETE, fileRef_complete);
                fileRef.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);
                fileRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSec);
            }

            private function browseAndUpload():void {
                fileRef.browse();
                message.text = &quot;&quot;;
            }

            private function ioErrorHandler(event:IOErrorEvent):void {
            	trace(event);
            }

            private function onSec(event:SecurityErrorEvent):void{
            	trace(event);
            }

            private function fileRef_select(evt:Event):void {
                try {
                    message.text = &quot;size (bytes): &quot; + numberFormatter.format(fileRef.size);

                    var req:URLRequest = new URLRequest();
                    req.url = FILE_UPLOAD_URL;
                    req.method = URLRequestMethod.POST;

                    fileRef.upload(req, &quot;FileUpload&quot;);
                } catch (err:Error) {
                    message.text = &quot;ERROR: zero-byte file&quot;;
                }
            }

            private function fileRef_progress(evt:ProgressEvent):void {
                progressBar.visible = true;
            }

            private function fileRef_complete(evt:Event):void {
                message.text += &quot; (complete)&quot;;
                progressBar.visible = false;
            }
        ]]&gt;
    &lt;/mx:Script&gt;

    &lt;mx:NumberFormatter id=&quot;numberFormatter&quot; /&gt;

    &lt;mx:Button label=&quot;Upload file&quot;
            click=&quot;browseAndUpload();&quot; /&gt;
    &lt;mx:Label id=&quot;message&quot; /&gt;
    &lt;mx:ProgressBar id=&quot;progressBar&quot;
            indeterminate=&quot;true&quot;
            visible=&quot;false&quot; /&gt;

&lt;/mx:Application&gt;
</pre>
<p>解决方法：<br />
暂时没有，但是有一个patch:</p>
<p>http://twistedmatrix.com/trac/ticket/2113</p>
<p>一起哭吧。。。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ityao.com/archives/59/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

