准备开发一个
Gtalk(Google Talk)机器人 ,现在在做资料收集和前期准备。
目前找到的支持
Jabber/XMPP协议的Python库有:
还没正式开始编写程序,哪个比较好目前还不知道。
大家知道有这里没有列出来的支持Jabber/XMPP协议的Python库,请留言告知。
有这些库有什么经验和看法也请不吝赐教,谢谢。
从高中到大学我都是留着长长的连鬓胡子的,工作以后为了显得自己是正常人,我开始刮胡子。但是今天看了
孟岩的文章我才发现自己越来越笨的主要原因是不留胡子了,灵感都跟着胡子走了。
中国古人更是依赖胡子的,
“吟安一个字,捻断数茎须”充分说明了胡子对诗人的作用。程序员也是一个需要创造力的职业,所以程序员也需要留胡子。火炬注意了,看来你前途有限,就没见你胡子长长过。
Tiny定理
玩微软平台开发的人只有两个下场:
- 被微软弄得没饭吃。
- 去微软混饭吃。
Borland是这个定理的忠实实践者,当然Borland前面还有无数的炮灰。
最近想出本书,颠覆下《人件》 的思想,这本书中我们要提出“不想做牲口的开发人员就不是好开发人员!”的口号。其他先都不管,书名一定要响亮。今天我想了一个下午,想出了一个好名字:
《件人》
客户端到客户端之间的连接
电骡客户端一般是为了下载某个文件才会连接到其他的客户端(也就是源)的。一个文件会被分为很多块。客户端会从多个客户端(源)那里下载同一个文件,从不同的源下载文件的不同部分(
这样不同的部分就可以同时被下载,如果源多,下载的效率就会极高)。
当两个客户端连接后,他们会交换容量信息,然后协商开始下载(或者说是上传,这取决于视角)的时间。每个客户端有一个下载队列,用来保存正在等待下载的客 户端的列表。当电骡客户端的下载对列为空的时候,下载请求会被马上接受(除非这个请求者已经被屏蔽)。如果下载对列不为空,那么新的下载请求就会放在队列 之中。不会努力服务更多的客户端,对每个下载客户端至少保持不少于2.k字节/每秒。一个正在下载的客户端的下载地位可能被一个对列等级(queue ranking)比他高的等待客户端抢占,在下载进程中的前15分钟正在下载的客户端的队列等级会增长用来避免产生颠簸(
这里说的颠簸就是说,一个客户端频繁的从下载地位切换到等待状态,然后再切换回去。这种频繁的切换叫做颠簸,这对资源是种浪费,所以要避免。)。
当正在下载的客户端到达了下载队列的顶部,提供上传的客户端初始化一个连接用于把它需要的文件片断传送给它。一个电骡客户端可能会在多个源客户端的等待队 列中,在每个客户端上注册要求同一个文件片断。当这个等待客户端实际上完成了这个文件片断的下载,他不会通知那些源客户端删除它的请求,而仅仅是在它在那 些源客户端的队列中排到顶端的时候拒绝上传请求而已。
电骡使用一个声望系统来鼓励上传,为了防止假冒,电骡用RSA公钥加密技术来保护声望系统。
客户端连接中会使用很多电驴协议(eDonkey protocol)没有定义的消息,这些消息叫做扩展协议。扩展协议用来实现信用系统,用来进行信息交换(例如,服务器列表的更新和源的更新),通过对文 件块进行压缩提升发送和接收的效率。电骡客户端连接中有限地使用UDP去周期其他客户端的状态。
客户端ID
客户端是一个4字节的标识符,在跟服务器连接握手的时候由服务器提供的。客户端ID仅在客户端服务器TCP连接的生命期内可用,虽然如果客户端是高ID (High ID),它在任何服务器分配的客户端ID都一样,除非IP变化了。客户端ID分为低ID(low ID)和高ID。电骡服务器通常会给不能接受连接的客户端分配低ID。拥有低ID会限制客户端在电骡网络中的使用,甚至会造成服务器拒绝连接。高ID是由 客户端的IP地址为基础算出的。这里从电骡协议的观点来看客户端ID的分配和表示。得到高ID的客户端允许其他的客户端自由地连接他的电骡TCP端口(默 认为4662)。得到高ID的客户端在电骡网络内不受任何限制。当服务器不能打开一个连往客户端的电骡端口的连接时,服务器给客户端一个低ID。这主要是 客户端安装了防火墙组织外来连接造成的。以下情况下,客户端会得到低ID:
- 当客户端通过NAT或者代理服务器上网。
- 当服务器正在忙(造成服务器的连接计数器超时,从而认为客户端无法连接)。
高ID通过下面的方法计算:假设机器IP地址为X.Y.Z.W,客户端ID应该为 X+2
8*Y+2
16*Z+2
24*W(big endian高位在前)。低ID总是小于15777216(0x1000000)我不知道它是怎么计算的(
协议原文如此,看来低ID的算法并不重要,只要满足条件即可。),注意从不同的服务器得到的低ID是不一样的。
低ID的客户端没有公开的IP地址供其他的客户端连接,所以所有的通信必须通过电骡服务器。这会造成服务器的负载提升,所以服务器不愿意接受低ID的客户端。同样,这说明低ID的客户端不能跟其他服务器上面的低ID客户端连接,因为电骡不支持服务器间的桥接。
为了支持低ID客户端电骡协议引入了回调机制。使用这种机制,一个高ID客户段可以要求(通过服务器)低ID客户端连接它来交换文件。
(
现在大部分服务器不会拒绝低ID的客户端连接,因为他们基本上都不帮助客户端传输文件了。由此,低ID的客户端之间也无法传输了。)
用户ID
电骡支持声望系统为了增加用户的文件共享。一个用户上传给其他客户端越多东西,它就得到越多的声望,这样它在他们的等待队列中前进就会越快。用户ID是一 个128位(16字节)GUID,通过连接随机数而产生,第6和第15位不是随机生成的,他们分别是14和111。用户ID仅在客户端和服务器会话中有 效,用户ID是唯一的用来标识客户端。用户ID在声望系统里面起了很大的作用,攻击者冒充其他用户就是为了得到它们声望对应的权利。电骡提供了加密方案用 来用户欺诈。实现方式是用RSA方法来加密方法来加密信息交换。
文件ID
文件ID用于网络中文件的唯一标识,以及文件损坏的检测和修复。注意电骡对文件进行唯一标识和编目不依赖于文件名,文件由其内容哈希计算出来的全局唯一ID来标识。文件ID有两种,一种用来生成唯一标识,一种用于文件损坏的检测和修复。
文件哈希
文件是用一个128位的GUID来标识的,这个GUID是由客户端用文件内容哈希计算出来的。GUID使用MD4算法计算。计算文件ID的时候文件被分成 9.28MB的大小。一个GUID是分别计算每个文件块的哈希,然后把它们合成为一个唯一文件ID。下载客户端完成文件块的下载后,会计算块的哈希和文件 上传端发送来的文件块哈希做比较,如果不同,就说明文件块损坏了,客户端将逐块的覆盖(一次180kb)知道哈希计算表明文件块已经修复为止。
根哈希
根哈希是每个文件块用SHA1算法计算出来的,每个计算单元尺寸为180kb。它提供了更高级别的可靠性和错误恢复。
电骡协议拓展
虽然电骡(eMule)完全兼容电驴(eDonkey),但是它还是实现了一些扩展,用于增强它的功能。扩展关注于客户端和客户端之间的通信,特别是安全领域和UDP工具。
软件和硬件限制
服务器设定包括两种对活跃用户数目的限制,软件的和硬件的。硬件限制大于等于软件限制。当活跃用户数目到达了软件限制,服务器停止接受新的低ID客户端连接,当用户数目达到了硬件限制,服务器不会接受任何连接。
eMule协议简要分析[一]
最近我对P2p方面很有兴趣。实际上P2p并不仅仅能用于盗版的传播,在很多合理合法的需求中,P2p也有很广泛的前景,至少包括了信息的冗余存储,内容分发,突破信息监管等等方面。
Google文件系统(Google File System)文档中 就提到,在Google网络内分发一个新版本的应用程序的时候,有巨大数量的客户端需要连接到服务器去下载新版本,造成了数据传输热点严重影响系统的运 行,他们计划利用P2p类的技术来解决这个问题。一段时间以来,网络游戏客户端升级都在采用或者部分采用P2p方案。这些都是在软件分发领域P2p的应 用。
eMule是我用的最多的P2p应用,所以研究也从eMule开始。
最主要的参考文本是eMule协议1.0版,
原文地址。分析的流程是简要翻译加上我的思考,但我的目标不在于完整的翻译,我的思考和点评会用红色标出。
--------
电骡eMule是基于电驴eDonkey协议的。电骡网络是由数百个电骡服务器和数百万的电骡客户端组成的。客户端必须连接到服务器来获得网络服务,这个连接要一直保持直到客户端关闭。服务器提供集中的索引服务(类同Napster),不同的服务器之间没有通讯。
每个电骡客户端都预先设置好了一个服务器列表和一个本地共享文件列表。客户端通过一个单一的TCP连接到电骡服务器进行网络登陆,得到想要的文件的信息和可用客户端的信息。(
这样造成了电骡和电驴都不能完全去中心化,虽然文件存储在客户端上。) 电骡客户端用几百个TCP连接与其他的客户端连接进行文件的上传和下载。每个电骡客户端为它的共享文件维护一个上传队列。正在下载的客户端加入这个队列的 底部,然后逐渐的前进,直到他们达到队列的顶端开始下载文件。一个客户端可能从多个其他的电骡客户端下载同一个文件,从不同的客户端取得不同的部分。客户 端也可以上传一个没有完全下载的文件的部分数据。(
文件可以分块传输大大提高了效率,但是也造成了一些问题,比如源提前退出以后,所有的客户端都是不完全数据的情况。)最终,电骡扩展了电驴的能力允许客户端交换关于服务器、其他客户端和文件的信息。(
这个能力又开始把中心的意义淡化。)注意,客户端和服务器的通信都是基于TCP的。
服务器使用一个内部数据库来保存客户端和文件的信息。电骡服务器不保存任何文件,它是文件位置信息的中心索引。服务器的另一个功能,正在受到质疑,他将作为通过防火墙连接的客户端之间的桥梁,这样的客户端不能接受引入的连接。桥接功能大大的增加了服务器的负载。(
这个功能让服务器承担了过分的负担,大大降低了服务器的能力,在设计中应该摒弃,目前应用中大部分的服务器已经关闭了这个功能,也就是说两个Low id的客户端是不能传输数据的。)电骡使用UDP增强客户端跟服务器和其他客户端的通信能力。但是客户端收发UDP信息的能力不是客户端日常操作强制要求的,即使防火墙阻止客户端收发UDP信息,客户端仍能完美的工作。
客户端到服务器的连接

图一 电骡网络图
客户端一启动就会用TCP连接到一个电骡服务器。服务器给客户端提供一个客户端ID,这个ID仅在客户端服务器连接的生命周期内有效(注意如果客户端是高 ID,那么他在所有的服务器得到的ID都是一样的,直到他的IP地址变化为止)。连接建立后,客户端把它共享的文件列表发送给服务器。服务器把这个列表保 存在它的内部数据库内,这个数据库通常包括了数十万可用文件和活动客户端。电骡客户端也会发送它的下载列表,包含了他想要下载的文件。后面将给出电骡客户 端和服务器间的TCP信息交换格式细节。
连接建立以后,电骡服务器给客户端发送一个列表,这个列表包括了那些有客户端需要的文件的客户端(这些客户端叫做源)。然后,客户端就去跟那些有所需文件的客户端建立连接。
注意客户端服务器的TCP连接在整个客户端会话过程中都会保持。初始化握手之后,事务主要是由用户活动触发的:有时客户端发送一个文件查找请求给服务器, 服务器会返回一个查找结果,一个查找事务之后通常是一个对指定文件的源查询,这个查询的结果是一个可以提供该文件下载的源的列表。
电骡客户端用UDP来跟登录服务器以外的服务器进行通信。UDP信息的用途是增加文件搜索能力,源搜索能力,保持连接。
- 重构是一种代码优化技术,这里说的优化不是执行效率的优化,而是软件工程层面的优化,更确切的说是可维护性,可扩展性层面的优化。
- 单元测试是保证重构每个步骤正确性的手段。
- 设计模式是代码重构的目标。
二、熟悉脚本编程的模型
用脚本编写的插件是架构在plug-in helper框架之上的。用JavaScript我们可以修改插件的属性和显示的内容,还可以修改插件菜单,实现设定对话框等等。我们还可以使用标准的JavaScript特性、函数和数据类型。但是对目前的发行版,脚本不能在桌面边框的界面中使用本地的用户界面元素。
脚本插件接口了下面的全局变量供开发者使用:
- pluginHelper
用来修改插件的配置信息。
- 属性
- content_items
- content_item对象的数组,可读写
- 保存显示内容条目的数组
- max_content_items
- 整数,可读写
- 可以显示的最大内容条目数。默认值为25,但是插件可以修改。
- window_width
- window_height
- pin_images
- image数组,可读写
- Array of images to use for the 'pin' icon, which when clicked pins the clicked item at the top of the list.
- 方法
- SetFlags(plugin_flags, content_flags)
- 没有返回值
- 设定插件和内容的标志,从而影响插件的行为。
- SetIcons(small_icon, large_icon)
- AddContentItem(content_item, display_options)
- RemoveContentItem(content_item)
- RemoveAllContentItems()
- 事件句柄
- onShowOptionsDlg
- 在显示设定对话框前对其进行初始化。原型:InitDialog(window)
- 返回false取消对话框,true或者不返回任何东西的情况下显示对话框
- onAddCustomMenuItems
- 在显示菜单前对其进行初始化。原型:AddCustomMenuItems(menu)
- 不需返回
- onCommand
- 执行GD API定义的命令(命令形式为GDD_CMD_xxxx)。原型:OnCommand(command)
- 不需返回
- onDisplayStateChange
- 显示状态变化时调用。原型:OnDisplayStateChange(new_display_state)
- 不需返回
- ContentItem
- 属性
- 方法
- SetRect(x, y, width, height)
- 不返回任何东西
- 设定条目的显示位置。在设定条目的位置前,需要打开ANUAL_LAYOUT标志。否则,条目将会在缺省的位置 出现。
- 事件句柄
- onDrawItem
- 描绘条目的时候调用.
- 原型:DrawItem(item, display_target, graphics, x, y, width, height)
- 不需返回
- onGetHeight
- 取得给定宽度的条目的高度
- 原型:GetHeight(item, display_target, graphics, width)
- 返回给定宽度的条目的高度
- onOpenItem
- 用户打开或双击条目的时候调用
- 原型:OpenItem(item)
- 不需返回
- onToggleItemPinnedState
- 用户点击pin按钮的时候调用
- 原型:ToggleItemPinnedState(item)
- 不需返回
- onGetIsTooltipRequired
- 原型:GetIsTooltipRequired(item, display_target, graphics, x, y, width, height)
- onDetaisView
- 显示指定条目的时候显示。
- 原型:OnDetailsView(item)
- 不返回会取消细节视图,或者返回有以下属性的对象
- obj.title 细节视图里面显示的标题
- obj.details_control 细节视图里面显示的activeX控件
- obj.flags 控制细节视图显示布局和用途的标志
- 以上参数的更多细节请参看文档中IGoogleDesktopDisplayContentItemHandler接口的OnDetailsView事件。
- onProcessDetailsViewFeedback
- 在细节视图中处理用户动作
- 原型:ProcessDetailsViewFeedback(item, details_view_flags)
- 不需返回
- onRemoveItem
- 原型:RemoveItem(item)
- 返回true取消删除操作,返回false确认操作,删除指定内容条目。
- options
- 方法
- GetValue(key_text)
- PutValue(key_text, value)
- Clear()
- utils
- 方法
- loadImage(file_path)
- setInterval(handler, elapse_ms)
- 返回新产生的计时器的id
- 设定周期调用handler的时间间隔
- clearInterval(timer_id)
- setTimeout(handler, elapse_ms)
- 返回新的计时器id
- 设定一次性调用handler的计时器的时间间隔。
- clearTimeout(timer_id)
- alert(text)
- confirm(text)
- 显示一个让用户选择确定和取消的对话框
- 用户选择ok返回true,选择cancel返回false
- prompt(label, default_text)
- Graphics
- 方法
- DrawLine(x1, y1, x2, y2, color);
- DrawRect(x, y, width, height, line_color, fill_color)
- DrawImage(x, y, width, height, image, alpha_percent)
- 在指定长方形内显示图片,可以设定透明度alpha_percent,范围0-100
- DrawText(x, y, width, height, text, color, flags, font)
- GetTextWidth(text, flags, font)
- GetTextHeight(text, width, flags, font)
- Menu
- 方法
- AddItem(item_text, style, handler)
- 增加一个菜单,菜单的样式是gddMenuItemFlagXXXX常量的组合。菜单事件处理函数的原型是OnMenuItem(item_text)。
- SetItemStyle(item_text, style)
- AddPopup(popup_text)
- Window
- 方法
- AddControl(ctrl_class, ctrl_type, ctrl_id, text, x, y, width, height)
- 返回新控件的WindowControl对象
- 创建一个给定数据的控件并加入窗体内。ctrl_class应该是gddWndCtrlClassXXX中的一个,ctrl_type应该是gddWndCtrlTypeXXX中的一个。ctrl_id, text, x, y, width和height等参数会直接传给ctrl_class的内,所以他们的值需要满足那些属性的要求。
- GetControl(ctrl_id)
- 事件句柄
- onClose
- 原型:OnClose(button_id),button_id是gddIdXXXX中的一个。
- 返回false保持窗口不关闭,返回true或者不返回怎窗口关闭。
- WindowControl
- 属性
- id
- enabled
- text
- 对于列表控件,是字符串数组。对其他控件是字符串。可读写。
- 用于控件的显示文本。
- value
- 对于列表控件是当前选中的字符串。对于复选框,是布尔变量,表明选择状态。对于其他控件,就是显示的文本。可读写。
- x
- y
- width
- height

Google桌面搜索推出第二个版本的时候,有两个细节很值得留意。
第一是名字里面少了点东西,Google桌面搜索(Google Desktop Search)变成了Google桌面(Google Desktop);第二是功能方面多了点东西,那就是增加了Google桌面边栏 (Google Desktop SiderBar)。
这两个细节有很多人都忽略了,在他们看来,Google桌面仍旧只是一个桌面搜索工具。我要说他们错了,有了桌面边栏以后的Google Desktop更像一个个人信息平台,一个良好的桌面搜索是构建个人信息平台的基础,但绝对不是全部。可以参照的是,今年7月,Yahoo收购了Konfabulator。这样,在桌面信息中心的争夺战中,Google和Yahoo一人往前线走了一步。
如果有人问我什么是WebOs,我会说这就是WebOs的雏形。桌面边栏是一个客户端程序,但是里面显示的内容都来自网络,实时适时更新。桌面边栏里面的大部分功能都可以在浏览器里面实现,也就是说,你可以把它理解为一个看起来稍微胖了一点的Web客户端。或者说,按照流行的话说,他是一个Rich的,一个丰富的客户端。
现在每天我的桌面边栏都是打开的,我用它来浏览Google News,用它来关注Google、百度和微软的股价,用它来实时跟踪我的Google Adsense广告点击和收益情况,甚至用它的插件gdTunes来控制我的iTunes播放音乐。还有些东西我也想用它来做,唯一的障碍就是没有相应的插件。
但是这个问题也很好解决,因为从一开始推出,Google桌面和桌面边栏就支持非常强大全面的插件接口,你几乎可以用这些接口实现任何你想要的插件。
Google桌面插件接口是基于Com的,这样任何支持Com的语言和开发工具都可以用来开发Google桌面插件。Google方面似乎更推荐大家使用VC7来进行开发,他们提供了一个VC7开发Google桌面插件的向导。
然而,今天本文要介绍的是用JavaScript(实际上也可以用
VBScript)来开发Google桌面插件。因为这更加简单,也更加可靠,因为用JavaScript来开发Google桌面插件可以避开Com的复杂性。当然,用这个方法开发插件也会受到一些表现能力方面的限制,你的插件只能包含标准的Google桌面插件界面元素。
下面我们开始如何开发Google桌面插件(这里说的是显示插件,也就是会显示在桌面边栏上面的插件。):
一、开发环境的建立
首先你先要到Google桌面网站(http://desktop.google.com/)下载最新版的SDK。下载完毕后,解压到任意目录,然后把其中的tools目录加入到Windows环境变量Path之中。
然后,你要到Wix网站(http://sourceforge.net/projects/wix/)去下载Wix工具。下载后,解压到任意目录,这个目录也加入到Windows环境变量Path之中。
今天听说某人的Blog访问量一天有10k-15k,非常诧异。因为也没有发现他的blog有多少人回复的样子,怎么流量会那么大呢?
后来才知道原来在Google中搜索某个搜索量极大的关键字的时候,他的Blog有篇文章会排在前三名。(这个关键字稍微有点不雅观,这里就不提了。)
这让我想起了Google时代精神,来看看吧,最近有没有什么好玩的。
英文的咱们就不关心了,看看
Google九月份的时代精神中国版:
1. 邹和明 (the inventor's name)
2. 大长今 (a popular Korean TV drama)
3. 党性分析材料 (analysis documents on the Party)
4. 超级女声 (a popular TV series, "super girl")
5. 李宇春 (the winner of "super girl")
6. 冒险岛 (adventure island)
7. 迅雷 ("Thunder" software)
8. 驱动之家 (mydrivers.com, download website)
9. 在线翻译 (online translation)
10. 在线漫画 中游动漫 (online cartoon)
11. 魔兽世界 ("world of monsters" video game)
12. 火影忍者 (a popular game)
13. 金山词霸 (word translator)
14. 中国移动 (China mobile)
15. 招商银行 (China merchants bank)
第一名 邹和明很眼生,我甚至没有听说过这人,用Google找了下,也没有找到什么有营养的信息.怀疑是作弊做出来的,但是做这个弊有什么用,目前要打个问号.有人知道为什么么?可以告诉我.
第二名 大长今,不出乎意料,这段时间大长今确实有点红得发紫,9月份我都贡献了不止10次搜索量.
第三名 党性分析材料,也不出乎意料。毕竟现在天天都在讲党员的先进 性教育(噢,sorry,党员的先进性教育,靠,怎么感觉还是不对呢。)。
第四名 超级女声和和第五名李宇春搜索量大也是实至名归,很多人是为了找他们更多的资料而搜索的,很多人是听到人人都在谈论他们才去搜索的。李宇春上了《时代》亚洲封面,肯定也起到了一定的推波助澜作用。
第六名 冒险岛,原本以为是那个古老的单机游戏呢,原来居然是盛大的网游。那么我们要问了,教育类《学雷锋 ONLINE》和《中华英雄谱》呢?怎么还没有出来呢?盛大公司,你们不能光顾着做赚钱的网游啊,我们大家还等着玩《学雷锋 ONLINE》和《中华英雄谱》受教育呢。
第七名 迅雷,没用过,不了解。
第八名 驱动之家,我觉得驱动之家进入榜单的主要原因是,第一名气大,第二域名太长没人记得住,而且很容易打错。就我自己找驱动程序的经历来看,我没有一次把驱动之家的域名输对的时候,每次都是从Google搜索找到的。
第九名 在线翻译,这个没话说,充分说明国人的英语水平还有待提高,包括我在内。
第十名 在线漫画 中游动漫 这么长的关键字居然进榜,出乎意料,不明白。
十一名 魔兽世界,这个进榜很不稀奇,连我这样的,火炬这样的,极少玩游戏的人,都很是玩了一阵子魔兽,可见其魅力之大啊。
十二名 火影忍者,风评据说不错的日本漫画,现在有动画有游戏。今天我的同事还提起过,不过我没看过。
十三名 金山词霸,又一个软件上榜,不过我每次搜索的时候搜的都是“金山词霸共享版”,呵呵,穷人没办法啊。
十四名 中国移动,哈哈,我搜索的时候搜的都是“该死的中国移动”,效果极佳。
十五名 招商银行,招行的网址我每次也是搜索进入的,因为记不住。不过现在工资在建行,我现在每次搜索的都是“建设银行”了。
最早注意到Google File System是在看过
六翼的一篇文章《
Google的启示》,六翼感慨Google可以创新是因为可以抛去经验的束缚来做全新的设计。
之后,在CSDN看到一个广告《Google搜索引擎技术研讨会》,本以为是Google搞的,后来才发现是一个叫做
尚观Linux研究室的组织搞的免费技术交流会。上周六,我参加了这个会,还是比较有意思。
我下载过Google File System的论文,就是一直没时间看,研讨会后仔细看了看,确实很好。
李开复在开复学生论坛说:
Google最厉害的技术是它的storage(file system)。我认为学计算机的学生都应该看看Google File System。
它的search、GMail、video、blog spaces。等等都是用这个技术做的。
当网络服务公司都在比谁能够用最少的代价作出最快、最稳健、最安全的large cluster (超过10万台服务器),这方面的优势是比较可持续的。
当然,它的每一个产品都很优秀:search, GMail, Google Map, Google Earth, Google news, Google image,Google Scholar,Google Print, Google Local, Froogle, Google Answers....虽然它的收入大多数来自于搜索,它的技术早已到了很多领域。
最后,大的公司就会有economy of scale。更好的搜索带来更多的广告,广告的收入又投入更好的搜索。。。再加上成本上的优势(Google File System)。。。
当然,其他的公司也可以做这方面的投入,也可能有一天超过Google。这就是网络和软件业的特殊点:没有永远可以持续的优势。
还有,这些并不代表它就值八百亿美元的市值。股票市场不是理智的。
Google File System那么被人称道的原因就是它是Google集群技术的核心。
Google 2003年关于Google File System的论文
Google 2003年关于Google File System的论文的中文翻译
个人情况
姓名:郝培强
网名:Tinyfool
年龄:26
婚姻状态:未
手机:13520711089
Mail: Tinyfool@Gmail.com
GTalk:Tinyfool
职业:软件工程师
经历:365kit.com 项目客户端和Msn机器人开发者
曾任职于北京金远见电子有限公司,天津津亚电子有限公司
在校期间曾创办学生网站“我心飞扬”(现已关闭),曾经为教育网内最大的免费空间提供站点。
网站
微尘程序员网站
Blog
Tinyfool的开发日记
Tinyfool@Donews Blog(IT评论)
Tinyfool的移动开发阵线
中国播客观察 China Podcast Observer
Tinyfool's diary (英文Blog)
我的照片
文集
今天看到
梦想风暴的文章“
做自己的客户”,有点感受。
从我今年五月份正式开始参加
365kit到现在已经有快半年光景了。到目前为止,开发的速度我还是满意的,然而Bug着实多了些,尤其是我负责的客户端Bug多了些。
我不想去解释自己为什么不能把握好我的Code,但是仅仅从分析的角度去看,我想Bug那么多有几个原因:
1、因为是利用业余时间开发,所以开发进度时紧时松,节奏很不好。
2、对通讯录和Outlook插件开发领域也是初步的进入,经验方面有些欠缺。
3、因为开发人员的数量少,没有专门测试人员,所以测试比较简单片面。
4、该死的Windows的复杂性和COM的复杂性。
跟对这些Bug的原因,解决的办法应该有:
1、尽量管理好时间,稳定开发节奏。
2、多看些资料,多做总结。
3、开始单元测试,发布版本前多做测试。
4、多学习。
然而,那些都是些客观原因。从主观上看,问题又在哪里呢?
我想梦想风暴的文章正好可以回答这个问题,我自己还不是365kit的好用户,我用的还不够多。如果我用的足够多,很多Bug,就应该是我们自己发现的,而不是用户提出来的。
为了测试的方便,我的365kit帐号上基本上都是些测试数据,而不是我的真实联系人。这因为如此,我在测试之余几乎都不会去用365kit,从今天开始,我要把所有的联系人导入进去,另开一个帐号作为测试之用。家里的机器也搭建了各种Win版本和各种Outlook版本的测试平台,我们会把测试变得更加专业,以提高软件的质量和用户感受。