0
周爱民(aimingoo),DelphiBBS(大富翁论坛)资深成员。自1997年以来,历任部门负责人、软件部经理、区域总经理等职,在软件开发、软件工程、团队建设以及部门管理方面经验丰富。
- 1999~2000年为AV95的三个核心开发人员之一,顺利完成了该核心代码层编写。
- 2000~2002年主持并完成极光网络数据仓库中心系统,并被评为河南省高新技术产品二等奖。
- 2002年4月,完成DelphiBBS首届编程竞赛的组织和评测工作。
- 2003年5月,被美国Borland公司授予“Borland Delphi产品专家”称号。同时授予“论坛特别贡献奖”,为惟一同时被授予两个奖项的人员。
- 2003年11月,受邀参加Borland公司成立20周年举办的“Borland首届开发者大会”,发表题为“利用Delphi实现在Microsoft .NET下的开发”的演讲。
- 2004年8月,由电子工业出版社出版软件开发专著《Delphi源码分析》,被业界誉为“Delphi领域精品著作”。
- 2004年10月,在JavaScript实现完整的OOP特性,并进一步完成企业级的RIA框架WEUI。该框架被应用在电信系统的大型业务项目中。
- 2005年3月,完成《大道至简——软件工程实践者的思想》一书的编写,并开始在《程序员》连载。并于2005年11月,发布该书的电子版。
- 1999~2000年为AV95的三个核心开发人员之一,顺利完成了该核心代码层编写。
- 2000~2002年主持并完成极光网络数据仓库中心系统,并被评为河南省高新技术产品二等奖。
- 2002年4月,完成DelphiBBS首届编程竞赛的组织和评测工作。
- 2003年5月,被美国Borland公司授予“Borland Delphi产品专家”称号。同时授予“论坛特别贡献奖”,为惟一同时被授予两个奖项的人员。
- 2003年11月,受邀参加Borland公司成立20周年举办的“Borland首届开发者大会”,发表题为“利用Delphi实现在Microsoft .NET下的开发”的演讲。
- 2004年8月,由电子工业出版社出版软件开发专著《Delphi源码分析》,被业界誉为“Delphi领域精品著作”。
- 2004年10月,在JavaScript实现完整的OOP特性,并进一步完成企业级的RIA框架WEUI。该框架被应用在电信系统的大型业务项目中。
- 2005年3月,完成《大道至简——软件工程实践者的思想》一书的编写,并开始在《程序员》连载。并于2005年11月,发布该书的电子版。
| 引用(0)
~~~~~
一、 发生了就发生了吧
~~~~~
关于Borland出售IDE的消息,我比CSDN上公开这条消息早了半天知道。接下来这些天,总有
人在MSN或者mail里问我关于这个消息的态度,我一方面显得很乐观,另一方面也很淡然。从
整件事情开始直到现在,我似乎少了李维那种惊叹的表情,我总是淡淡地说:发生了就发生
了吧。
我的释然却是与李维有关的。我第一次见李维的时候是去BorCon 2003大会做演讲。跟李维谈
得很投机。最后我终于问到了我一直深存于心的问题:Borland到底为什么不停地买进又扔掉
技术。那一时,李维的脸色显得尴尬、茫然而又愤懑于心。李维说为了推进技术投入和高层
对技术、研发部门的关注,他甚至跟总部大吵过。然而Borland毕竟不是一个开发人员说了算
的公司。因此一些的努力只能(仅仅只能)是努力而已。
两年前李维的神情今犹历历在目,自那以后,我再也不跟李维讨论Borland的内部问题。他不
吐不快而欲言又止,愿做局外人,奈何局中人。
而今终于可以谈了。李维在blog中说“Chuck爭的累了,Danny爭的也累了,我們許多人都累
了”,我是知道的;李维说“我們無法決定Borland的走向”,我也是明白的。
~~~~~
二、机会
~~~~~
所以,当那天晚上左轻侯拿了David.I的blog给我看,我就回道“旦愿他们是对的。卖掉了,
borland才活得下去”;我甚至说“如果MS有可能买下delphi,那么对delphi来说,将会是最
大的福音”;我甚至还说“如果MS买Delphi,我就决定开始写《Delphi源代码分析》的第二版
了。还有,如果MS买,用Delphi写代码的开发人员,就又会有活路了。哈哈~~ ”。
注意我用的词是“活路”。换而言之,此前的Borland,已经把Delphi和Delphi的用户挤进死
路了。我在自己的blog中列了今年的几件事,其中尽管有写《Delphi源代码分析》的打算,但
却实在提不起兴趣来写它。如今连我,以及我的这本书都看到了希望。
不是因为结果会如何,而是因为出现了新的机会。
曾经5415兄在DELPHIBBS里大大地捣乱,得罪了N多人。后来有人问我对这件事的看法,我说“
即便是一锅糨糊,也好过一潭死水”。如今对Borland售出IDE的局面,我仍旧是这个观点。今
天又在李维的blog里看到他说“我終於又看到了『創新』,『激情』和『朝氣』”。我深以为
然。起码,Delphi以及Borland的IDE产品线又面临了新的机会。
~~~~~
三、语言
~~~~~
很多人问我对Delphi的未来的看法,因为在很多人看来,我是Delphi的拥护者。事实上,我也
一直拥护Delphi。我如今做架构设计中,一些示例代码都还习惯用Delphi来完成。
然而在MSN上divey对我说“我有点担心delphi的未来呀”。我的回答却是这样:
----------------
有什么必要担心这个呢?语言,不过是一种工具,而已。
我也喜欢Delphi。可能方式不一样。如果Delphi没有好的买家,或者未来的发展不济。我可能
会改写Delphi 2006的内核,使它能跑在Delphi 7上面。或者我也可能改写一些有价值的VCL,
使他能在Delphi 7上运行。
无所谓了。如果不能商用,并不等于它就死亡了。死不死亡,是它之于你的状态。你怎么看,
都可以。
我现在还是在用delphi 2006写代码。我并不担心它消失或者消亡。因为这些代码可以被移植,
也可以放弃。没有永恒的语言,只有永恒的思想。过于固守语言的人,才会痛苦于Delphi的存
在与消亡。——不过,我痛惜Borland的现状,觉得,尽管没有了Delphi/IDE的产品线的Borland,
有点壮士断腕的惨烈。不过于整件事的结果,我却是乐观的。
----------------
所以,在我看来语言只是一种表达编程思想的方式。如果这种方式不够方便了,就换一种;如
果有能力去改变他,就去重新组织语言去重述它。如果又懒于改变它,又不想改换它,只是在
那里哼哼,那么和一个套在大枷下的囚徒有什么两样呢?
~~~~~
四、买家
~~~~~
这两天还跟老朋友leon谈到了Delphi的买家的问题。事实上,尽管我说“最好MS买掉Delphi”,
然而那只是一时之言。仔细的推敲,Borland怎么卖,卖给谁都还是问题。
首先我认为Borland IDE产品线不可能放到开源界。一则是Borland现在资源紧张,没有这么大
的手笔。再则Borland IDE基本都是商用产品,扔到开源界的话,Borland要承担商业维护的责
任。所以Borland会把IDE买给一家企业用户能接受,不会为此跟Borland找麻烦的公司。
接下来我认为Borland的IDE产品线应该分拆来买,而不是整条产品线向一家公司买出。正如我
跟左轻候说的“谁一方面搞java,一方面又搞.net。原本也只有borland会这样BT的”。所以
Borland可以将IDE拆成SUN、Linux和Windows平台三个部分来买。在这种情况下,买出的机会,
以及买个好价钱的机会反倒大得多。
关于Windows平台的部分,我认为MS购买Delphi的机率有40%。首先pascal/delphi语言有非常庞
大的用户群,对MS在win32/.net两个方向上都有足够的支持。再则Delphi的体系与.NET的体系有
近同的地方,MS要改造它并不难。而另一方面,MS尽管在.NET时代力主推动C#,但对于既有的语
言,例如C++、java、vb,甚至JScript也并不轻视。.NET的语言系统内置C#、J#、VB.NET和
JScript.NET,并不仅仅是“显示架构体系的整合能力”那么简单。当然,在这个体系中,加入
Delphi for .NET,也是MS乐见之事。最后Anders Hejlsberg在MS和.NET中的角色,也使得Delphi
收归MS不显得那么突兀。
不要说我亲MS,我在所有非公开的文档中都是将MS打成M$的。然而我也认为,MS的这个商业推动
能力对Delphi来说,是好事而非坏事。Borland却正是缺乏这种能力,所以我在给leon说到这个问
题时说“(borland)没有足够的力量来发展IDE产品线了,而且IDE并不挣钱。——MS可以花4/5年
来推.net,可以面向开发人员出免费的express,你说borland还能做什么?有什么可争的?放弃
是很明智的。”。
然而leon表达了不同的意见,他认为Delphi拿在Borland手里还有活路,买出去最终是死掉,而
丢到MS的手里会死得最惨。哈哈,的确是不一样的想法:
----------------
leon : 卖的delphi的borland还是borland吗?
我 : borland一心面向企业应用提供ALM,尽管这是面子上的功夫。——也许CEO只想拿一笔就
跑路。但另一面的影响,可能也给了delphi这些产品更大的空间。
我 : 我觉得borland象是一个无主的孤魂,没有思想也没有方向。如果这样,这些IDE产品离开
他们这些昏头昏脑的管理层,反倒是好事情。
leon : 说明borland已经默认了失败,准备趁着delphi还值点钱,赶快卖了,delphi的死活,borland
已经不关心了。
我 : 是。其实他们早就不关心了。
leon : 买家会好好的做delphi吗? ms如果买了,我肯定不会好好的做它。其他人买了,有能力做
好它吗???
我 : 这个这个~~MS买了反倒会好。
我 : 因为MS不会放弃大批的、成型的pascal/delphi语言市场。他知道争取语言,而并不是产品。
我 : 他们可能会从此把Delphi叫D#。但没关系,真的,真正由MS来运作这个Delphi,我反倒放心些。
leon : 不可能,vb它现在都干甩了,捧一个c#来,pascal算什么
leon : 看看java#吧,有几个人用?
leon : vb.net市场的萎缩速度估计微软都没有想到
我 : MS知道不可能由一个语言来一统天下的。
我 : 但可能如你所说,即使MS来做Delphi,也未必能活下来。这倒是真的。
leon : 但pascal肯定不是一个可以活下来的语言
leon : ms做,肯定活不下来
leon : 其他人做,也活不下来
我 : 我倒不担心这个~~说老实话。尽管我比较偏向MS来收购,但我只是认为没有更好的买家了。
起码MS还有能力(而不是有可能)做好它。
leon : delphi死了!
leon : 他(MS)买就是让他死的
leon : 都是死,所以我说borland的这个决定其实已经宣判delphi死了
我 : 怎么说呢。那你说说谁买不是个死?
我 : 我的认为是:放在borland手里,是死路一条;放出来,有活的机会。
我 : ——看到我这一段时间的MSN签名了吗?
我 : “生存或者死亡,是个问题”。
----------------
在生活或者死亡这个问题上,如一部分人一样,leon是悲观的、绝望的。如另一部分人一样,我是乐观
的、观望的。
~~~~~
五、期待
~~~~~
所以,我对左轻候说完下面这句话之后,就关掉了MSN,洗洗睡了:
----------------
对头对头。所以呢,快卖快卖。一旦花落谁家,大局一定,就一切明朗了。
----------------
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=600408
一、 发生了就发生了吧
~~~~~
关于Borland出售IDE的消息,我比CSDN上公开这条消息早了半天知道。接下来这些天,总有
人在MSN或者mail里问我关于这个消息的态度,我一方面显得很乐观,另一方面也很淡然。从
整件事情开始直到现在,我似乎少了李维那种惊叹的表情,我总是淡淡地说:发生了就发生
了吧。
我的释然却是与李维有关的。我第一次见李维的时候是去BorCon 2003大会做演讲。跟李维谈
得很投机。最后我终于问到了我一直深存于心的问题:Borland到底为什么不停地买进又扔掉
技术。那一时,李维的脸色显得尴尬、茫然而又愤懑于心。李维说为了推进技术投入和高层
对技术、研发部门的关注,他甚至跟总部大吵过。然而Borland毕竟不是一个开发人员说了算
的公司。因此一些的努力只能(仅仅只能)是努力而已。
两年前李维的神情今犹历历在目,自那以后,我再也不跟李维讨论Borland的内部问题。他不
吐不快而欲言又止,愿做局外人,奈何局中人。
而今终于可以谈了。李维在blog中说“Chuck爭的累了,Danny爭的也累了,我們許多人都累
了”,我是知道的;李维说“我們無法決定Borland的走向”,我也是明白的。
~~~~~
二、机会
~~~~~
所以,当那天晚上左轻侯拿了David.I的blog给我看,我就回道“旦愿他们是对的。卖掉了,
borland才活得下去”;我甚至说“如果MS有可能买下delphi,那么对delphi来说,将会是最
大的福音”;我甚至还说“如果MS买Delphi,我就决定开始写《Delphi源代码分析》的第二版
了。还有,如果MS买,用Delphi写代码的开发人员,就又会有活路了。哈哈~~ ”。
注意我用的词是“活路”。换而言之,此前的Borland,已经把Delphi和Delphi的用户挤进死
路了。我在自己的blog中列了今年的几件事,其中尽管有写《Delphi源代码分析》的打算,但
却实在提不起兴趣来写它。如今连我,以及我的这本书都看到了希望。
不是因为结果会如何,而是因为出现了新的机会。
曾经5415兄在DELPHIBBS里大大地捣乱,得罪了N多人。后来有人问我对这件事的看法,我说“
即便是一锅糨糊,也好过一潭死水”。如今对Borland售出IDE的局面,我仍旧是这个观点。今
天又在李维的blog里看到他说“我終於又看到了『創新』,『激情』和『朝氣』”。我深以为
然。起码,Delphi以及Borland的IDE产品线又面临了新的机会。
~~~~~
三、语言
~~~~~
很多人问我对Delphi的未来的看法,因为在很多人看来,我是Delphi的拥护者。事实上,我也
一直拥护Delphi。我如今做架构设计中,一些示例代码都还习惯用Delphi来完成。
然而在MSN上divey对我说“我有点担心delphi的未来呀”。我的回答却是这样:
----------------
有什么必要担心这个呢?语言,不过是一种工具,而已。
我也喜欢Delphi。可能方式不一样。如果Delphi没有好的买家,或者未来的发展不济。我可能
会改写Delphi 2006的内核,使它能跑在Delphi 7上面。或者我也可能改写一些有价值的VCL,
使他能在Delphi 7上运行。
无所谓了。如果不能商用,并不等于它就死亡了。死不死亡,是它之于你的状态。你怎么看,
都可以。
我现在还是在用delphi 2006写代码。我并不担心它消失或者消亡。因为这些代码可以被移植,
也可以放弃。没有永恒的语言,只有永恒的思想。过于固守语言的人,才会痛苦于Delphi的存
在与消亡。——不过,我痛惜Borland的现状,觉得,尽管没有了Delphi/IDE的产品线的Borland,
有点壮士断腕的惨烈。不过于整件事的结果,我却是乐观的。
----------------
所以,在我看来语言只是一种表达编程思想的方式。如果这种方式不够方便了,就换一种;如
果有能力去改变他,就去重新组织语言去重述它。如果又懒于改变它,又不想改换它,只是在
那里哼哼,那么和一个套在大枷下的囚徒有什么两样呢?
~~~~~
四、买家
~~~~~
这两天还跟老朋友leon谈到了Delphi的买家的问题。事实上,尽管我说“最好MS买掉Delphi”,
然而那只是一时之言。仔细的推敲,Borland怎么卖,卖给谁都还是问题。
首先我认为Borland IDE产品线不可能放到开源界。一则是Borland现在资源紧张,没有这么大
的手笔。再则Borland IDE基本都是商用产品,扔到开源界的话,Borland要承担商业维护的责
任。所以Borland会把IDE买给一家企业用户能接受,不会为此跟Borland找麻烦的公司。
接下来我认为Borland的IDE产品线应该分拆来买,而不是整条产品线向一家公司买出。正如我
跟左轻候说的“谁一方面搞java,一方面又搞.net。原本也只有borland会这样BT的”。所以
Borland可以将IDE拆成SUN、Linux和Windows平台三个部分来买。在这种情况下,买出的机会,
以及买个好价钱的机会反倒大得多。
关于Windows平台的部分,我认为MS购买Delphi的机率有40%。首先pascal/delphi语言有非常庞
大的用户群,对MS在win32/.net两个方向上都有足够的支持。再则Delphi的体系与.NET的体系有
近同的地方,MS要改造它并不难。而另一方面,MS尽管在.NET时代力主推动C#,但对于既有的语
言,例如C++、java、vb,甚至JScript也并不轻视。.NET的语言系统内置C#、J#、VB.NET和
JScript.NET,并不仅仅是“显示架构体系的整合能力”那么简单。当然,在这个体系中,加入
Delphi for .NET,也是MS乐见之事。最后Anders Hejlsberg在MS和.NET中的角色,也使得Delphi
收归MS不显得那么突兀。
不要说我亲MS,我在所有非公开的文档中都是将MS打成M$的。然而我也认为,MS的这个商业推动
能力对Delphi来说,是好事而非坏事。Borland却正是缺乏这种能力,所以我在给leon说到这个问
题时说“(borland)没有足够的力量来发展IDE产品线了,而且IDE并不挣钱。——MS可以花4/5年
来推.net,可以面向开发人员出免费的express,你说borland还能做什么?有什么可争的?放弃
是很明智的。”。
然而leon表达了不同的意见,他认为Delphi拿在Borland手里还有活路,买出去最终是死掉,而
丢到MS的手里会死得最惨。哈哈,的确是不一样的想法:
----------------
leon : 卖的delphi的borland还是borland吗?
我 : borland一心面向企业应用提供ALM,尽管这是面子上的功夫。——也许CEO只想拿一笔就
跑路。但另一面的影响,可能也给了delphi这些产品更大的空间。
我 : 我觉得borland象是一个无主的孤魂,没有思想也没有方向。如果这样,这些IDE产品离开
他们这些昏头昏脑的管理层,反倒是好事情。
leon : 说明borland已经默认了失败,准备趁着delphi还值点钱,赶快卖了,delphi的死活,borland
已经不关心了。
我 : 是。其实他们早就不关心了。
leon : 买家会好好的做delphi吗? ms如果买了,我肯定不会好好的做它。其他人买了,有能力做
好它吗???
我 : 这个这个~~MS买了反倒会好。
我 : 因为MS不会放弃大批的、成型的pascal/delphi语言市场。他知道争取语言,而并不是产品。
我 : 他们可能会从此把Delphi叫D#。但没关系,真的,真正由MS来运作这个Delphi,我反倒放心些。
leon : 不可能,vb它现在都干甩了,捧一个c#来,pascal算什么
leon : 看看java#吧,有几个人用?
leon : vb.net市场的萎缩速度估计微软都没有想到
我 : MS知道不可能由一个语言来一统天下的。
我 : 但可能如你所说,即使MS来做Delphi,也未必能活下来。这倒是真的。
leon : 但pascal肯定不是一个可以活下来的语言
leon : ms做,肯定活不下来
leon : 其他人做,也活不下来
我 : 我倒不担心这个~~说老实话。尽管我比较偏向MS来收购,但我只是认为没有更好的买家了。
起码MS还有能力(而不是有可能)做好它。
leon : delphi死了!
leon : 他(MS)买就是让他死的
leon : 都是死,所以我说borland的这个决定其实已经宣判delphi死了
我 : 怎么说呢。那你说说谁买不是个死?
我 : 我的认为是:放在borland手里,是死路一条;放出来,有活的机会。
我 : ——看到我这一段时间的MSN签名了吗?
我 : “生存或者死亡,是个问题”。
----------------
在生活或者死亡这个问题上,如一部分人一样,leon是悲观的、绝望的。如另一部分人一样,我是乐观
的、观望的。
~~~~~
五、期待
~~~~~
所以,我对左轻候说完下面这句话之后,就关掉了MSN,洗洗睡了:
----------------
对头对头。所以呢,快卖快卖。一旦花落谁家,大局一定,就一切明朗了。
----------------
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=600408
| 引用(0)
最近,5月19日,Linux操作系统的奠基人Linus Torvalds,一位36岁的芬兰人,邀请Kristie Lu Stout先生(本文称KLS先生)到家中做客,倾吐了自己的心声。他们的谈话,很有意思。
KLS先生问:“在当今Linux开发中,您扮演什么角色”?
Linus Torvalds(本文简称LT)说:“好的(Well,口头语),当今我所做的大多数事情,实际上就是沟通。现在,我已经不作为主要的程序开发者,实际上,我所做的事情主要是:作为许多Linux程序开发者的一个“中心点”,我把他们汇聚起来,就他们该做什么事情,进行相互“沟通””。注意,在这个问题上,Torvalds本人非常谦虚,他不用“主持”、“协调”等字眼,而仅用“沟通”两字。他把自己比喻成一个“中心点”(Central Point),而不是什么“中心”(Center)。当今,Linux操作系统(内核)已有近千万行源代码,若是用A4打印纸把其全部程序都打印出来,堆在一起,高达10米以上。当今,有谁敢说,对于Linux的全部源代码能够“倒背如流”,“了如指掌”?实际上,Linux操作系统的复杂性,早已超出某一个人的思维能力所能完全控制的程度,也不是几个人,花费几天时间,就能完全“搞定”的。在Linux上,搞“自主创新”,谈何容易?!谈论什么“国产Linux”,更是荒谬之极。
KLS先生问:“根据您的估计,Linux的开发者大概有多少人”?
LT说:“实际上,我只是与很少的几个人在一起工作。所以,我只与10~20个人保持直接的相互沟通。Linux核心开发者有20~50人,而外围参与人员有数千人之多。人们(指Linux开发者)都是通过电子邮件进行相互沟通。他们实际在什么地方并不重要”。实际上,Linux的核心开发人员分布在世界不同国家和地区,但是,肯定不在我们的国家。这是客观事实。由此,这并不能说,在我国境内就没有人能够完全懂得Linux、彻底掌握Linux,能够修改和完善Linux,从而无所作为。Linux能够“为我所用”,但是,一定要遵守国际“游戏规则”。
KLS先生问:“请问,是什么动机(或者因素)促使Linux核心团队成员能够不断努力工作,从而有可能创建出最好的开源软件产品”?
LT回答:“大多数Linux的核心成员,都像我一样,只是对技术问题感兴趣,喜欢做他们自己感兴趣的事情,这似乎成了一种习惯。至少从我们开发者的立场来看,没有一个人从事Linux开发是出自对微软的憎恨(Hate)。特别是,与我共事的核心成员,没有一个人是出于这种理由而工作,他们只是喜欢做自己喜欢做的事情。”因此,把一批Linux爱好者想象为是一群十分憎恨微软的人,完全没有根据。微软与微软的技术,要加以区分,是两个不同的概念。Linux和Windows,作为两种操作系统,都有存在的理由,都有使用的根据。当今,兴起一种“虚拟化”技术,在同一台计算机上,能够驱动多种操作系统同时运行。红帽Linux和微软的Windows Vista都包含这种新技术,为此,微软表示将对Linux予以支持。根据对北美市场今年年初进行的一项调查发现,到今年年底,在Windows和Linux平台上进行软件开发的程序员人数“持平”,各占50%。这是客观事实。至此,Linux和Windows,将共存于一个软件生态链之中。
KLS先生问:“在过去几年中,Linux获得了极大的增长,特别是在桌面计算机方面,比如:OpenOffice(办公套件)和FireFox(火狐)。您是否认为,我们已经接近一个“时点”,从此开始,Linux将变为主流”?
LT说:“好的,就我的考虑来看,Linux实际上已经“相当主流”了,我为此已经做了15年。您必须理解,在整个这件事情上,我个人有略为不同的看法”。
KLS先生说:“这一点,我理解。但是,比如就您的母亲和我的母亲而言,他们在互联网上冲浪,未必使用FireFox浏览器,甚至他们根本不知道Linux实际上是什么东西”。
LT说:“开源软件肯定已经到了那个时刻,许多人实际上并不知道开源技术的本身,但是,他们却开始明白开源的理念并且开始使用开源软件产品”。
LT接着说:“不仅是Linux,我是说,FireFox肯定是许多人将会看到的开源软件产品之一,因为他们喜欢它、因为它更好、因为它更安全、或是其他数不尽的理由”。在这里,Linus Torvalds说的意思是,现今,开源软件的产品在不知不觉中已经进入了人们的实际生活。据统计,美国境内70~80%的企业,都在不同程度上使用着开源软件产品,但是,这些企业的老板们却未必都清楚地认识到这一事实。在我国,开源软件产品,比如:OpenOffice办公套件,许多单位实际上都在使用它,但是,开源软件产品OpenOffice却被某些国内厂商加上了一个“国产面具”,模糊了人们的视线。
KLS先生说:“还有另外一个理由,它(指开源软件)是微软产品的替代物”。
LT说:“好的,我想,这是有点夸大了它(指开源软件)必须发挥出的作用”。
KLS先生问:“在1990年早期,你开始做Linux的时候,是什么因素促使你公开分发它的源代码的”?
LT说:“我开始并没有想到自己要公开程序的源代码 。那时,我才21岁,是赫尔辛基大学的学生,大部分生活时间都是在编程。我所做过的这整个项目全是为了我自己的兴趣,即技术挑战,也是为了解决自己所遇到的问题。至今,Linux的开发与那个时期的情况并没有什么不同”。LT接着说:“开源软件实际上并不是“我要使它开放源码”的有意识的一项决定”;“在很大程度上,开源软件仅是一种途径(方法),使得别人可以看见你编写的源代码,并且说,“咳,这是我编写的代码,我为此感到十分自豪””。15年如一日,Linus Torvalds始终坚持“做Linux”,从不停步,但是,他并没有特定的商业目的。
KLS先生问:“您以前是否想到过借助Linux赚钱”?
LT说:“我已经很富裕了。这个想法不错。但是,它不是我所感兴趣的事情。在许多方面,整个Linux商业市场,使我感到很幸福,因为商业市场做的所有这些事情,要是让我来做,绝对只有“零兴趣”。但是,每月我拿的工资最终还是出自Linux商业市场所创造的价值。我只去做我所喜欢的Linux技术方面的工作,而不去涉及有关Linux商业市场方面的事务。我想,对于这种安排,每个人都会喜欢。”Linus Torvalds是个明白人,他只做自己所精通的Linux技术工作,决不涉足Linux的商业运作。
KLS先生问:“这些年来,Linux催生了许多别的开放技术,甚至形成了一种开源精神或是开源哲学。您对此有何看法”?
LT说:“就有关主体而言,我们不能把荣誉只给予Linux,在Linux出现之前,就存在许多开源计划和自由软件。从多方面来说,Linux只是这一领域里面的较为明显可见的大型开源技术开发项目之一。因为Linux采取了既有实践证明,也有理论根据的开发途径,由此改变了人们对于开放技术的看法。同时,我并不认为整个的“开放性观念”是个新的什么东西。实际上,我经常把开源模式与科学研究做比较。采取“完全开放”的观念,并且在前人成果的基础上进行不断的改善,最终使科学成为今天的样子,并且取得了令人难以置信的巨大成就。相反,巫术和炼丹术不准你采取这种“开放性”研究途径,结果导致今天的彻底衰落。所以,开放性并不是个什么新东西,实际上,它是长久以来就在发挥作用的。”Linux Torvalds把开源模式比作科学技术研究,寓意极为深刻。当今,在我国软件界,提倡“完全自主创新”,是缺乏科学根据的。
KLS先生说:“当今,在技术圈子里面,您好像成了摇滚明星”?
LT回答:“在平常生活中,我根本不关心这些事情。实际上,我不参加许多这种会议。一般情况下,人们不会认出我来,不会把裤子掷向我。我是一个完全正常的人,喜欢坐在自己的小书斋(Den)里做自己喜欢做的事情”。
KLS先生问:“您对Linux的未来,有何想法?没有您,Linux是否还能够继续幸存下去”?
LT回答:“现今,Linux已经长大了。十年前,它需要我,无论是个人方面的原因,还是作为Linux的领头人。但是,现在情况不同了,许多公司,许多人都懂得这种技术。我最终只是成了一个“中心汇聚点”,因为,人们了解我,人们信任我。我是中性的。实际上,我热爱做(do)Linux。我喜欢技术挑战。在工作上,我喜欢相互配合,而且只要我继续做Linux,我会是一个最为合适的人选”。
KLS先生最后问:“在今后的Linux开发过程中,您还愿意继续做Linux开发的中心聚焦点吗”?
LT明确回答:“当然,同时,我也将试图把尽可能多的工作“外包”出去,不继续进行“微观管理”。我仍然希望当好那个“中心点”,但是,不想成为阻碍任何事情的“瓶颈”。
由此可见,Linux就是一本书,总编兼作者就是Linus Torvalds本人,参与该书写作的人大多还在世。“Linux”作为一个注册商标在美国是有效的,受到法律保护。对于我们而言,如何正确对待Linux,有两条途径可以选择:1,参与写作,共享成果;2,不参与写作,只是拿来阅读(包括使用)。这两种选择都行。或者,我们对Linux根本不予理会,完全“自主创新”,另搞一套。
在北美经济发达地区,软件开发者在市场的驱动下,可以自由选择开发平台,根据一项最近的调查,到今年年底,在Windows和Linux操作系统平台上,软件开发者人数将达到一个“平衡点”(请见“Tipping Point Ahead”一文)。在怎样正确看待Linux的问题上,我们应当持有客观、公正的立场,不应被商业操作所干扰,
Linux就是一本大厚书,让我们善待它吧!
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=783710
KLS先生问:“在当今Linux开发中,您扮演什么角色”?
Linus Torvalds(本文简称LT)说:“好的(Well,口头语),当今我所做的大多数事情,实际上就是沟通。现在,我已经不作为主要的程序开发者,实际上,我所做的事情主要是:作为许多Linux程序开发者的一个“中心点”,我把他们汇聚起来,就他们该做什么事情,进行相互“沟通””。注意,在这个问题上,Torvalds本人非常谦虚,他不用“主持”、“协调”等字眼,而仅用“沟通”两字。他把自己比喻成一个“中心点”(Central Point),而不是什么“中心”(Center)。当今,Linux操作系统(内核)已有近千万行源代码,若是用A4打印纸把其全部程序都打印出来,堆在一起,高达10米以上。当今,有谁敢说,对于Linux的全部源代码能够“倒背如流”,“了如指掌”?实际上,Linux操作系统的复杂性,早已超出某一个人的思维能力所能完全控制的程度,也不是几个人,花费几天时间,就能完全“搞定”的。在Linux上,搞“自主创新”,谈何容易?!谈论什么“国产Linux”,更是荒谬之极。
KLS先生问:“根据您的估计,Linux的开发者大概有多少人”?
LT说:“实际上,我只是与很少的几个人在一起工作。所以,我只与10~20个人保持直接的相互沟通。Linux核心开发者有20~50人,而外围参与人员有数千人之多。人们(指Linux开发者)都是通过电子邮件进行相互沟通。他们实际在什么地方并不重要”。实际上,Linux的核心开发人员分布在世界不同国家和地区,但是,肯定不在我们的国家。这是客观事实。由此,这并不能说,在我国境内就没有人能够完全懂得Linux、彻底掌握Linux,能够修改和完善Linux,从而无所作为。Linux能够“为我所用”,但是,一定要遵守国际“游戏规则”。
KLS先生问:“请问,是什么动机(或者因素)促使Linux核心团队成员能够不断努力工作,从而有可能创建出最好的开源软件产品”?
LT回答:“大多数Linux的核心成员,都像我一样,只是对技术问题感兴趣,喜欢做他们自己感兴趣的事情,这似乎成了一种习惯。至少从我们开发者的立场来看,没有一个人从事Linux开发是出自对微软的憎恨(Hate)。特别是,与我共事的核心成员,没有一个人是出于这种理由而工作,他们只是喜欢做自己喜欢做的事情。”因此,把一批Linux爱好者想象为是一群十分憎恨微软的人,完全没有根据。微软与微软的技术,要加以区分,是两个不同的概念。Linux和Windows,作为两种操作系统,都有存在的理由,都有使用的根据。当今,兴起一种“虚拟化”技术,在同一台计算机上,能够驱动多种操作系统同时运行。红帽Linux和微软的Windows Vista都包含这种新技术,为此,微软表示将对Linux予以支持。根据对北美市场今年年初进行的一项调查发现,到今年年底,在Windows和Linux平台上进行软件开发的程序员人数“持平”,各占50%。这是客观事实。至此,Linux和Windows,将共存于一个软件生态链之中。
KLS先生问:“在过去几年中,Linux获得了极大的增长,特别是在桌面计算机方面,比如:OpenOffice(办公套件)和FireFox(火狐)。您是否认为,我们已经接近一个“时点”,从此开始,Linux将变为主流”?
LT说:“好的,就我的考虑来看,Linux实际上已经“相当主流”了,我为此已经做了15年。您必须理解,在整个这件事情上,我个人有略为不同的看法”。
KLS先生说:“这一点,我理解。但是,比如就您的母亲和我的母亲而言,他们在互联网上冲浪,未必使用FireFox浏览器,甚至他们根本不知道Linux实际上是什么东西”。
LT说:“开源软件肯定已经到了那个时刻,许多人实际上并不知道开源技术的本身,但是,他们却开始明白开源的理念并且开始使用开源软件产品”。
LT接着说:“不仅是Linux,我是说,FireFox肯定是许多人将会看到的开源软件产品之一,因为他们喜欢它、因为它更好、因为它更安全、或是其他数不尽的理由”。在这里,Linus Torvalds说的意思是,现今,开源软件的产品在不知不觉中已经进入了人们的实际生活。据统计,美国境内70~80%的企业,都在不同程度上使用着开源软件产品,但是,这些企业的老板们却未必都清楚地认识到这一事实。在我国,开源软件产品,比如:OpenOffice办公套件,许多单位实际上都在使用它,但是,开源软件产品OpenOffice却被某些国内厂商加上了一个“国产面具”,模糊了人们的视线。
KLS先生说:“还有另外一个理由,它(指开源软件)是微软产品的替代物”。
LT说:“好的,我想,这是有点夸大了它(指开源软件)必须发挥出的作用”。
KLS先生问:“在1990年早期,你开始做Linux的时候,是什么因素促使你公开分发它的源代码的”?
LT说:“我开始并没有想到自己要公开程序的源代码 。那时,我才21岁,是赫尔辛基大学的学生,大部分生活时间都是在编程。我所做过的这整个项目全是为了我自己的兴趣,即技术挑战,也是为了解决自己所遇到的问题。至今,Linux的开发与那个时期的情况并没有什么不同”。LT接着说:“开源软件实际上并不是“我要使它开放源码”的有意识的一项决定”;“在很大程度上,开源软件仅是一种途径(方法),使得别人可以看见你编写的源代码,并且说,“咳,这是我编写的代码,我为此感到十分自豪””。15年如一日,Linus Torvalds始终坚持“做Linux”,从不停步,但是,他并没有特定的商业目的。
KLS先生问:“您以前是否想到过借助Linux赚钱”?
LT说:“我已经很富裕了。这个想法不错。但是,它不是我所感兴趣的事情。在许多方面,整个Linux商业市场,使我感到很幸福,因为商业市场做的所有这些事情,要是让我来做,绝对只有“零兴趣”。但是,每月我拿的工资最终还是出自Linux商业市场所创造的价值。我只去做我所喜欢的Linux技术方面的工作,而不去涉及有关Linux商业市场方面的事务。我想,对于这种安排,每个人都会喜欢。”Linus Torvalds是个明白人,他只做自己所精通的Linux技术工作,决不涉足Linux的商业运作。
KLS先生问:“这些年来,Linux催生了许多别的开放技术,甚至形成了一种开源精神或是开源哲学。您对此有何看法”?
LT说:“就有关主体而言,我们不能把荣誉只给予Linux,在Linux出现之前,就存在许多开源计划和自由软件。从多方面来说,Linux只是这一领域里面的较为明显可见的大型开源技术开发项目之一。因为Linux采取了既有实践证明,也有理论根据的开发途径,由此改变了人们对于开放技术的看法。同时,我并不认为整个的“开放性观念”是个新的什么东西。实际上,我经常把开源模式与科学研究做比较。采取“完全开放”的观念,并且在前人成果的基础上进行不断的改善,最终使科学成为今天的样子,并且取得了令人难以置信的巨大成就。相反,巫术和炼丹术不准你采取这种“开放性”研究途径,结果导致今天的彻底衰落。所以,开放性并不是个什么新东西,实际上,它是长久以来就在发挥作用的。”Linux Torvalds把开源模式比作科学技术研究,寓意极为深刻。当今,在我国软件界,提倡“完全自主创新”,是缺乏科学根据的。
KLS先生说:“当今,在技术圈子里面,您好像成了摇滚明星”?
LT回答:“在平常生活中,我根本不关心这些事情。实际上,我不参加许多这种会议。一般情况下,人们不会认出我来,不会把裤子掷向我。我是一个完全正常的人,喜欢坐在自己的小书斋(Den)里做自己喜欢做的事情”。
KLS先生问:“您对Linux的未来,有何想法?没有您,Linux是否还能够继续幸存下去”?
LT回答:“现今,Linux已经长大了。十年前,它需要我,无论是个人方面的原因,还是作为Linux的领头人。但是,现在情况不同了,许多公司,许多人都懂得这种技术。我最终只是成了一个“中心汇聚点”,因为,人们了解我,人们信任我。我是中性的。实际上,我热爱做(do)Linux。我喜欢技术挑战。在工作上,我喜欢相互配合,而且只要我继续做Linux,我会是一个最为合适的人选”。
KLS先生最后问:“在今后的Linux开发过程中,您还愿意继续做Linux开发的中心聚焦点吗”?
LT明确回答:“当然,同时,我也将试图把尽可能多的工作“外包”出去,不继续进行“微观管理”。我仍然希望当好那个“中心点”,但是,不想成为阻碍任何事情的“瓶颈”。
由此可见,Linux就是一本书,总编兼作者就是Linus Torvalds本人,参与该书写作的人大多还在世。“Linux”作为一个注册商标在美国是有效的,受到法律保护。对于我们而言,如何正确对待Linux,有两条途径可以选择:1,参与写作,共享成果;2,不参与写作,只是拿来阅读(包括使用)。这两种选择都行。或者,我们对Linux根本不予理会,完全“自主创新”,另搞一套。
在北美经济发达地区,软件开发者在市场的驱动下,可以自由选择开发平台,根据一项最近的调查,到今年年底,在Windows和Linux操作系统平台上,软件开发者人数将达到一个“平衡点”(请见“Tipping Point Ahead”一文)。在怎样正确看待Linux的问题上,我们应当持有客观、公正的立场,不应被商业操作所干扰,
Linux就是一本大厚书,让我们善待它吧!
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=783710
| 引用(0)
引用
非常对不起作者,当初贴得时候一时图快,没有加上您得地址,在这里向您表示深深得道歉.
原文地址:http://blog.csdn.net/bluesen/archive/2006/06/09/783734.aspx
原文地址:http://blog.csdn.net/bluesen/archive/2006/06/09/783734.aspx
--TTS漫谈
首先声明,我不是语言专家,以下讨论从程序员的角度出发。
TTS就是Text To Speech,文本转语音,文本朗读,差不多是一个意思。在语音系统开发中经常要用到。
//转载请注明来源:http://blog.csdn.net/tingya
//版权声明:
//本书是《Apache源代码全景分析》的草稿部分,
//读者可以自由浏览和打印
//未经本文允许,不得以任何形式出现在盈利印刷品中,否则将追究法律责任!!!
9.1 套接字地址
9.1.1套接字地址
在了解APR中对IP地址的封装之前,我们首先看一下通常情况下对IP地址的使用情况。下面的代码掩饰了简单的服务器端套接字的地址初始化过程:
struct sockaddr_in server_addr; /* 本机地址信息 */
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(SERVPORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
……
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size);
Socket API中提供了三种类型的地址:sockaddr,sockaddr_in和sockaddr_un。sockaddr是通用的套接字结构,sockaddr_in为Internet协议族的地址描述结构,sockaddr_un则是Unix协议组的地址描述结构。sockaddr_in结构中的sa_family决定是sockaddr_in还是sockaddr_un。
如果直接使用Socket API提供的地址结构,则至少存在下面的几个问题:
1、在网络应用程序中,对于internet地址,如上面的程序代码所示,通常总是使用sockaddr_in描述,而在一些Socket API函数中则使用sockaddr作为套接字地址,因此在使用的时候必须将sockaddr_in强制转换为sockaddr类型,这是一个麻烦而且容易出错的地方。
2、sockaddr_in也不是一个特别容易理解的数据结构。通常情况下,sin_family和sin_port相对容易记忆,而套接字地址sin_addr.s_addr则未必。套接字的这种结构对一般人而言无疑是一种噩梦。
3、另外一个问题则是Ipv6的地址问题。目前,Apache已经开始同时支持Ipv4和Ipv6两种类型的地址,如果用户需要支持Ipv6,则还必须使用Ipv6对应的地址数据结构。
对于一个良好的类库,不管是Ipv4还是Ipv6协议,都必须提供同样的接口,这种接口必须简单易懂,同时必须尽可能的隐藏内部的细节,比如对于sin_addr.s_addr无非暴露给用户。
基于上面的分析,APR中只使用一种数据结构apr_sockaddr_t来描述IP地址,该结构定义在文件apr_network_io.h中:
struct apr_sockaddr_t {
apr_pool_t *pool;
/*第一部分*/
char *hostname;
char *servname;
/*第二部分*/
apr_port_t port;
apr_int32_t family;
union {
struct sockaddr_in sin;
#if APR_HAVE_IPV6
struct sockaddr_in6 sin6;
#endif
#if APR_HAVE_SA_STORAGE
struct sockaddr_storage sas;
#endif
} sa;
/*第三部分*/
apr_socklen_t salen;
int ipaddr_len;
int addr_str_len;
void *ipaddr_ptr;
apr_sockaddr_t *next;
};
该结构描述了socket地址的三部分的信息内容:
第一部分:
Hostname是该地址对应的主机名称,而servname则是对应端口的服务名称,比如80对应的名称为”www”,21端口对应的servname则是”FTP”。如果某个端口比如9889并没有对应某个众所皆知的服务,那么servname则直接是端口的字符串描述。
第二部分:
该部分则对应的是sockaddr结构中的内容,port是端口,family则是地址协议族类型,包括AF_INET,AF_UNIX等。sa则为联合类型,用以描述对应的套接字地址,或者是Ipv4类型,或者是Ipv6类型,两者只能居其一。
第三部分:
这部分主要是一些与套接字地址相关的附加信息。Salen是当前套接字地址的长度,通常情况下它的值为sizeof(struct sockaddr_in),对于IPV6,则是sizeof(struct sockaddr_in6);ipiaddr_len则是对应得IP地址结构的长度,对于Ipv4总是sizeof(struct in_addr),而对于Ipv6,则是sizeof(struct in6_addr);addr_str_len则是IP地址缓冲的长度,对于Ipv4,该值为14,而对于IPV6,则是46。这三个地址的含义完全不同。
Ipaddr_ptr指针指向sockaddr结构中的IP地址结构,通常情况下,它的初始化使用下面的代码:
apr_socketaddr_t addr;
addr->ipaddr_ptr = &(addr->sa.sin.sin_addr);
对于一些服务器而言,可能会使用多个IP地址。这些IP地址之间通过next指针形成单链表结构。
从next可以看出各个socket地址之间可以形成链表。
9.1.2子网掩码结构
与此同时,APR中也定义了数据结构apr_ipsubnet_t来描述IP地址掩码,当然由于IP地址分为Ipv4和Ipv6,因此掩码描述也可以分为两种,apr_ipsubnet_t结构定义在文件apr_sockaddr.c中,属于内部数据结构,具体如下:
struct apr_ipsubnet_t {
int family;
#if APR_HAVE_IPV6
apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
apr_uint32_t mask[4];
#else
apr_uint32_t sub[1];
apr_uint32_t mask[1];
#endif
};
family是当前掩码所属于的地址族,APR_INET表示Ipv4,而APR_INET6则表示Ipv6。
对于Ipv4而言,该结构演变为如下:
struct apr_ipsubnet_t {
int family;
apr_uint32_t sub[1];
apr_uint32_t mask[1];
};
而对于Ipv6,则该结构可以演变为如下:
struct apr_ipsubnet_t {
int family;
apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
apr_uint32_t mask[4];
};
9.1.3 Socket地址处理接口
为了处理Socket地址,APR中提供了四个操作接口,这些接口定义在apr_network_io.h中,而实现则sockaddr.c中。这四个接口分别是:
9.1.3.1地址获取
由于APR中仅仅使用apr_sockaddr_t结构描述套接字地址,因此其余的各类描述信息最终都要转换为该结构,APR中提供apr_sockaddr_info_get函数实现该功能:
APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
const char *hostname,
apr_int32_t family,
apr_port_t port,
apr_int32_t flags,
apr_pool_t *p);
该函数允许从主机名hostname,地址协议族family和端口port创建新的apr_sockaddr_t地址,并由sa返回。
hostname参数允许是实际的主机名称,或者也可以是字符串类型的IP地址,比如”127.0.0.1”,甚至可以是NULL,此时默认的地址是”0.0.0.0”。
family的值可以是AF_INET,AF_UNIX等系统定义类型,也可以是APR_UNSPEC类型,此时,地址协议族由系统决定。
flags参数用以指定Ipv4和Ipv6处理的 优先级,它的取值包括两种:APR_IPV4_ADDR_OK和APR_IPV6_ADDR_OK。这两个标志并不是在所有的情况下都有效,这可以从函数的实现中看出它的用法:
{
apr_int32_t masked;
*sa = NULL;
if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
if (!hostname ||
family != APR_UNSPEC ||
masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) {
return APR_EINVAL;u
}
#if !APR_HAVE_IPV6
if (flags & APR_IPV6_ADDR_OK) {
return APR_ENOTIMPL;
}
#endif
}
#if !APR_HAVE_IPV6
if (family == APR_UNSPEC) {
family = APR_INET; v
}
#endif
return find_addresses(sa, hostname, family, port, flags, p); w
}
从实现代码可以看出,函数的内部实际的地址转换过程是由函数find_address完成的。不过在调用find_address之前,函数进行了相关检查和预处理,这些检查和预处理包括:
1、APR_IPV4_ADDR_OK标记只有在hostname为NULL,同时family为APR_UNSPEC的时候才会有效,而APR_IPV6_ADDR_OK和APR_IPV4_ADDR_OK是相互排斥的,一旦定义了APR_IPV4_ADDR_OK,就不能使用APR_IPV6_ADDR_OK,反之亦然。只有在hostname为NULL,同时family为APR_UNSPEC并且没有定义APR_IPV4_ADDR_OK的时候APR_IPV6_ADDR_OK才会有效。
2、如果操作系统平台并不支持IPV6,同时并没有限定获取的地址族,那么此时将默认为IPV6。如果指定必须获取IPV6的地址信息,但系统并不提供支持,此时返回APR_EINVAL。
一般情况下,在IPV4中从主机名到网络地址的解析可以通过gethostbyname()函数完成,不过该API不允许调用者指定所需地址类型的任何信息,这意味着它仅返回包含IPV4地址的信息,对于目前新的IPV6则无能为力。一些平台中为了支持IPV6地址的解析,提供了新的地址解析函数getaddrinfo()以及新的地址描述结构struct addrinfo。APR中通过宏HAVE_GETADDRINFO判断是否支持IPV6地址的解析。目前Window 2000/XP以上的操作系统都能支持新特性。为此APR中根据系统平台的特性采取不同的方法完成地址解析。
首先我们来看支持IPV6地址解析平台下的实现代码,find_address函数的实现如下:
static apr_status_t find_addresses(apr_sockaddr_t **sa,
const char *hostname, apr_int32_t family,
apr_port_t port, apr_int32_t flags,
apr_pool_t *p)
{
if (flags & APR_IPV4_ADDR_OK) {
apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p);
#if APR_HAVE_IPV6
if (error) {
family = AF_INET6; /* try again */ u
}
else
#endif
return error;
}
#if APR_HAVE_IPV6
else if (flags & APR_IPV6_ADDR_OK) {
apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p);
if (error) { v
family = AF_INET; /* try again */
}
else {
return APR_SUCCESS;
}
}
#endif
return call_resolver(sa, hostname, family, port, flags, p); w
}
从上面的代码可以清晰的看到APR_IPV4_ADDR_OK和APR_IPV6_ADDR_OK的含义:对于前者,函数内部首先查询对应主机的IPV4地址,只有在IPV4查询失败的时候才会继续查询IPV6地址;而后者则与之相反,对于给定的主机名称,首先查询IPV6地址,只有在查询失败的时候才会查询IPV4。因此APR_IPV4_ADDR_OK和APR_IPV6_ADDR_OK决定了查询的优先性,任何时候一旦查询成功都不会继续查询另外协议地址,即使被查询主机具有该协议地址。
查询的核心代码封装在内部函数call_resolve中,该函数的参数和apr_sockaddr_info_get函数的参数完全相同且对应,call_resolve中的宏处理比较的多,因此我们将分开描述:
static apr_status_t call_resolver(apr_sockaddr_t **sa,
const char *hostname, apr_int32_t family,
apr_port_t port, apr_int32_t flags,
apr_pool_t *p)
{
struct addrinfo hints, *ai, *ai_list;
apr_sockaddr_t *prev_sa;
int error;
char *servname = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
#ifdef HAVE_GAI_ADDRCONFIG
if (family == APR_UNSPEC) {
hints.ai_flags = AI_ADDRCONFIG;
}
#endif
在了解上面的代码之前我们首先简要的了解一些getaddrinfo函数的用法,该函数定义如下:
int getaddrinfo(const char *hostname, const char *service, const struct addinfo *hints,struct addrinfo **result);
hostname是需要进行地址解析的主机名称或者是二进制的地址串(IPV4的点分十进制或者Ipv6的十六进制数串),service则是一个服务名或者是一个十进制的端口号数串。其中hints是addfinfo结构,该结构定义如下:
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for nodename */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
hints参数可以是一个空置针,也可以是一个指向某个addrinfo结构的指针,调用者在该结构中填入关于期望返回的信息类型的暗示,这些暗示将控制内部的转换细节。比如,如果指定的服务器既支持TCP,也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置为SOCK_DGRAM,使得返回的仅仅是适用于数据报套接口的信息。
hints结构中调用者可以设置的成员包括ai_flags,ai_family,ai_socktype和ai_protocol。
其中,ai_flags成员可用的标志值及含义如下:
标志名称 标志含义
AI_PASSIVE 套接口将用于被动打开
AI_CANONNAME 告知getaddrinfo函数返回主机的规范名称
AI_NUMERICHOST 防止任何类型的名字到地址的映射;hostname必须是一个地址串
AI_NUMERICSERV 防止任何类型的名字到服务的映射,service参数必须是一个十进制端口号数串
AI_V4MAPPED 如果同时指定ai_family成员的值为AF_INET6和AF_INET,那么如果没有可用的AAAA记录就返回与A记录对应得Ipv4映射的IPV6地址
AI_ALL 如果同时指定AI_V4MAPPED标志,那么除了返回与AAAA对应得IPV6地址之外,还会返回与A记录对应的IPV4映射的Ipv6地址。
AI_ADDRCONFIG 按照所在主机的配置选择返回的地址类型,也就是只查找与所在主机回馈接口以外的网络接口配置的IP地址版本一直的地址。只有当本地系统中配置仅仅配置了IPV4地址才会将主机名称转换位IPV4地址;同样只有当本地系统中仅配置了IPV6地址的时候才会返回IPV6地址。Loopback地址并不在这种限制之中。
ai_family参数指定调用者期待返回的套接口地址结构的类型。它的值包括三种:AF_INET,AF_INET6和AF_UNSPEC。如果指定AF_INET,那么函数九不能返回任何IPV6相关的地址信息;如果仅指定了AF_INET6,则就不能返回任何IPV4地址信息。AF_UNSPEC则意味着函数返回的是适用于指定主机名和服务名且适合任何协议族的地址。如果某个主机既有AAAA记录(IPV6)地址,同时又有A记录(IPV4)地址,那么AAAA记录将作为sockaddr_in6结构返回,而A记录则作为sockaddr_in结构返回。
if(hostname == NULL) {
#ifdef AI_PASSIVE
hints.ai_flags |= AI_PASSIVE;
#endif
#ifdef OSF1
hostname = family == AF_INET6 ? "::" : "0.0.0.0";
servname = NULL;
#ifdef AI_NUMERICHOST
hints.ai_flags |= AI_NUMERICHOST;
#endif
#else
#ifdef _AIX
if (!port) {
servname = "1";
}
else
#endif /* _AIX */
servname = apr_itoa(p, port);
#endif /* OSF1 */
}
#ifdef HAVE_GAI_ADDRCONFIG
if (error == EAI_BADFLAGS && family == APR_UNSPEC) {
hints.ai_flags = 0;
error = getaddrinfo(hostname, servname, &hints, &ai_list);
}
#endif
if (error) {
#ifndef WIN32
if (error == EAI_SYSTEM) {
return errno;
}
else
#endif
{
#if defined(NEGATIVE_EAI)
error = -error;
#endif
return error + APR_OS_START_EAIERR;
}
}
9.1.3.2主机名获取
apr_sockaddr_info_get函数用以完成从主机名到网络地址的转换,而APR中提供的apr_getnameinfo则可以实现从网络地址到主机名的转换,该函数定义如下:
APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, apr_sockaddr_t *sa, apr_int32_t flags);
参数sa指定需要转换的网络地址,转换后的主机名由hostname返回。fags是标志位,用以控制内部的转换过程。
{
#if defined(HAVE_GETNAMEINFO)
int rc;
#if defined(NI_MAXHOST)
char tmphostname[NI_MAXHOST];
#else
char tmphostname[256];
#endif
SET_H_ERRNO(0);
#if APR_HAVE_IPV6
if (sockaddr->family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) {
struct sockaddr_in tmpsa;
tmpsa.sin_family = AF_INET;
tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];
#ifdef SIN6_LEN
tmpsa.sin_len = sizeof(tmpsa);
#endif
rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
tmphostname, sizeof(tmphostname), NULL, 0,
flags != 0 ? flags : NI_NAMEREQD);
}
else
#endif
#endif
rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
tmphostname, sizeof(tmphostname), NULL, 0,
flags != 0 ? flags : NI_NAMEREQD);
在函数的内部实现从地址到主机名称的解析是由函数getnameinfo完成的,该函数是getaddrinfo的互补函数,它以一个套接口地址为参数,返回描述其中的主机的一个字符串和描述其中的服务的另一个字符串。另外该函数以协议无关的方式提供这些信息,调用者必须关心存放在套接口地址结构中的协议地址的类型,这些由函数自行处理。
需要转换的地址到底是IPv4还是IPv6,这由地址结构中的family参数决定。尽管理想中的做法是将apr_getnameinfo()中的参数直接传递给getnameinfo()函数,但是在一些平台上还是会出现一些问题。
MacOS X Panther has a lousy getnameinfo() implementation that doesn't fill the buffer when no DNS entry is found for a host and a numerical result wasn't explicitely asked. As a result, Pure-FTPd didn't even start on Panther (saying "bad IP address") . We now check for EAI_NONAME if available and we retry with NI_NUMERICHOST if this is what getnameinfo() returns. Thanks to Yann Bizeul for his valuable help on this issue. Will research it more and see if I can come up with a patch (I am NOT good at C!)
在一些操作系统中,比如老版本的Mac OS X,如果Ipv6地址是由Ipv4地址映射的结果,那么该地址在传递给getnameinfo函数的时候将会产生错误,这是系统本身实现的BUG。因此对于这种情况,解决的方法就是将这种Ipv6地址重新转换为Ipv4地址。Ipv6地址是否是由Ipv4地址进行映射而成,通过宏IN6_IS_ADDR_V4MAPPED可以实现检测。IPV4到IPV6地址的映射可以用下图描述:
Ipv4地址通过在其十六进制前面添加前导零的方式映射为IPV6地址。反之如果一个IPV6地址是由IPV4地址映射而成,则只要剔除前面的前导零即可,剔除后的地址通常为((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];一旦获取了实际的IPV4地址,则可以将其传递给getnameinfo函数。
对于其余的IP地址,包括普通的Ipv4地址,非Ipv4映射的Ipv6地址,由于不存在BUG,因此可以直接调用getnameinfo。
getnameinfo函数原型如下:
Int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flag);
函数的前面几个参数都非常容易理解,只有最后一个参数flag,它用于控制getnameinfo的操作,它允许的值如下面所列:
NI_DGRAM
当知道处理的是数据报套接口的时候,调用者应该设置NI_DGRAM标志,因为在套接口地址结构中给出的仅仅是IP地址和端口号,getnameinfo无法就此确定所用协议是TCP还是UDP。比如端口514,在TCP端口上提供rsh服务,而在UDP端口上则提供syslog服务。
NI_NOFQDN
该标志导致返回的主机名称被截去第一个点号之后的内容。比如假设套接口结构中的IP地址为912.168.42.2,那么不设置该标志返回的主机名为aix.unpbook.com,那么如果设置了该标志后返回的主机名则为aix。
NI_NUMERICHOST,NI_NUMERICSERV,NI_NUMERICSCOPE
该标志通知getnameinfo不要调用DNS,而是以数值表达格式作为字符串返回IP地址;类似的,NI_NUMERICSERV标志指定以十进制数格式作为字符串返回端口号,以代替查找服务名;NI_NUMERICSCOPE则指定以数值格式作为字符串返回范围标识,以代替其名字
NI_NAMEREQD
该标志通知getnameinfo函数如果无法适用DNS反向解析出主机名,则直接返回一个错误。需要把客户的IP地址映射成主机名的那些服务器可以使用该特性。
如果flag没有指定,即为零,那么NI_NAMEREQD将是Apache中默认的标志项,如果不设置该标志,那么在反向解析失败的时候getnameinfo将返回一个数值地址字符串,显然这并不是Apache所需要的结果。
if (rc != 0) {
*hostname = NULL;
#ifndef WIN32
if (rc == EAI_SYSTEM) {
if (h_errno) { /* for broken implementations which set h_errno */
return h_errno + APR_OS_START_SYSERR;
}
else { /* "normal" case */
return errno + APR_OS_START_SYSERR;
}
}
else
#endif
{
#if defined(NEGATIVE_EAI)
if (rc < 0) rc = -rc;w
#endif
return rc + APR_OS_START_EAIERR; /* return the EAI_ error */
}
}
*hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, tmphostname);
return APR_SUCCESS;
上面的代码是对getnameinfo发生错误时候的处理(rc==0意味着成功,否则意味着转换失败)。此时将需要返回的主机名称设置为NULL。当getnameinfo发生错误的时候通常会返回EAI_XXXX的错误码,在所有这些错误码中比较特殊的就是EAI_SYSTEM,它意味着同时在errno变量中有系统错误返回,而其余的EAI_XXXX错误并不会设置errno变量。
对于非EAI_SYSTEM错误码,APR并不能直接返回。正如第一章所说,APR中对于apr_status_t返回码有自己的布局和规则,因此这些错误码必须转换至APR返回码。EAI_XXXX错误码的起始偏移是APR_OS_START_EAIERR,因此返回值实际上是rc+APR_OS_START_EAIERR。不过在一些平台上比如glibc,为了防止和h_errno的值冲突,系统将使用EAI_XXXX的负值, 这正是上面的代码w的原因。
上面的代码有一个假设前提,就是系统中必须提供getnameinfo()函数。但是由于getnameinfo()是比较新的一个函数,并不是每个操作系统平台都支持该函数。目前大部分Ipv4平台上不过都提供了gethostbyaddr()函数,通过该函数也能完成从主机地址到主机名称的转换,不过该函数仅仅支持Ipv4协议,不支持Ipv6协议。具体的代码如下所示:
#else
#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \
defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)
#ifdef GETHOSTBYNAME_R_HOSTENT_DATA
struct hostent_data hd;
#else
char tmp[GETHOSTBYNAME_BUFLEN];
#endif
int hosterror;
struct hostent hs, *hptr;
#if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
/* AIX, HP/UX, D/UX et alia */
gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, u
sizeof(struct in_addr), AF_INET, &hs, &hd);
hptr = &hs;
#else
#if defined(GETHOSTBYNAME_R_GLIBC2)
/* Linux glibc2+ */
gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, v
sizeof(struct in_addr), AF_INET,
&hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);
#else
/* Solaris, Irix et alia */
hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, w
sizeof(struct in_addr), AF_INET,
&hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);
#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
if (!hptr) {
*hostname = NULL;
return hosterror + APR_OS_START_SYSERR;
}
#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
#else
struct hostent *hptr;
hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, x
sizeof(struct in_addr), AF_INET);
#endif
if (hptr) {
*hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name);
return APR_SUCCESS;
}
*hostname = NULL;
#if defined(WIN32)
return apr_get_netos_error();
#elif defined(OS2)
return h_errno;
#else
return h_errno + APR_OS_START_SYSERR;
#endif
#endif
函数中众多的预定义让人眼花缭乱。不过最主要的预定义处理还在于对gethostbyaddr()函数的调用。从上面的代码中可以看出,gethostbyaddr有一个函数变形gethostbyaddr_r,而且不同平台下的gethostbyaddr_t函数的参数也不相同,要了解详细的原因,必须了解一些函数可重入的概念。
所谓可重入函数是指一个可以被多个任务调用的函数,任务在调用时候不必担心数据会出错;通常情况下下面的函数是不可重入的:
(1)、函数体内使用了静态的数据结构;
(2)、函数体内调用了malloc()或者free()函数;
(3)、函数体内调用了标准I/O函数。
通常情况下,在一个UNIX进程中发生重入问题的条件是:从主程序中和某个信号处理函数中同时调用某个不可重入函数.。另外在多线程应用中也会出现函数重入的问题。不幸的是由于历史的原因,我们经常使用的gethostbyaddr也是一个不可重入的函数,因为它们都返回指向同一个静态结构的指针。关于gethostbyaddr的重入问题,《Unix网络编程 第一卷:套接口API》中文版第二版的第207页中有一段描述,摘抄如下:
不幸的是,重入问题比他表面看起来更要严重。首先,关于gethostbyname和gethostbyaddr的重入问题无标准可循。POSIX规范声明这两个函数不必是可重入的。Unix98只说这两个函数必须是线程安全的。
其次,关于_r函数也没有标准可循。Solaris 2.X,Digital Unix 4.0和HP-UX 10.30都提供了可重入版本的gethostbyaddr_r函数,不过它们的参数并不相同,不同版本的gethostbyaddr_r函数原型如下表所示:
操作系统平台 函数原型
solaris struct hostent* gethostbyaddr_r(const char *addr, int len, int type,
struct hostent *result, char *buf, int buflen, int * h_errnop);
AIX,HP-UX,Digital Unix int gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
struct hostent_data *buffer);
Linux glibc2+ int gethostbyaddr_r(const char *addr,int len, int type,struct hostent *result,
char* buf, int buflen, struct hostent *hs, int* h_errnop);
大部分gethostbyaddr_r函数的前四个参数都相同,第一个是需要转换的地址;第二个地址的字节大小,用sizeof(struct in_addr)表示;第三个是需要转换地址的协议族,或者是AF_INET,或者是AF_INET6;第四个则是描述主机的hostent结构。区别通常在后几个参数:
对于Solaris,Irix等操作系统而言,后面还需要三个额外的参数,buf是由调用者分配的并且大小为buflen的缓冲区,该缓冲区用于存放规范主机名称,别名指针数组,各个别名字符串,地址指针数组以及各个实际地址。如果初出错,错误码通过h_errnop指针返回,注意不是我们通常所说的h_errno返回。
对于AIX,HP-UX,Digital Unix等平台而言,后面的三个参数则被组合为一个新的数据结构hostent_data,指向该结构的指针构成本函数的第三个和最后一个参数。Apache中默认的缓冲区大小为GETHOSTBYNAME_BUFLEN,即512字节。
对于Linux glibc2+而言,gethostbyaddr_r的参数与前两者又存在一定的差异,它共计有八个参数,与Solaris平台相比多了struct hostent* hs参数。
如果操作系统平台不支持可重入的gethostaddr_r函数,那么只能使用不可重入的gethostbyaddr函数,如x所示。
返回的主机名称保存在hostent结构中,如果查询成功,从hostname参数中返回即可。
9.1.3.3 IP地址解析
APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr,
char **scope_id,
apr_port_t *port,
const char *str,
apr_pool_t *p);
9.1.3.4 子网掩码
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish1234 at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=785671
//版权声明:
//本书是《Apache源代码全景分析》的草稿部分,
//读者可以自由浏览和打印
//未经本文允许,不得以任何形式出现在盈利印刷品中,否则将追究法律责任!!!
9.1 套接字地址
9.1.1套接字地址
在了解APR中对IP地址的封装之前,我们首先看一下通常情况下对IP地址的使用情况。下面的代码掩饰了简单的服务器端套接字的地址初始化过程:
struct sockaddr_in server_addr; /* 本机地址信息 */
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(SERVPORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
……
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size);
Socket API中提供了三种类型的地址:sockaddr,sockaddr_in和sockaddr_un。sockaddr是通用的套接字结构,sockaddr_in为Internet协议族的地址描述结构,sockaddr_un则是Unix协议组的地址描述结构。sockaddr_in结构中的sa_family决定是sockaddr_in还是sockaddr_un。
如果直接使用Socket API提供的地址结构,则至少存在下面的几个问题:
1、在网络应用程序中,对于internet地址,如上面的程序代码所示,通常总是使用sockaddr_in描述,而在一些Socket API函数中则使用sockaddr作为套接字地址,因此在使用的时候必须将sockaddr_in强制转换为sockaddr类型,这是一个麻烦而且容易出错的地方。
2、sockaddr_in也不是一个特别容易理解的数据结构。通常情况下,sin_family和sin_port相对容易记忆,而套接字地址sin_addr.s_addr则未必。套接字的这种结构对一般人而言无疑是一种噩梦。
3、另外一个问题则是Ipv6的地址问题。目前,Apache已经开始同时支持Ipv4和Ipv6两种类型的地址,如果用户需要支持Ipv6,则还必须使用Ipv6对应的地址数据结构。
对于一个良好的类库,不管是Ipv4还是Ipv6协议,都必须提供同样的接口,这种接口必须简单易懂,同时必须尽可能的隐藏内部的细节,比如对于sin_addr.s_addr无非暴露给用户。
基于上面的分析,APR中只使用一种数据结构apr_sockaddr_t来描述IP地址,该结构定义在文件apr_network_io.h中:
struct apr_sockaddr_t {
apr_pool_t *pool;
/*第一部分*/
char *hostname;
char *servname;
/*第二部分*/
apr_port_t port;
apr_int32_t family;
union {
struct sockaddr_in sin;
#if APR_HAVE_IPV6
struct sockaddr_in6 sin6;
#endif
#if APR_HAVE_SA_STORAGE
struct sockaddr_storage sas;
#endif
} sa;
/*第三部分*/
apr_socklen_t salen;
int ipaddr_len;
int addr_str_len;
void *ipaddr_ptr;
apr_sockaddr_t *next;
};
该结构描述了socket地址的三部分的信息内容:
第一部分:
Hostname是该地址对应的主机名称,而servname则是对应端口的服务名称,比如80对应的名称为”www”,21端口对应的servname则是”FTP”。如果某个端口比如9889并没有对应某个众所皆知的服务,那么servname则直接是端口的字符串描述。
第二部分:
该部分则对应的是sockaddr结构中的内容,port是端口,family则是地址协议族类型,包括AF_INET,AF_UNIX等。sa则为联合类型,用以描述对应的套接字地址,或者是Ipv4类型,或者是Ipv6类型,两者只能居其一。
第三部分:
这部分主要是一些与套接字地址相关的附加信息。Salen是当前套接字地址的长度,通常情况下它的值为sizeof(struct sockaddr_in),对于IPV6,则是sizeof(struct sockaddr_in6);ipiaddr_len则是对应得IP地址结构的长度,对于Ipv4总是sizeof(struct in_addr),而对于Ipv6,则是sizeof(struct in6_addr);addr_str_len则是IP地址缓冲的长度,对于Ipv4,该值为14,而对于IPV6,则是46。这三个地址的含义完全不同。
Ipaddr_ptr指针指向sockaddr结构中的IP地址结构,通常情况下,它的初始化使用下面的代码:
apr_socketaddr_t addr;
addr->ipaddr_ptr = &(addr->sa.sin.sin_addr);
对于一些服务器而言,可能会使用多个IP地址。这些IP地址之间通过next指针形成单链表结构。
从next可以看出各个socket地址之间可以形成链表。
9.1.2子网掩码结构
与此同时,APR中也定义了数据结构apr_ipsubnet_t来描述IP地址掩码,当然由于IP地址分为Ipv4和Ipv6,因此掩码描述也可以分为两种,apr_ipsubnet_t结构定义在文件apr_sockaddr.c中,属于内部数据结构,具体如下:
struct apr_ipsubnet_t {
int family;
#if APR_HAVE_IPV6
apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
apr_uint32_t mask[4];
#else
apr_uint32_t sub[1];
apr_uint32_t mask[1];
#endif
};
family是当前掩码所属于的地址族,APR_INET表示Ipv4,而APR_INET6则表示Ipv6。
对于Ipv4而言,该结构演变为如下:
struct apr_ipsubnet_t {
int family;
apr_uint32_t sub[1];
apr_uint32_t mask[1];
};
而对于Ipv6,则该结构可以演变为如下:
struct apr_ipsubnet_t {
int family;
apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
apr_uint32_t mask[4];
};
9.1.3 Socket地址处理接口
为了处理Socket地址,APR中提供了四个操作接口,这些接口定义在apr_network_io.h中,而实现则sockaddr.c中。这四个接口分别是:
9.1.3.1地址获取
由于APR中仅仅使用apr_sockaddr_t结构描述套接字地址,因此其余的各类描述信息最终都要转换为该结构,APR中提供apr_sockaddr_info_get函数实现该功能:
APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
const char *hostname,
apr_int32_t family,
apr_port_t port,
apr_int32_t flags,
apr_pool_t *p);
该函数允许从主机名hostname,地址协议族family和端口port创建新的apr_sockaddr_t地址,并由sa返回。
hostname参数允许是实际的主机名称,或者也可以是字符串类型的IP地址,比如”127.0.0.1”,甚至可以是NULL,此时默认的地址是”0.0.0.0”。
family的值可以是AF_INET,AF_UNIX等系统定义类型,也可以是APR_UNSPEC类型,此时,地址协议族由系统决定。
flags参数用以指定Ipv4和Ipv6处理的 优先级,它的取值包括两种:APR_IPV4_ADDR_OK和APR_IPV6_ADDR_OK。这两个标志并不是在所有的情况下都有效,这可以从函数的实现中看出它的用法:
{
apr_int32_t masked;
*sa = NULL;
if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
if (!hostname ||
family != APR_UNSPEC ||
masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) {
return APR_EINVAL;u
}
#if !APR_HAVE_IPV6
if (flags & APR_IPV6_ADDR_OK) {
return APR_ENOTIMPL;
}
#endif
}
#if !APR_HAVE_IPV6
if (family == APR_UNSPEC) {
family = APR_INET; v
}
#endif
return find_addresses(sa, hostname, family, port, flags, p); w
}
从实现代码可以看出,函数的内部实际的地址转换过程是由函数find_address完成的。不过在调用find_address之前,函数进行了相关检查和预处理,这些检查和预处理包括:
1、APR_IPV4_ADDR_OK标记只有在hostname为NULL,同时family为APR_UNSPEC的时候才会有效,而APR_IPV6_ADDR_OK和APR_IPV4_ADDR_OK是相互排斥的,一旦定义了APR_IPV4_ADDR_OK,就不能使用APR_IPV6_ADDR_OK,反之亦然。只有在hostname为NULL,同时family为APR_UNSPEC并且没有定义APR_IPV4_ADDR_OK的时候APR_IPV6_ADDR_OK才会有效。
2、如果操作系统平台并不支持IPV6,同时并没有限定获取的地址族,那么此时将默认为IPV6。如果指定必须获取IPV6的地址信息,但系统并不提供支持,此时返回APR_EINVAL。
一般情况下,在IPV4中从主机名到网络地址的解析可以通过gethostbyname()函数完成,不过该API不允许调用者指定所需地址类型的任何信息,这意味着它仅返回包含IPV4地址的信息,对于目前新的IPV6则无能为力。一些平台中为了支持IPV6地址的解析,提供了新的地址解析函数getaddrinfo()以及新的地址描述结构struct addrinfo。APR中通过宏HAVE_GETADDRINFO判断是否支持IPV6地址的解析。目前Window 2000/XP以上的操作系统都能支持新特性。为此APR中根据系统平台的特性采取不同的方法完成地址解析。
首先我们来看支持IPV6地址解析平台下的实现代码,find_address函数的实现如下:
static apr_status_t find_addresses(apr_sockaddr_t **sa,
const char *hostname, apr_int32_t family,
apr_port_t port, apr_int32_t flags,
apr_pool_t *p)
{
if (flags & APR_IPV4_ADDR_OK) {
apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p);
#if APR_HAVE_IPV6
if (error) {
family = AF_INET6; /* try again */ u
}
else
#endif
return error;
}
#if APR_HAVE_IPV6
else if (flags & APR_IPV6_ADDR_OK) {
apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p);
if (error) { v
family = AF_INET; /* try again */
}
else {
return APR_SUCCESS;
}
}
#endif
return call_resolver(sa, hostname, family, port, flags, p); w
}
从上面的代码可以清晰的看到APR_IPV4_ADDR_OK和APR_IPV6_ADDR_OK的含义:对于前者,函数内部首先查询对应主机的IPV4地址,只有在IPV4查询失败的时候才会继续查询IPV6地址;而后者则与之相反,对于给定的主机名称,首先查询IPV6地址,只有在查询失败的时候才会查询IPV4。因此APR_IPV4_ADDR_OK和APR_IPV6_ADDR_OK决定了查询的优先性,任何时候一旦查询成功都不会继续查询另外协议地址,即使被查询主机具有该协议地址。
查询的核心代码封装在内部函数call_resolve中,该函数的参数和apr_sockaddr_info_get函数的参数完全相同且对应,call_resolve中的宏处理比较的多,因此我们将分开描述:
static apr_status_t call_resolver(apr_sockaddr_t **sa,
const char *hostname, apr_int32_t family,
apr_port_t port, apr_int32_t flags,
apr_pool_t *p)
{
struct addrinfo hints, *ai, *ai_list;
apr_sockaddr_t *prev_sa;
int error;
char *servname = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
#ifdef HAVE_GAI_ADDRCONFIG
if (family == APR_UNSPEC) {
hints.ai_flags = AI_ADDRCONFIG;
}
#endif
在了解上面的代码之前我们首先简要的了解一些getaddrinfo函数的用法,该函数定义如下:
int getaddrinfo(const char *hostname, const char *service, const struct addinfo *hints,struct addrinfo **result);
hostname是需要进行地址解析的主机名称或者是二进制的地址串(IPV4的点分十进制或者Ipv6的十六进制数串),service则是一个服务名或者是一个十进制的端口号数串。其中hints是addfinfo结构,该结构定义如下:
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for nodename */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
hints参数可以是一个空置针,也可以是一个指向某个addrinfo结构的指针,调用者在该结构中填入关于期望返回的信息类型的暗示,这些暗示将控制内部的转换细节。比如,如果指定的服务器既支持TCP,也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置为SOCK_DGRAM,使得返回的仅仅是适用于数据报套接口的信息。
hints结构中调用者可以设置的成员包括ai_flags,ai_family,ai_socktype和ai_protocol。
其中,ai_flags成员可用的标志值及含义如下:
标志名称 标志含义
AI_PASSIVE 套接口将用于被动打开
AI_CANONNAME 告知getaddrinfo函数返回主机的规范名称
AI_NUMERICHOST 防止任何类型的名字到地址的映射;hostname必须是一个地址串
AI_NUMERICSERV 防止任何类型的名字到服务的映射,service参数必须是一个十进制端口号数串
AI_V4MAPPED 如果同时指定ai_family成员的值为AF_INET6和AF_INET,那么如果没有可用的AAAA记录就返回与A记录对应得Ipv4映射的IPV6地址
AI_ALL 如果同时指定AI_V4MAPPED标志,那么除了返回与AAAA对应得IPV6地址之外,还会返回与A记录对应的IPV4映射的Ipv6地址。
AI_ADDRCONFIG 按照所在主机的配置选择返回的地址类型,也就是只查找与所在主机回馈接口以外的网络接口配置的IP地址版本一直的地址。只有当本地系统中配置仅仅配置了IPV4地址才会将主机名称转换位IPV4地址;同样只有当本地系统中仅配置了IPV6地址的时候才会返回IPV6地址。Loopback地址并不在这种限制之中。
ai_family参数指定调用者期待返回的套接口地址结构的类型。它的值包括三种:AF_INET,AF_INET6和AF_UNSPEC。如果指定AF_INET,那么函数九不能返回任何IPV6相关的地址信息;如果仅指定了AF_INET6,则就不能返回任何IPV4地址信息。AF_UNSPEC则意味着函数返回的是适用于指定主机名和服务名且适合任何协议族的地址。如果某个主机既有AAAA记录(IPV6)地址,同时又有A记录(IPV4)地址,那么AAAA记录将作为sockaddr_in6结构返回,而A记录则作为sockaddr_in结构返回。
if(hostname == NULL) {
#ifdef AI_PASSIVE
hints.ai_flags |= AI_PASSIVE;
#endif
#ifdef OSF1
hostname = family == AF_INET6 ? "::" : "0.0.0.0";
servname = NULL;
#ifdef AI_NUMERICHOST
hints.ai_flags |= AI_NUMERICHOST;
#endif
#else
#ifdef _AIX
if (!port) {
servname = "1";
}
else
#endif /* _AIX */
servname = apr_itoa(p, port);
#endif /* OSF1 */
}
#ifdef HAVE_GAI_ADDRCONFIG
if (error == EAI_BADFLAGS && family == APR_UNSPEC) {
hints.ai_flags = 0;
error = getaddrinfo(hostname, servname, &hints, &ai_list);
}
#endif
if (error) {
#ifndef WIN32
if (error == EAI_SYSTEM) {
return errno;
}
else
#endif
{
#if defined(NEGATIVE_EAI)
error = -error;
#endif
return error + APR_OS_START_EAIERR;
}
}
9.1.3.2主机名获取
apr_sockaddr_info_get函数用以完成从主机名到网络地址的转换,而APR中提供的apr_getnameinfo则可以实现从网络地址到主机名的转换,该函数定义如下:
APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, apr_sockaddr_t *sa, apr_int32_t flags);
参数sa指定需要转换的网络地址,转换后的主机名由hostname返回。fags是标志位,用以控制内部的转换过程。
{
#if defined(HAVE_GETNAMEINFO)
int rc;
#if defined(NI_MAXHOST)
char tmphostname[NI_MAXHOST];
#else
char tmphostname[256];
#endif
SET_H_ERRNO(0);
#if APR_HAVE_IPV6
if (sockaddr->family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) {
struct sockaddr_in tmpsa;
tmpsa.sin_family = AF_INET;
tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];
#ifdef SIN6_LEN
tmpsa.sin_len = sizeof(tmpsa);
#endif
rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
tmphostname, sizeof(tmphostname), NULL, 0,
flags != 0 ? flags : NI_NAMEREQD);
}
else
#endif
#endif
rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
tmphostname, sizeof(tmphostname), NULL, 0,
flags != 0 ? flags : NI_NAMEREQD);
在函数的内部实现从地址到主机名称的解析是由函数getnameinfo完成的,该函数是getaddrinfo的互补函数,它以一个套接口地址为参数,返回描述其中的主机的一个字符串和描述其中的服务的另一个字符串。另外该函数以协议无关的方式提供这些信息,调用者必须关心存放在套接口地址结构中的协议地址的类型,这些由函数自行处理。
需要转换的地址到底是IPv4还是IPv6,这由地址结构中的family参数决定。尽管理想中的做法是将apr_getnameinfo()中的参数直接传递给getnameinfo()函数,但是在一些平台上还是会出现一些问题。
MacOS X Panther has a lousy getnameinfo() implementation that doesn't fill the buffer when no DNS entry is found for a host and a numerical result wasn't explicitely asked. As a result, Pure-FTPd didn't even start on Panther (saying "bad IP address") . We now check for EAI_NONAME if available and we retry with NI_NUMERICHOST if this is what getnameinfo() returns. Thanks to Yann Bizeul for his valuable help on this issue. Will research it more and see if I can come up with a patch (I am NOT good at C!)
在一些操作系统中,比如老版本的Mac OS X,如果Ipv6地址是由Ipv4地址映射的结果,那么该地址在传递给getnameinfo函数的时候将会产生错误,这是系统本身实现的BUG。因此对于这种情况,解决的方法就是将这种Ipv6地址重新转换为Ipv4地址。Ipv6地址是否是由Ipv4地址进行映射而成,通过宏IN6_IS_ADDR_V4MAPPED可以实现检测。IPV4到IPV6地址的映射可以用下图描述:
Ipv4地址通过在其十六进制前面添加前导零的方式映射为IPV6地址。反之如果一个IPV6地址是由IPV4地址映射而成,则只要剔除前面的前导零即可,剔除后的地址通常为((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];一旦获取了实际的IPV4地址,则可以将其传递给getnameinfo函数。
对于其余的IP地址,包括普通的Ipv4地址,非Ipv4映射的Ipv6地址,由于不存在BUG,因此可以直接调用getnameinfo。
getnameinfo函数原型如下:
Int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flag);
函数的前面几个参数都非常容易理解,只有最后一个参数flag,它用于控制getnameinfo的操作,它允许的值如下面所列:
NI_DGRAM
当知道处理的是数据报套接口的时候,调用者应该设置NI_DGRAM标志,因为在套接口地址结构中给出的仅仅是IP地址和端口号,getnameinfo无法就此确定所用协议是TCP还是UDP。比如端口514,在TCP端口上提供rsh服务,而在UDP端口上则提供syslog服务。
NI_NOFQDN
该标志导致返回的主机名称被截去第一个点号之后的内容。比如假设套接口结构中的IP地址为912.168.42.2,那么不设置该标志返回的主机名为aix.unpbook.com,那么如果设置了该标志后返回的主机名则为aix。
NI_NUMERICHOST,NI_NUMERICSERV,NI_NUMERICSCOPE
该标志通知getnameinfo不要调用DNS,而是以数值表达格式作为字符串返回IP地址;类似的,NI_NUMERICSERV标志指定以十进制数格式作为字符串返回端口号,以代替查找服务名;NI_NUMERICSCOPE则指定以数值格式作为字符串返回范围标识,以代替其名字
NI_NAMEREQD
该标志通知getnameinfo函数如果无法适用DNS反向解析出主机名,则直接返回一个错误。需要把客户的IP地址映射成主机名的那些服务器可以使用该特性。
如果flag没有指定,即为零,那么NI_NAMEREQD将是Apache中默认的标志项,如果不设置该标志,那么在反向解析失败的时候getnameinfo将返回一个数值地址字符串,显然这并不是Apache所需要的结果。
if (rc != 0) {
*hostname = NULL;
#ifndef WIN32
if (rc == EAI_SYSTEM) {
if (h_errno) { /* for broken implementations which set h_errno */
return h_errno + APR_OS_START_SYSERR;
}
else { /* "normal" case */
return errno + APR_OS_START_SYSERR;
}
}
else
#endif
{
#if defined(NEGATIVE_EAI)
if (rc < 0) rc = -rc;w
#endif
return rc + APR_OS_START_EAIERR; /* return the EAI_ error */
}
}
*hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, tmphostname);
return APR_SUCCESS;
上面的代码是对getnameinfo发生错误时候的处理(rc==0意味着成功,否则意味着转换失败)。此时将需要返回的主机名称设置为NULL。当getnameinfo发生错误的时候通常会返回EAI_XXXX的错误码,在所有这些错误码中比较特殊的就是EAI_SYSTEM,它意味着同时在errno变量中有系统错误返回,而其余的EAI_XXXX错误并不会设置errno变量。
对于非EAI_SYSTEM错误码,APR并不能直接返回。正如第一章所说,APR中对于apr_status_t返回码有自己的布局和规则,因此这些错误码必须转换至APR返回码。EAI_XXXX错误码的起始偏移是APR_OS_START_EAIERR,因此返回值实际上是rc+APR_OS_START_EAIERR。不过在一些平台上比如glibc,为了防止和h_errno的值冲突,系统将使用EAI_XXXX的负值, 这正是上面的代码w的原因。
上面的代码有一个假设前提,就是系统中必须提供getnameinfo()函数。但是由于getnameinfo()是比较新的一个函数,并不是每个操作系统平台都支持该函数。目前大部分Ipv4平台上不过都提供了gethostbyaddr()函数,通过该函数也能完成从主机地址到主机名称的转换,不过该函数仅仅支持Ipv4协议,不支持Ipv6协议。具体的代码如下所示:
#else
#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \
defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)
#ifdef GETHOSTBYNAME_R_HOSTENT_DATA
struct hostent_data hd;
#else
char tmp[GETHOSTBYNAME_BUFLEN];
#endif
int hosterror;
struct hostent hs, *hptr;
#if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
/* AIX, HP/UX, D/UX et alia */
gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, u
sizeof(struct in_addr), AF_INET, &hs, &hd);
hptr = &hs;
#else
#if defined(GETHOSTBYNAME_R_GLIBC2)
/* Linux glibc2+ */
gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, v
sizeof(struct in_addr), AF_INET,
&hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);
#else
/* Solaris, Irix et alia */
hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, w
sizeof(struct in_addr), AF_INET,
&hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);
#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
if (!hptr) {
*hostname = NULL;
return hosterror + APR_OS_START_SYSERR;
}
#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
#else
struct hostent *hptr;
hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, x
sizeof(struct in_addr), AF_INET);
#endif
if (hptr) {
*hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name);
return APR_SUCCESS;
}
*hostname = NULL;
#if defined(WIN32)
return apr_get_netos_error();
#elif defined(OS2)
return h_errno;
#else
return h_errno + APR_OS_START_SYSERR;
#endif
#endif
函数中众多的预定义让人眼花缭乱。不过最主要的预定义处理还在于对gethostbyaddr()函数的调用。从上面的代码中可以看出,gethostbyaddr有一个函数变形gethostbyaddr_r,而且不同平台下的gethostbyaddr_t函数的参数也不相同,要了解详细的原因,必须了解一些函数可重入的概念。
所谓可重入函数是指一个可以被多个任务调用的函数,任务在调用时候不必担心数据会出错;通常情况下下面的函数是不可重入的:
(1)、函数体内使用了静态的数据结构;
(2)、函数体内调用了malloc()或者free()函数;
(3)、函数体内调用了标准I/O函数。
通常情况下,在一个UNIX进程中发生重入问题的条件是:从主程序中和某个信号处理函数中同时调用某个不可重入函数.。另外在多线程应用中也会出现函数重入的问题。不幸的是由于历史的原因,我们经常使用的gethostbyaddr也是一个不可重入的函数,因为它们都返回指向同一个静态结构的指针。关于gethostbyaddr的重入问题,《Unix网络编程 第一卷:套接口API》中文版第二版的第207页中有一段描述,摘抄如下:
不幸的是,重入问题比他表面看起来更要严重。首先,关于gethostbyname和gethostbyaddr的重入问题无标准可循。POSIX规范声明这两个函数不必是可重入的。Unix98只说这两个函数必须是线程安全的。
其次,关于_r函数也没有标准可循。Solaris 2.X,Digital Unix 4.0和HP-UX 10.30都提供了可重入版本的gethostbyaddr_r函数,不过它们的参数并不相同,不同版本的gethostbyaddr_r函数原型如下表所示:
操作系统平台 函数原型
solaris struct hostent* gethostbyaddr_r(const char *addr, int len, int type,
struct hostent *result, char *buf, int buflen, int * h_errnop);
AIX,HP-UX,Digital Unix int gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result,
struct hostent_data *buffer);
Linux glibc2+ int gethostbyaddr_r(const char *addr,int len, int type,struct hostent *result,
char* buf, int buflen, struct hostent *hs, int* h_errnop);
大部分gethostbyaddr_r函数的前四个参数都相同,第一个是需要转换的地址;第二个地址的字节大小,用sizeof(struct in_addr)表示;第三个是需要转换地址的协议族,或者是AF_INET,或者是AF_INET6;第四个则是描述主机的hostent结构。区别通常在后几个参数:
对于Solaris,Irix等操作系统而言,后面还需要三个额外的参数,buf是由调用者分配的并且大小为buflen的缓冲区,该缓冲区用于存放规范主机名称,别名指针数组,各个别名字符串,地址指针数组以及各个实际地址。如果初出错,错误码通过h_errnop指针返回,注意不是我们通常所说的h_errno返回。
对于AIX,HP-UX,Digital Unix等平台而言,后面的三个参数则被组合为一个新的数据结构hostent_data,指向该结构的指针构成本函数的第三个和最后一个参数。Apache中默认的缓冲区大小为GETHOSTBYNAME_BUFLEN,即512字节。
对于Linux glibc2+而言,gethostbyaddr_r的参数与前两者又存在一定的差异,它共计有八个参数,与Solaris平台相比多了struct hostent* hs参数。
如果操作系统平台不支持可重入的gethostaddr_r函数,那么只能使用不可重入的gethostbyaddr函数,如x所示。
返回的主机名称保存在hostent结构中,如果查询成功,从hostname参数中返回即可。
9.1.3.3 IP地址解析
APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr,
char **scope_id,
apr_port_t *port,
const char *str,
apr_pool_t *p);
9.1.3.4 子网掩码
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish1234 at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=785671
| 引用(0)
MapReduce是Google开发的C++编程工具,用于大规模数据集(大于1TB)的并行运算。我关注MapReduce已经很久了,前些日子开始翻译Wikipedia上面的介绍文章,但是由于忙于其他的事务,直到今天才彻底翻译完成,更新了中文维基后,发在自己的Blog上,一方面多一个备份,另一方面方便不能访问维基的朋友查看,再有就是本人翻译水平和技术功底都不够,把译文和原文放在这里,有什么谬误请大家帮助更新维基上面的文章,不能访问维基的留言告知,我会尽快地更新,以免错误的理解和词语应用给大家带来误导。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
2004年6月,微软公司制定了一项“EULA”(End User License Agreement,即“最终用户许可协议”)法律文本。“EULA”是一种具有法律效力的协议(合约),用以规范(协调)微软公司与微软公司相应软件产品的最终用户之间的法律关系。简单说来,你(指软件产品用户)如果同意“EULA”条款的内容,那么,你就有安装软件、拷贝软件和其他使用该软件(比如运行软件)的相关权利;否则,也就是说,你如果不同意“EULA”条款的内容,你就没有上述相关权利。很清楚,“EULA”是微软公司和它的最终用户之间的一项“合约”(即双方一致同意的“合同”)。在“EULA”法律条款中,“EU”(最终用户)两个字母很重要。为什么说“EU”这个法律主体很重要呢?比如,有一位客户,高高兴兴地购买了一台“联想电脑”带回家。回家后,他发现电脑里面预装了“正版Windows”操作系统。这时,他该怎么办呢?此时,他已经是联想的客户,但是,他是不是就“自然成为”微软的“最终用户”了呢?答案是,不一定。因为,他必须面对这个“EULA”条款,毕竟这是他与微软公司之间的一项“合约”。这里的问题是,这位客户在购买这台“联想电脑”时,联想的微软代理人是不是明确向他交代了,“EULA”指的是什么,他自己是否表示了愿意接受这个“EULA”的全部条款。这位客户如果同意“EULA”,就把这台电脑买回去,否则,就别买。联想公司不能以微软Windows操作系统,家喻户晓,无人不知,从而推卸向客户明确交代“EULA”的责任。今年4月份,4部位有关“预装正版操作系统”文件,并没有指明一定要我国广大用户遵守“EULA”,预装正版Windows操作系统。预装什么,那是企业行为。联想公司有责任向广大客户解释“EULA”,给客户一个选择的机会,最终选择权当然应当在客户手中。
6月8日,微软公司的WGA程序每天向微软总部打“小报告”一事得以披露,突现了“EULA”的重要性。因为,WGA计划就是根据“EULA”才实施的,因此,WGA程序打“小报告”也应当算是正常的,只不过微软因为“疏忽”而事先没有向用户交代清楚罢了。因为,在“EULA”的2.3条款中,明确写明“你承认并且同意微软公司可以自动检查(你所运行的软件版本)”的字样。接受Windows,就必须接受EULA,就必须接受WGA程序的怪异行为。中国广大用户购置电脑处于如何选择的“两难”之中。
“EULA”的要点是:微软的软件产品不是卖的,而只是许可使用;软件的所有权完全由微软保留;软件的用户只是“租用”而已,因此,用户必须遵守微软的使用规矩。微软有权检查和自动处置任何涉及微软的伪造(假冒)软件与盗版软件。在“EULA”条款中,微软处于主动地位,用户处于被动地位。购买微软产品,必须懂得EULA条款。预装Windows,不管三七二十一,统统推销到用户手中,就等于强制广大用户遵守EULA。遵守EULA,有人觉得很舒服,但是也有人感到很别扭,甚至反感、愤怒。
下面,我把微软的“EULA”全名写出来,以便大家搜索查找。“EULA”出自“Microsoft Windows XP Home Edition(Retail) End-User License Agreement For Microsoft Software June 1, 2004”。微软是商人,做事守规矩,EULA条款写的明明白白,一目了然。
在现实生活中,也许真是“难得糊涂”。有人认为:你别说什么是“EULA”,谁会对它当真?实际上,当真的就是微软。它是微软的法宝。
袁萌 6月11日下午
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=788616
6月8日,微软公司的WGA程序每天向微软总部打“小报告”一事得以披露,突现了“EULA”的重要性。因为,WGA计划就是根据“EULA”才实施的,因此,WGA程序打“小报告”也应当算是正常的,只不过微软因为“疏忽”而事先没有向用户交代清楚罢了。因为,在“EULA”的2.3条款中,明确写明“你承认并且同意微软公司可以自动检查(你所运行的软件版本)”的字样。接受Windows,就必须接受EULA,就必须接受WGA程序的怪异行为。中国广大用户购置电脑处于如何选择的“两难”之中。
“EULA”的要点是:微软的软件产品不是卖的,而只是许可使用;软件的所有权完全由微软保留;软件的用户只是“租用”而已,因此,用户必须遵守微软的使用规矩。微软有权检查和自动处置任何涉及微软的伪造(假冒)软件与盗版软件。在“EULA”条款中,微软处于主动地位,用户处于被动地位。购买微软产品,必须懂得EULA条款。预装Windows,不管三七二十一,统统推销到用户手中,就等于强制广大用户遵守EULA。遵守EULA,有人觉得很舒服,但是也有人感到很别扭,甚至反感、愤怒。
下面,我把微软的“EULA”全名写出来,以便大家搜索查找。“EULA”出自“Microsoft Windows XP Home Edition(Retail) End-User License Agreement For Microsoft Software June 1, 2004”。微软是商人,做事守规矩,EULA条款写的明明白白,一目了然。
在现实生活中,也许真是“难得糊涂”。有人认为:你别说什么是“EULA”,谁会对它当真?实际上,当真的就是微软。它是微软的法宝。
袁萌 6月11日下午
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=788616
| 引用(0)
Borland产品专家榜
专家评委:李维(台湾),张小龙,左轻侯
Delphi产品专家榜
姓名 网名 说明
吴剑明 foxnt CSDN Delphi版主
吴发东 windindance CSDN Delphi版主
周蔚 ehom CSDN Delphi版主
陈刚 cg1120 CSDN Delphi积分前五名
陈江勇 Chechy CSDN Delphi积分前五名
王集鹄 zswang CSDN Delphi积分前五名
苏少岩 sysu CSDN Delphi积分前五名
李国新 cobi CSDN Delphi积分前五名
陈省 hubdog 《Delphi深度探索》作者
乔林 十一少 《参透Delphi/Kylix》作者
刘艺 newdream 《Delphi第三方控件使用大全》《Delphi第三方控件使用大全》作者
王寒松 坏人 报表控件Ereport的作者
李颖 李颖 数据库备份控件DBBackup的作者
夏昕 Nuke 共享软件Fatansia的作者
蒋靖 茶叶蛋 Delphibbs资深成员
王凯 cAkk Delphibbs资深成员
王玮 温柔一刀 Delphibbs资深成员
彭宇滨 Pipi Delphibbs资深成员
石玉琢 yzhshi Delphibbs资深成员
张智明 程云 Delphibbs资深成员
滕延年 卷起千堆雪tyn Delphibbs资深成员
申旻 Nicrosoft 《Delphi高手突破》作者
韩磊 grhunter 中文开发在线( http://www.CoDelphi.com )创办者
周爱民 aimingoo Delphibbs资深成员
周劲羽 与月共舞(yygw) CnPack(关于Delphi/C++Builder的控件) 项目发起人及现任开发组管理员
C++Builder产品专家榜
姓名 网名 说明
任颂华 TR@SOE CSDN C++Builder版主
孙春阳 Wingsun CSDN C++Builder版主
季世平 jishiping CSDN C++Builder版主
陈彬 Kingcaiyao CSDN C++Builder专家
赵勤忠 invalid CSDN C++Builder专家
张谦 Libran CSDN C++Builder 专家
宋红涛 songhtao CSDN C++Builder 专家
周思远 Sachow Delphibbs C++Builder专家
王旭东 wangxd(东东) Delphibbs C++Builder专家
陈锡震 chenxz Delphibbs C++Builder专家
黄卫国 forgot2002 Delphibbs C++Builder专家
王曦 小懒虫虫 “水木清华”C++版主
JBuilder产品专家榜
姓名 网名 说明
曹晓钢 曹晓钢 www.redsaga.com 创办者《深入Java虚拟机》译者
李风欣 feelyou 非鱼 JavaUnion.org论坛版主
丁令 令少爷 计算机世界开发者俱乐部的JAVA程序设计版面担任版主
田郁 tianyu 《J2EE clustering》1 2 3等文章作者
金化年 jhn 为Arkee.org站长之一
论坛特殊贡献奖
为大富翁论坛的建设和维护默默奉献的爱好者
做为一个非商业论坛,大富翁从1998年成立以来,吸引了众多的Borland爱好者,成为Borland爱好者学习的乐园,而这均源于很多很多为论坛的建设和维护默默奉献的“雷锋”。
姓名 网名 说明
王甲春 wjiachun 王昊 Soul
常文远 Wint
利志武 luyear
唐一丁 房客
周爱民 aimingoo
千中元 千中元
| 引用(0)
其实对于操作系统来说,未必一定要自己写出来什么代码
作为共享的社会思想,如果别人做的更好
为什么我们不采纳呢
只是国家的投资有点盲目了
明显没有必要作为863计划来作嘛
难道不是嘛?
有必要投资那么多嘛?
明显会得到这个结局的。
只能说无知,国家的悲哀。
2006.06.10 来自:中国经营报 窦毅
就在国家863重点科研项目麒麟操作系统软件被指涉嫌抄袭后,近日又有不愿透露姓名的Linux专家告诉记者:“至今国际正式发布的Linux内核文件中,尚没有中国人开发的一行代码。”这一情况,得到了国内Linux产业力促者、中国工程院院士倪光南先生的认同。
而与此形成鲜明对照的是,红帽、甲骨文、Novell、惠普、IBM、英特尔等美资商业公司大量技术被Linux内核小组接纳。美国《商业周刊》报道,这些公司已经占据了90%的Linux内核贡献者席位。
尽管未能进入系统内核开发,并不意味着不能享用内核技术,但技术空心化争论正在中国Linux产业圈内弥散。不深入“内核”工作的国产Linux企业前景堪忧。
7年投资无一行内核代码
记者调查发现,截止到目前,在国际上参与过Linux内核程序实际开发工作的中国人只有一度被称为中国Linux之父的龚敏一人。“但龚敏所开发了约3000多行Linux代码,最终并没有被采用。”据上述Linux专家透露,“随着龚敏先生回到国内,他在Linux内核的开发工作也退出了。”
另外,中科院计算所Linux安全专家谢华刚曾经因一项安全检测技术有望成为Linux内核开发成员,但最终也没有被接纳。
1999年中科院联合上海市政府、信息产业部筹备组建红旗Linux项目为始,中国扶持Linux至今已7年光阴。CSDN中国软件开发网邹震告诉记者:“这些年来,国内Linux企业所做的大部分集中在汉化和一些简单外围应用开发上。”
麒麟涉嫌抄袭事件揭发者、澳大利亚中国留学生Dancefire(网名)颇具火药味地批评:“国内Linux产品基本上是抄来抄去,和美国红帽公司相比,没有多少创新,这可能会给产业发展埋下很大危机。”
面对这样的声音,倪光南院士依旧保持了相当积极的观点,但无法掩饰目前国产Linux空心化的现状。倪院士认为:这只是暂时现象,情况正在发生变化。中国企业和个人对于Linux内核的贡献将随着Linux在中国的推广而与日俱增。他介绍说:浙大网新网络研发中心主任、中国Linux专家毛德操先生提出的“兼容内核”计划,旨在改造Linux内核,使其能兼容Windows应用软件。如果毛德操先生研究成功被Linux采纳,那他将成为国内第一位真正进入全球开源技术核心圈的华人。
“事实上毛先生还没有做到,国产Linux企业这种技术状态应该反思。”一位中国Linux企业高层感慨道,“中国不具备对Linux内核技术的掌控能力,寄望一个全部由外人主导开发的操作系统来改变本国的产业面目,是否现实?”
巨额财政投入打水漂?
作为一个被国家视为战略性的项目,投资产出比是否划算?由于投入的形式复杂,涉及部门和项目很多,7年来中国政府到底向Linux投了多少钱难以统计。
倪光南院士认为:中国每年实际投入到Linux方面的钱都有几亿元人民币规模。
据记者统计,1999年中科院筹建中科红旗,联合了上海市政府和信产部入股。后来,上海市政府和信产部又分别投资入股了拓林思中国和中标软件。与此同时,北京市科委也投资组建了共创开源公司,后又入股南京新华。
由中科院、上海市政府、信产部、北京市科委四家政府机构投资的5个Linux,每项投资都不低于几千万元规模。根据《中国软件与技术服务股份有限公司2004年年度报告》显示,中标软件累计现金投资已达到6482.9万元。
这些公司成立后,发展过程中还不断从国家得到各种各样的项目支持基金。以共创开源为例,股东结构几次变革,每轮重组均有新的财政性资金投入。
更多的间接投资还包括为了推动Linux开源产业发展,国内给几家企业提供便宜地皮、税收优惠等多个方面。
大笔科研资金真正流向了何处?大量投资与大力扶持之后,中国Linux等开源软件获得了什么成就?
4月份Dancefire撰文《麒麟操作系统内核与FreeBSD5.3内核的相似性达到了99.45%》披露由国防科技大学、中软公司、联想公司、浪潮公司和民族恒星公司五家单位合作研制的开源服务器操作系统——麒麟存在严重抄袭行为。作为投资7000万元的国家“863”软件重大专项研发成果,难道结果换回来的只是一个基于公版开源内核的“抄袭产品”吗?此事立刻在国内软件领域引起轩然大波。
麒麟事件,揭开了中国开源软件投资问题的一角,国内开始对国产开源产品产生了众多质疑。
但倪光南也认为:“与微软每年在Windows上投入几十亿美元相比,我们的软件人员做到这步已经很优秀了。”是否还要继续加大投资,这可能还是个未知数。
商业垄断环境难破
Linux被寄予厚望打破国际巨头对IT产业垄断的目标,至今还看不到前景。Linux开源反而成为垄断性巨头谋求产业转型的手段。赛迪顾问分析师钱磊博士告诉记者:“开源更大的意义在于改变过去旧有的软件交付模式,即一手交钱一手拿光盘,转变从为客户服务中挣钱的模式。”
这是否是对多年来千辛万苦尝试出来的开源软件的商业化模式的 一种讽刺?由于未来软件的主要赢利手段不是靠买授权了,所以最后的胜利者跑不出那些IT服务能力极强的企业。
而众多的Linux系统企业将只会以IT服务商的附庸存在。Novell在美国的再度崛起已经显示出IBM在Linux开源领域的绝对领导地位。原本IBM只支持红帽,但红帽做大以后不甘心跟随,IBM为了压制红帽,暗中支持Novell收购欧洲Linux企业SuSE,成为红帽之后的第二大Linux厂商。Linux的命运并不掌握在红帽、Novell这样的Linux系统企业手中。
不久前,红帽收购Jboss获得开放的中间件系统,意图将自己在操作系统上的实力向更接近“应用”的层面发展。直接后果,长期以来的合作伙伴甲骨文突然宣布谋划收购Novell的Linux业务,集成入自己的产品方案中——向红帽关闭了大门。
不光IBM、Oracle、Sun等企业正在主导开源,就连Linux最直接的竞争者——微软公司也在开源领域有所布局。微软已经向部分国家开发了很少一部分源代码,此外近来频繁赞助Linux。据外电报道,微软在最新版Windows中使用了一项开源的安全技术,这是否代表微软也将成为未来开源市场最大收获者呢?
| 引用(0)
我得点评:
记者有点太垃圾了,一点不动的这个行业,问的问题我想马大哥都觉得恶心了,微软?他们有什么共同的交叉电吗?
MSN??
可笑。
一切为了扩张
记者:现在的QQ像是一只肆意扩张的肥企鹅,从短信、网络硬盘、网络游戏到门户新闻,QQ急速扩张。有人认为,这是腾讯出于对抗MSN和Google这样的企业入侵。
马化腾:不仅微软、Google,包括国内的很多互联网企业,大家其实都在往一个方向走,向互联网相关多元化方向发展。最初,大家切入点不同。新浪、搜狐从新闻媒体切入,不断走入相关多元化市场;网易以免费电子邮件起家,再切入媒体、网游等相关多元化领域;而QQ是从聊天工具,逐步到门户网站、互动娱乐、拍卖网站等。
选择相关多元化发展和中国网络环境有关。目前国内互联网的赢利手段只有几种:一种媒体类,靠内容和新闻吸引浏览量来赚广告商的钱;第二种是增值服务收费模式,进行互动娱乐、手机短信等服务,依靠发售点卡和电信分成获利;第三种是商务类,提供一种平台,帮用户间进行撮合,最终达成交易,如订票、找工作、房地产等类型网站靠挣取中间佣金。
这些是收费模式,而电子邮件和即时通讯、网络游戏等等都是手段。为了增加收入大家不可能只依赖一种手段去响应所有的商业模式。也正是这样,你看到了QQ的扩张。
记者:相对于目前中国网民的需求来说,互联网公司所创造的服务形式还太少,但现在从业者们不把最大精力放在创新上,而是更多去抄袭扩张。这是否是中国互联网现阶段的一种悲哀呢?
马化腾:互联网在中国还处于发展初期,“中国”概念在国际资本市场上还是比较火的,大量资金进入中国市场。从整个互联网的资金容量看,供应大于需求,这造成了大部分公司具有相对多的资金来进入不同领域发展,包括一些并不能实现直接赢利,但能粘住用户的应用上,如即时通讯、电子邮件、网络硬盘存储等领域。而另一方面,中国银行业信用卡发展不能与需求相匹配,直接实现电子支付较困难,反而借助点卡、电信分成等间接收费。两方面夹击下,造成了今天中国互联网公司业务模式必然出现服务同质化。这不是悲哀,而是现实商业所逼。
对抗是必然
记者:我和腾讯的员工交流时,他们认为,目前在互联网行业即时通讯是竞争最激烈的市场,而且QQ面对来自微软MSN的竞争压力很大。
马化腾:从通讯市场来看,我们目前最大的竞争对手确实是微软的MSN。即时通讯市场是目前我见过的互联网应用最激烈竞争的市场,大大小小算起来超过40家。这个行业,市场技术门槛不是很高,但是易学难精。即时通讯价值在它的用户群越大,产业价值才越大。所以要有一定的先发优势。
与微软竞争,我们是特色优势。与MSN相比,QQ的用户群定位更偏重于中国本地化、年龄较轻的用户,这类人群具有一个特点,愿意去结交一些陌生用户群体。而MSN和E-mail结合紧密,这类用户的需求是与熟人交流。QQ也是努力地往上渗透,MSN也往下,坦率地讲在这一领域有很大竞争,但这两块市场留给其他竞争对手的空间并不是很大。
现在其他竞争企业推出的很多即时通讯工具都有各自的特点,像泡泡,它会以一种更加娱乐化的新功能,甚至会比MSN更加白领、小资化的功能来出现。
记者:MSN进入中国后,抢了QQ的很多用户,这一点你承认吗?
马化腾:我觉得应该是说他开发了很多新用户。此外有一部分高端用户会同时使用这两种软件,但并不是说,他就不用QQ的服务了。我见过很多朋友,上班用MSN,下班还是用QQ,因为上面很多应用不能丢掉,他以前一些同学都在上面。
记者:但毕竟MSN还是抢占了一些市场,譬如说上班族市场。
马化腾:对,但本来那端我们就比较弱。这端本来我们就没有拿下来,MSN自己开发最终拿下来了。
记者:这样对腾讯有很大的威胁,很多人觉得腾讯的核心竞争力在于市场占有率,而现在MSN在逐渐蚕食你的市场。
马化腾:应该说核心竞争力是即时通讯的用户区和社区,而不是简单的占有率。因为别人可以通过一种手段开发一片新市场,把你的占有率弄低。但是我相信,随着蛋糕的做大,我们也可以从原有的用户群渗透进别人的用户群,从而使自己的市场不断增大,从这一点看,未尝不是件好事。
占有率并不重要
记者:还是有人认为你和微软的竞争会相当激烈。这和目前网络热门的新概念Web2.0有关。Web2.0需要提供很多定制化的服务,所以在技术上,很多公司提供了自己的客户端产品,这样个性化定制除了可以在网络服务器上完成,有相当一部分设置在客户端软件完成,这就造成了产业界开始了一种相当宏伟的目标,由于桌面客户端功能不断膨胀,这样就可以取代以前桌面端很多微软的产品功能,进一步发展,如果这些企业再去开发LINUX操作系统,就能最终将自己树立成另一个“新微软”。腾讯也是以客户端起家的企业,因此大家都非常关心,你们是不是也在按照这样的思路去做?
马化腾:只能说手段都是客户端,但是实际上说Google和MSN两者的竞争更加贴切一点儿,但他们没有提Web 2.0这些说法,他们提出的主要是DESKTOP(桌面)竞争,就是说,通过用户在Windows桌面上的一些客户端软件的服务、安装,包括以后的升级,能够让客户端的元素、网络,更加融为一体,就更希望把单一的PC上的操作系统,和整个互联网融合起来成为一个大型的网络操作系统。用户今后使用起来,分不清是在用一个本地的软件还是在用一个网上的服务。
也许你以后写一个文档,进行字处理,进行一些绘图等工作时,你都分不出,这是一个软件还是一个网站上的服务。
微软最早提出的NET就是这一思路。思路大家都对,就是每个人都想自己建一套,你看Google现在做的就是自己建一套,他从DESKTOP开始,再进行整合其他服务,可能有朝一日,在桌面点一个软件,这个软件是直接去访问服务商的,而不是访问本地硬盘的,用户已经可以通过网上服务完成他在互联网所需要做的事情了。
这是一个大的方向,也是我们所讲的网络服务和本地服务的融合。
但是我觉得并不是非要这么做才能实行,我觉得很多服务用纯桌面和纯Web都有它的好处。我觉得只是会多元化,而不是说以后全部要升级过去。所以我看这个问题比较现实,而不是说那是潮流,我们一定要往那边走。
最后还要具体分析,看哪些情况真的是实用或是不实用。
记者:是否可以认为腾讯不会大规模去建立自己的网络系统?
马化腾:看具体的应用了,现在一些小的应用,包括像博客网和DONEWS都有了一些网摘,比如你看了一些文章,把它存下来,或者把自己本地的地址栏、通讯录等都同步起来,这样一些小的应用思想都可以借鉴,并应用到未来我们新的版本上。但并不是说一定要往这边走的趋势。我觉得还是要从用户的实际应用角度出发。
MSN在全球遇到的商业竞争就会发现这样的结论,互联网服务并不是一个技术和标准圈占市场的时候,而依然是新应用圈占市场,并不是占有了平台资源就能抓住客户的。MSN进来后,迅速打败了韩国原来最大的即时通讯企业,然而随即又被另一家韩国企业反扑。韩国电信服务商下属的赛我网,将门户和新的即时通讯,再集合赛我的社区服务,逐步从MSN手中又找回了市场份额。现在赛我在20到29岁这个年龄层上的市场占有率已经超过MSN。
赛我战胜微软靠的是什么?除了集成这些大同小异的服务外,结合社交软件、博客等几大核心。在全球目前只有赛我获得了成功,目前在我们的QQ里集成了很多赛我的思路。这也就是为什么即时通讯要不断向竞争对手学习,甚至不是我们的直接竞争对手,一些国外的企业模式,也要不断去学习。他们在对抗MSN方面有很多很好的经验。我们看到很多新功能,微软根本不理解,很多在美国并不流行,或者无市场的功能,却在亚洲市场相当的流行。有很多创新的应用,例如社交软件把人与人交往的六度空间等都集成在一起。通过朋友去找朋友,可以把这个概念融入网络服务中去。
中国互联网市场空白还很多,目前比的是创新而不是占有率。但不能异想天开,还没到缔造“新微软”帝国的时候,也不能妄自菲薄。
各有各的玩法
记者:你怎么去评价原来这个市场的领先者呢?原来韩国最大的即时通讯企业被MSN战胜,而在美国ICQ也已经被微软MSN挤到倒闭边缘。这是否也是腾讯的危机呢?早起步,并不一定能收获?
马化腾:要看怎么做,其实MSN也很早起步,1995年就开始有雏形,所以不是说MSN是后来者。而ICQ的今天和它过早卖给AOL有关系,即时通讯这个产业绝不是做一个单一产品卖给别人就可以了,这绝对是没有动力的,你必须不断求变,不断去改。不可能站在原有的市场上就可以不断地收获,这种想法不现实。包括我们也一样,中间走了很多弯路,中间有许多次转型,又增加许多新的功能。
记者:腾讯进入相关多元化服务,对员工的素质和管理要求有什么变化?从单一的技术型公司,涉足到内容领域,你的运营成本会剧烈增加,管理难度也加大了。
马化腾:刚进入互联网行业时,公司没有收入,如果支撑一个300人的内容团队来说,确实是一件非常困难的事,但随着公司进入盈利阶段,腾讯发展到今天,就不困难了。
最大的难度是如何管理这些不同的业务人员。要建立不同的管理方式去平衡公司的发展,像以前那种完全用相同的管理方式去管理公司已经不太现实了。譬如进军SP,拿互联网公司的管理方法去管理和发展SP,你会发现其实你打不过一些纯专业的SP。
他们聘请的很多都是高中生,最多是大专生去制造内容,月薪最多2000元,不行就换,它会很快地适应市场的反应。而在互联网公司拿八九千元,甚至一万元工资都是很正常的。
这是值得警惕的事情。
| 引用(0)
猛禽(整理)
Mental Studio
本来打算把这次的聊天内容整理成文章,但一不小心写得太长,还没写完,加之最近事多,一时半会还写不完。Delphi8又出来了,需要研究一下,所以暂时先把这个聊天记录贴出来将就一下吧。
Mental Studio
本来打算把这次的聊天内容整理成文章,但一不小心写得太长,还没写完,加之最近事多,一时半会还写不完。Delphi8又出来了,需要研究一下,所以暂时先把这个聊天记录贴出来将就一下吧。
[本站讯]2004年8月17日的美国加州圣巴巴拉,正在召开的国际密码学会议(Crypto’2004)安排了三场关于杂凑函数的特别报告。在国际著名密码学家Eli Biham和Antoine Joux相继做了对SHA-1的分析与给出SHA-0的一个碰撞之后,来自山东大学的王小云教授做了破译MD5、HAVAL-128、 MD4和RIPEMD算法的报告。在会场上,当她公布了MD系列算法的破解结果之后,报告被激动的掌声打断。王小云教授的报告轰动了全场,得到了与会专家的赞叹。报告结束时,与会者长时间热烈鼓掌,部分学者起立鼓掌致敬,这在密码学会议上是少见的盛况。王小云教授的报告缘何引起如此大的反响?因为她的研究成果作为密码学领域的重大发现宣告了固若金汤的世界通行密码标准MD5的堡垒轰然倒塌,引发了密码学界的轩然大波。会议总结报告这样写道:“我们该怎么办?MD5被重创了;它即将从应用中淘汰。SHA-1仍然活着,但也见到了它的末日。现在就得开始更换SHA-1了。”
http://bdn.borland.com/article/0,1410,32845,00.html
Abstract: All Borland C++Builder customers should read this open letter from Borland
Borland would like to take this opportunity to thank you for the long lasting support you have provided Borland and its C++Builder product line.
We recognize and appreciate the extensive developer base that relies on the VCL-based Borland C++Builder, and the many end user solutions that are deployed with C++Builder technology. We believe there is great value in moving both C++Builder and your existing investments forward.
Therefore, we are pleased to assure the community that Borland will continue to develop VCL-based C++. The next version of C++Builder will be part of the Delphi IDE family, enabling you to take advantage of the latest Delphi VCL and IDE framework and many of the new C++ features that you have requested. It is our intention to include this personality in or before the next major release of Delphi. We will be communicating additional details and timelines as they become available.
We are grateful to you for your commitment to Borland and specifically the C++Builder product line. We learn a great deal about your achievements through open dialogue, and we hope and intend that these lines of communication will remain open and active.
We ask you to continue providing us with your C++Builder feedback by emailing cppbuilder@borland.com, or by putting your requests in QualityCentral.
Best wishes for continued success in your software development.
Sincerely,
Borland Software Corporation
Abstract: All Borland C++Builder customers should read this open letter from Borland
Borland would like to take this opportunity to thank you for the long lasting support you have provided Borland and its C++Builder product line.
We recognize and appreciate the extensive developer base that relies on the VCL-based Borland C++Builder, and the many end user solutions that are deployed with C++Builder technology. We believe there is great value in moving both C++Builder and your existing investments forward.
Therefore, we are pleased to assure the community that Borland will continue to develop VCL-based C++. The next version of C++Builder will be part of the Delphi IDE family, enabling you to take advantage of the latest Delphi VCL and IDE framework and many of the new C++ features that you have requested. It is our intention to include this personality in or before the next major release of Delphi. We will be communicating additional details and timelines as they become available.
We are grateful to you for your commitment to Borland and specifically the C++Builder product line. We learn a great deal about your achievements through open dialogue, and we hope and intend that these lines of communication will remain open and active.
We ask you to continue providing us with your C++Builder feedback by emailing cppbuilder@borland.com, or by putting your requests in QualityCentral.
Best wishes for continued success in your software development.
Sincerely,
Borland Software Corporation
| 引用(0)
/*微软最高机密——Windows 98 源代码 项目:Chicago(tm) 项目发行日期:1998年夏天*/
Delphi 2006 !(Dexter)
隨著Dexter推出的日子逐漸接近,Dexter的Beta測試也進入了如火如荼的階段,目前Dexter的狀態是第4個Beta,我也好久沒有看到Borland的產品會有Beta 4了(Delphi 8/Delphi 2005是Beta 3之後便被下令推出),而且Dexter還有好幾個月的時間繼續進行穩定性,延展性以及效率的調整,這實在是令人高興,因為這代表Borland的高層現在腦筋終於清醒了,我不知道Dexter推出後在Marketing方面是不是可以掃除Delphi 8/Delphi2005負面的印象,但我知道如果Dexter依照目前的計劃發展下去,那麼我們終於將有一個很棒的產品了,OK,不多說 Politics方面的事以免我有麻煩,讓我們多談談Dexter技術以及產品本身的事好了。
隨著Dexter推出的日子逐漸接近,Dexter的Beta測試也進入了如火如荼的階段,目前Dexter的狀態是第4個Beta,我也好久沒有看到Borland的產品會有Beta 4了(Delphi 8/Delphi 2005是Beta 3之後便被下令推出),而且Dexter還有好幾個月的時間繼續進行穩定性,延展性以及效率的調整,這實在是令人高興,因為這代表Borland的高層現在腦筋終於清醒了,我不知道Dexter推出後在Marketing方面是不是可以掃除Delphi 8/Delphi2005負面的印象,但我知道如果Dexter依照目前的計劃發展下去,那麼我們終於將有一個很棒的產品了,OK,不多說 Politics方面的事以免我有麻煩,讓我們多談談Dexter技術以及產品本身的事好了。
Tags: c++builder10 | 引用(0)
今天有幸进入图书馆内部,看到了以前翻过的TCP/IP三卷,高兴之余,全部借来,还有一本服务器设计的书,因为看过原版的,才发现翻译是在太差了,唉,很失望,如果是我翻译,都会更好,可惜了一本好书。
等看完了,一定写一些总结。
还有借了世界当代史,世界近代史,最近不知道为什么,非常喜欢看历史,希望历史的那种变革,那些人物的失败或成功,为什么失败,为什么成功。
或许这是由技术转向管理的一个必然吧。
等看完了,一定写一些总结。
还有借了世界当代史,世界近代史,最近不知道为什么,非常喜欢看历史,希望历史的那种变革,那些人物的失败或成功,为什么失败,为什么成功。
或许这是由技术转向管理的一个必然吧。
| 引用(0)




2006/06/13
14:25
6945




