bt下载与小说520

bt下载与小说520

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  16 随笔 :: 0 文章 :: 6 评论 :: 0 Trackbacks

2008年10月1日 #

Mozilla Public License

MPL License,允许免费重发布、免费修改,但要求修改后的代码版权归软件的发起者。这种授权维护了商业软件的利益,,它要求基于这种软件得修改无偿贡献版权给该软件。这样,围绕该软件得所有代码得版权都集中在发起开发人得手中。但MPL是允许修改,无偿使用得。MPL软件对链接没有要求。

SD开源协议

BSD开源协议是一个给于使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。 当你发布使用了BSD协议的代码,或则以BSD协议代码为基础做二次开发自己的产品时,需要满足三个条件:

1. 如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的BSD协议。

2. 如果再发布的只是二进制类库/软件,则需要在类库/软件的文档和版权声明中包含原来代码中的BSD协议。

3. 不可以用开源代码的作者/机构名字和原来产品的名字做市场推广。

BSD代码鼓励代码共享,但需要尊重代码作者的著作权。BSD由于允许使用者修改和重新发布代码,也允许使用或在BSD代码上开发商业软件发布和销售,因此是对商业集成很友好的协议。而很多的公司企业在选用开源产品的时候都首选BSD协议,因为可以完全控制这些第三方的代码,在必要的时候可以修改或者二次开发。

Apache Licence 2.0

Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似,同样鼓励代码共享和尊重原作者的著作权,同样允许代码修改,再发布(作为开源或商业软件)。需要满足的条件:

1. 需要给代码的用户一份Apache Licence

2. 如果你修改了代码,需要再被修改的文件中说明。

3. 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议,商标,专利声明和其他原来作者规定需要包含的说明。

4. 如果再发布的产品中包含一个Notice文件,则在Notice文件中需要带有Apache Licence。你可以在Notice中增加自己的许可,但不可以表现为对Apache Licence构成更改。

Apache Licence也是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布/销售。

GPL

GPL许可证是自由软件的应用最广泛的软件许可证,人们可以修改程式的一个或几个副本或程式的任何部分,以此形成基於这些程式的衍生作品。必须在修改过的档案中附有明显的说明:您修改了此一档案及任何修改的日期。 您必须让您发布或出版的作品,包括本程式的全部或一部分,或内含本程式的全部或部分所衍生的作品,允许第三方在此许可证条款下使用,并且不得因为此项授权行为而收费。

LGPL

Linux就是采用了GPL。GPL协议和BSD, Apache Licence等鼓励代码重用的许可很不一样。GPL的出发点是代码的开源/免费使用和引用/修改/衍生代码的开源/免费使用,但不允许修改后和衍生的代码做为闭源的商业软件发布和销售。这也就是为什么我们能用免费的各种linux,包括商业公司的linux和linux上各种各样的由个人,组织,以及商业软件公司开发的免费软件了。

GPL协议的主要内容是只要在一个软件中使用(“使用”指类库引用,修改后的代码或者衍生代码)GPL协议的产品,则该软件产品必须也采用GPL协议,既必须也是开源和免费。这就是所谓的”传染性”。GPL协议的产品作为一个单独的产品使用没有任何问题,还可以享受免费的优势。

由于GPL严格要求使用了GPL类库的软件产品必须使用GPL协议,对于使用GPL协议的开源代码,商业软件或者对代码有保密要求的部门就不适合集成/采用作为类库和二次开发的基础。

其它细节如再发布的时候需要伴随GPL协议等和BSD/Apache等类似。

Public Domain

公共域授权。将软件授权为公共域,这些软件包没有授权协议,任何人都可以随意使用它。

Artistic许可

使作者保持对进一步开发的控制。

posted @ 2008-12-18 13:55 bt下载| 编辑 收藏

着第3届bt论坛的顺利结束的秋风,我也来分享一下自己在前端优化方面的一些些小经验,其实这些经验本身都是来自yahoo的优化原则,不过经过ahuaxuan自身的实践和再次的思考,把原来的原则都进行了分组和分析.不过由于ahuaxuan bt涉及到的东西有限,并没有经历过全部的优化点,所以只把自己做过的拿出来和大家讨论讨论,其中不免加入自己一些观点,希望大家指正.

先说说目标,前端优化的目标是什么,一个字:快.两个字:更快.那么下面我们来看看慢的网页将会给我们带来什么:
1. 慢的页面可能会网站失去更多的用户.

2. 慢500ms意味着20%的用户将放弃访问(google)

3. 慢100ms意味着1%的用户将放弃交易(amazon)

4. 慢 ???ms意味着??%的用户将放弃xx(your site)

所以我们的目标很明确,就是要网页展现的速度更快.
经过ahuaxuan的实践和总结,其实要让网页展现更快只需要注意几个大的方面,下面会一一描述这几个大的方面.


[size=medium]1减少http请求,我把它排在了第一点,为啥要在第一点呢,很简单,因为它最重要.



如何做呢.让ahuaxuan带着大家分析一下这个问题.从何处着手呢.ahuaxuan大声疾呼,我们要从数据开始.ok,一般来说,我们从变化性上把数据分成两种类型,变和不变.那么不变的数据可以缓存,变化的数据不能缓存,这是一个常识,也就是说要减少我们的http请求次数这个目标可以转换成把数据分为变化和不变化两个部分.不变化的数据不需要再次请求,这样http请求的次数就减少了,下面我们分点来描述将数据分类的途径.


1. 合并脚本文件
包括脚本,样式和图片,可以有选择的把一些Js和css可以合并成一个文件,一些图片可以使用css sprites技术.这样做的原因是什么?做过web开发的人都知道,js和css基本是不变的,是静态文件,图片亦然.那么不变的文件如果适当的合并在一起,会有什么效果呢?请求的次数从多次变成了一次.这样http请求的次数就减少了.当时合并之后,文件体积变大了,会影响速度吗?答:肯定会啊,不过这里是需要权衡的,比如我100份静态文件,合并成10份还是合并成1份这就得看你得具体情况了.

2. 指定Expires或者Cache-Control,
对于静态内容:设置文件头过期时间Expires的值为“Never expire”(永不过期)
动态页面,在代码中添加cache-control,表示多少时间之后过期,如:
response.setHeader("Cache-Control", "max-age=3600");
如果使用了Expires文件头,当页面内容改变时就必须改变内容的文件名。通常是在文件内容后加版本号
这一点是大多数人都忽略得,之前很多人在坛子上发布自己得小系统,还有demo,ahuaxuan跑过去一看,my god,一堆又一堆得js,css,既没有恰当得合并,也没有设置过期时间.每次刷新页面都要重新下载这一堆又一堆的js,css.http请求那叫一个多啊.无谓了流量就这样产生了.

这一点在企业应用的系统中也时有发生.比如我们使用extjs作为前端的技术,400多k啊,每打开一个页面都导入,下载这个js,够无聊的.那么童子们可能就要问了,静态文件为啥不用apache,lighttpd等呢,答,用了又怎么样,不设expire或者max-age不是一样要下载,最好的方法是写一个filter,再filter中判断,如果url满足一定的条件(比如符合配置文件中的正则表达式),那么就设置一个max-age,这样就ok,太简单了,几行代码就可以搞定.快哉.

3. 缓存Ajax请求
缓存的方法同动态页面,ajax请求需要使用get方式,url长度为2k(ie)限制(post请求有两个过程,1发送请求headers,2发送请求数据,根据http规范,get请求只会发送一个tcp包).--------这一段话来自yahoo,先不管其真假,我们从另外一个方面来考虑一下为什么最好使用get方式,讲一个ahuaxuan经历过的事情,之前有一个项目的ajax请求使用了post方式,后来发现经常出错,而且抛出了squid的错误,因为我们的网站使用了squid,问题就出在这里了,从http协议上可以了解到,method=post是指把数据提交到服务器上去,那么squid的一个特性是不会缓存post请求(事实上它确实不应该缓存,因为这样会违反http协议中的语义),把ajax请求改成get方式之后,一切恢复如常.

4. 移除重复的js
重复的js导入也有可能导致ie重新加载该脚本.没啥好说的,照做.

5. 避免重定向
有一种经常被网页开发者忽略却往往十分浪费响应时间的跳转现象。这种现象发生在当URL本该有斜杠(/)却被忽略掉时。这时候会返回一个301的状态码,然后浏览器重新发起一次请求.在企业应用里,重定向是我们在企业应用中常用的技术,不过用在网站项目上,您可要小心了,因为普通的重定向其实是server在response header中设置http status=302,浏览器收到之后,判断出是302,会重新发送一个请求,目标地址是前一次返回中指定的地址.在网站项目中如果可以不用重定向就别用吧.如果您做企业应用项目,ok,关系不大,您就放心的”定”吧.

小节,ahuaxuan把减少http请求次数分为了以上5个小点,每个小点之后附加一些实例,大家可以根据这些点来判断自己的项目是否可以有优化的地方.


使用cdn
让内容更靠近用户,这有啥好说呢,原理很简单,就是根据用户浏览器所在机器的ip来判断哪些服务器离用户最近,浏览器会再次去请求这些最近的机器.一般的cdn服务商是通过开发自己的dns server来达到这个目的的.不过这个是通常情况哦,技术实力比较高,或者场景比较特殊的公司会开发自己的cdn.当然不管怎么说,使用cdn肯定可以使页面响应更快(也包括音频,视频,图片,文本文件,等等等等)

减小返回数据的体积
1. 使用gzip压缩返回数据
Gzip压缩所有可能的文件类型是减少文件体积增加用户体验的简单方法。比如本来400k的文件,压缩一下之后只有50k-100k,那么网络的流量就立刻下来了,压缩的代价是服务器端要压缩文件,需要消耗cpu,浏览器需要解压文件,也需要消耗cpu,不过对于现代这么nb的pc,来说,浏览器解压一下数据带来的cpu消耗简直不值一提.所以您就压吧.不过压的时候要小心哦,有的浏览器在特定场景下会出去一些小bug,导致页面不正常.比如ie6在跨域的时候可能会有些小麻烦,把这部分数据的gzip去掉就可以了.

2. 最小化js文件和css文件
压缩js可以使用JSMin或者YUI Compressor,后者同时可以压缩css,这个也没啥好说的,照做吧.

3. 将css和js独立成外部文件
其实这一点也可以看成是区分不变数据和变化数据.很多人喜欢在页面商写很多很多的js和css,这些数据其实都是不会变化的数据,也就是说这些数据也是可以缓存在浏览器上的,通过把它们独立成外部文件,可以把这些数据缓存起来.这样做看上去是增加的请求的次数,但是由于第一次请求之后该部分数据已经被缓存,所以第二次就无需再请求后端,减少了网络带宽的开销.

优化Cookie

1. 减小cookie体积
能不放就别放吧,为啥呀,cookie就象钥匙串,只有出门和回家得时候才用,但是一整天你都要带在身上,麻烦不.
2. 合理设置Cookie域
由于二级域名可以拿到一级域名得cookie,那么如果,而二级域名之间确不能相互共享cookie,所以合理得设置cookie得域名也可以避免无必要得带宽浪费和响应速度得增加.
3. 设置合理的cookie过期时间
该过期就过期,不要让不必要的数据一直带在身上走来走去.
4. 使用域分离
为图片或者其他静态资源文件使用子域或者建立新的独立域名(申请新的域名),避免无必要的cookie传输,当然也是要在有必要得情况下,图片类网站肯定有必要,javaeye上得图片并没有使用域分离,所以我们得cookie其实会带到坛子得图片服务器上去,每次请求图片都是如此(不过还好,坛子里没有什么图片,所以这方面的浪费不大).

小结,其实cookie上得问题,单词请求看上去也不是什么大问题,好像是无所谓得事情,就那么几十个byte,至于吗,不过大家都听说过水滴石穿,绳锯木断的故事.所以该做的,我们还是要做,正所谓,勿以善小而不为,勿以恶小而为之.
优化浏览器加载
1. 将css放在页面顶部加载
把样式表放在文档底部的问题是在包括Internet Explorer在内的很多浏览器中这会中止内容的有序呈现。浏览器中止呈现是为了避免样式改变引起的页面元素重绘。用户不得不面对一个空白页面。
      HTML规范清 楚指出样式表要放包含在页面的<head />区域内:“和<a />不同,<link />只能出现在文档的<head />区域内,尽管它可以多次使用它”。无论是引起白屏还是出现没有样式化的内容都不值得去尝试。最好的方案就是按照HTML规范在文 档<head />内加载你的样式表。

2. 将js放在页面底部加载
脚本带来的问题就是它阻止了页面的平行下载。HTTP/1.1 规范建议,浏览器每个主机名的并行下载内容不超过两个。如果你的图片放在多个主机名上,你可以在每个并行下载中同时下载2个以上的文件。但是当下载脚本时,浏览器就不会同时下载其它文件了,即便是主机名不相同。

Js放在底部加载其实并不影响浏览器展示页面,除非用户会在js加载完成之前就调用某个js方法,比如说页面刚展现到一半,但是恰好这一半里有一部分是调用了还未下载的js,这个时候就会出问题了,如果童子们遇到这种情况,可以把这部分js先加载.

    
总结一下下:以上这些优化点其实只是前端优化的部分内容,不过根据80/20原则,这些优化点已经覆盖了80%的情况了,同时前端优化其实也不是什么复杂的东西,原理上是很简单的,更多的是需要我们的实践,因为我们可能会碰到各种各样的问题,而很多的这些问题其实一般是预测不到的.只有遇到过才知道.
说的不对的地方请大家拍砖,或者童子们也可以把自己的经验在这里和大家分享一下.代表其他童子表示十分的感谢.

当然,由于ahuaxuan水平有限,文章中难免有不到之处,还望不吝指正,谢谢.
posted @ 2008-12-04 20:31 bt下载 阅读(1524) | 评论 (3)编辑 收藏

企业向国家工商总局申请对百度滥用市场支配地位进行反垄断调查,并处1.7亿元罚款 bt吧。

  本报记者 韦文洁

  目前,国内对百度的竞价排名虽然诟病颇多,但在制约手段的建立上处于真空状态,缺乏相应的措施。在业界评论家看来,如果国内搜索控制舆论没有相关的法律法规来制裁,总有一天,网络自由也将会沦为资本的附属品 色即是空

  2008年的这个秋天,对北京百度网讯科技有限公司(以下简称百度)来说,可谓多事之秋。

  10月31日,就在秋末的最后这几天,受河北唐山人人信息服务有限公司法定代表人王冠珏的委托,北京市邦道律师事务所李长青律师,把一册厚达91页16开本的《反垄断调查申请书》,送到了国家工商总局反垄断处一位官员手中,申请对百度滥用市场支配地位的反垄断调查。据这位官员告诉他,这是反垄断法实施以来,发生在网络领域的第一例。

  而在此之前,9月8日,淘宝网“为杜绝不良商家欺诈”,首次向外界宣布屏蔽百度搜索链接,向其公正性公开提出抗议;9月12日,百度因被披露涉嫌收取300万元保护费屏蔽三鹿奶粉负面新闻,被卷入震惊全国的“三鹿问题奶粉”事件之中,成为公众口诛笔伐的对象。

  更早一些,在今年的秋初,因质疑“竞价排名”的猫腻,百度就被深圳律师黄维领告上法院,如果不是百度提出管辖权异议,此案恐怕已在深圳市福田区人民法院开庭审理。

  “发难”一场连接一场,面对来自南北的不断夹击,百度这个“全球最大的中文搜索引擎”,如何将这股诉讼潮化险为夷,巧渡搜索引擎行业所面临的经营模式之困,化解新技术带来的法律难题,成为业界关注的焦点。

  异常变化

  2007年初,曾有10年经营药品生意的唐山人王冠珏,在工商局登记注册了唐山人人信息服务有限公司,创办了一个普及医药知识及招商的网站———全民医药网。

  为了提高网站的点击率,增加客流量,全民医药网和百度河北代理商签了一个《竞价排名协议》。

  所谓“竞价排名”,就是搜索引擎商推出的一种业务。当用户搜索一些常用词语时,从搜索引擎服务商购买了服务的厂商的名字就会排在搜索的前列。每当用户点击搜索的结果进入厂商的主页时,厂商就要向搜索引擎服务商缴纳一次费用,也就是搜索引擎的广告收入。

  全民医药网和百度签订的这个竞价排名,参与时间为2008年3月至9月份,金额8.9万元,排位于第3名,点击一次最低价格为0.55元,最高为3.8元。

  参与竞价的最初几个月,是全民医药网和百度的蜜月期。全民医药网做的全国厂家招商、招会员,在百度搜索排第一名。他们网站的客流,高峰时日浏览量达8000次,每月固定客户以1000人的比例上涨。

  谁知前景开始看好的时候,因为全民医药网要改版,6月至8月,全民医药网把竞价支付价格调到最低时,异常便开始出现了。

  7月5日一上班,商务部经理李娟就慌慌张张地跑来告诉王冠珏,“今天在百度里输入全民医药网的网址,链接一下子突然少了,以前的八万多条信息,只剩下了一个页面4条记录”。

  身为商人的王冠珏深知,访问量就是网站的生命,新客户来不了,老客户不会来,做免费的广告,商家也不会干。从百度来的访问量一直占全民医药网90%的客流量,如果不及时改变这种异常变化,全民医药网只能是“坐以待毙。”

  为了解决面临的“灭顶之灾”,作为百度的一个客户,王冠珏赶紧让技术部长王运岭,给百度总部和百度石家庄代理商发信和去电,反映这一异常变化。但百度的电话始终打不通。最后好不容易收到了石家庄百度的回信:“通常这种变化是正常的,是完全自动的,并不表示会对个别网站进行惩罚。”

  可是,让王冠珏焦虑不已的是,到了7月10日,全民医药网的日访问量骤减,从前一日的2961IP骤减为701IP。而后来以2008年7月10日为分界点的前后两个月对比,全民医药网的月访问量从前一个月的88095IP锐减至18340IP,日均访问量从2936IP锐减至611IP,会员已经在网上搜不到全民医药网,网站几乎没人来光顾了。再和百度联系,一点音信都没有。

  7月14日,焦虑不已的王冠珏不得不再次给百度去信哀求:“就算是你们客服说的是因为系统自动更新,但更新也不能差距这么大呀?现在几乎就在百度里找不到带着全民医药网域名的内容了……请帮我们查出原因,速回邮件或致电。”

  但直到现在,他也没有等来百度的邮件或回电。

  “降权惩罚”

  9月初,王冠珏给全民医药网换了一个域名,希望百度能够收录他们网站,但是一个月过去了,一条记录都没有。

  2008年9月25日,王冠珏在查询谷歌、雅虎对全民医药网的收录情况时,结果分别显示为6690条及3000多条,而其他的包括有道、搜狗,都比百度多。

  面对这种异常,王冠珏真是百思不解。经过走访大量的网站,咨询行内专家,翻阅大量资料后,发现他们也遭遇过类似的结果。

  一些站长告诉他,之前在百度做了竞价排名,如果后来不做,很容易就被百度屏蔽了。比如:重庆某知名民营医院在建立自己的网站后,在百度、谷歌、雅虎等搜索引擎上搜索排名一直排第一。但是,从今年8月开始,用百度竟然再也搜索不到医院网站了,但用谷歌、雅虎却能够搜索到,而且还是排位第一。这让医院感到十分疑惑,便以各种方式向百度反映这一情况,但都未得到令人信服的答复。迫于无奈,医院负责人赶紧投钱参加百度的竞价排名,很快,医院的网站又“神奇地”在百度上出现了。

  2005年10月至2006年4月,365数码网曾在百度做竞价排名广告。而当他们停止续费,不再在百度上投放广告后,竟然被百度“屏蔽”。

  据中搜网的技术专家介绍,所有的搜索结果都可以进行人工干预,所谓屏蔽就是在搜索程序中嵌入针对特定信息的“黑名单”,从而使机器自动不去抓取指定域名的网页,从而实现自己的营销目的。

  王冠珏的一位网友还告诉他,其代理的客户大部分在行业中有较强的影响,网站也都具有相当的流量。在购买百度关键词竞价之前,在百度搜索页左边的排序中,基本都能排在前几名,而在购买了百度的关键词竞价服务后,反而在首页很难找到。

  “显然,百度在非付费的自然排序中有意下降客户的排名,目的就是希望这些客户对于关键词竞价这种付费服务产生依赖。”王冠珏的网友说。

  因此,早在2005年,一些网站站长甚至结成了“反百度联盟”,并且获得了信息产业部备案序号(豫ICP备05009507)。据《瞭望》报道,联盟的发起人郭振东,2004年发现自己创办的文学网站美人鱼社区被百度屏蔽。此后,他在与百度上海公司员工的接触中获悉,只要交6000元就能将被封的网站解禁,并承诺在一年内不再屏蔽。因此,他认为百度之所以对网站进行屏蔽,是为了推广百度的竞价排名服务,遂发起“反百度联盟”,收集百度公司对待站长和网友不公正的证据。

  “没在百度做竞价排名广告前,还可以在百度上搜索到365数码网,现在却搜不到了。早知道这样,还不如一开始就不做呢。”该365数码网负责人认为,百度“封杀”365数码网的目的,在于迫使其继续交钱给百度做竞价排名广告。

  “最令人不服气的是,用什么评定中小网站该不该被屏蔽,这一系列的标准都是百度自己在操作,外人无法知道,更无法考证和干涉。”一位网友告诉王冠珏。

  看一看他人,比一比自己,王冠珏彻底明白了,因为自己的网站开始有了4000以上的客流量,它一看你的IP这么高,开始能赚到钱,为什么还不到我这里来交钱?便给你的网站来了个“降权惩罚。”

  但百度企业市场部总监舒迅曾对“屏蔽”一说断然否认:“百度搜索引擎上是否收录一个网站,与这个网站是否参与百度竞价排名推广没有任何关系。百度收录的中文网站数是全球最多的,但并不承诺收录每一个网站。”

百度垄断

  “百度一下”,几乎已经成为广大网民最为常见的习惯性搜索。

  自7月份以来,不断有客户问王冠珏:“在网上为什么搜不到你们网站?”网民一般都使用百度,他们认为在百度搜不到,就是在网上搜不到。

  李长青律师认为,百度的屏蔽行为对其他网站之所以构成封杀是基于其获得的市场支配地位。

  据相关资料表明,2008年第2季度,百度占据中国搜索引擎市场份额的64.4%。第3季度,坐拥中国搜索市场近2/3份额。到今年10月23日,百度网站发布公司新闻,已经在中国搜索引擎市场稳稳占据70%以上市场份额。虽然它不过是一个工具,但它现在形成了一个霸主的地位。将对手远远抛在后面。

  《反垄断法》第19条第一款第一项规定,有下列情形之一的,可以推定经营者具有市场支配地位:一个经营者在相关市场的市场份额达到二分之一的。上述资料表明,百度已经完全获得了中国搜索引擎市场的支配地位。

  正是因为百度具有了这样的市场地位,其屏蔽行为才具有了封杀其他网站的能量和效果。百度也利用此举,赢得了巨大的收益:2007年,百度年收入为17.444亿元人民币,比2006年增长108.2%。而其2008年第二季度的财报显示,收入突破一亿美元。

  记者一位在北京经营网站的朋友则认为,对于众多中小网站来讲,其绝大多数的流量都来自于百度搜索引擎这个“入口”。因为绝大多数网民往往只能记住网站的名称,然后通过搜索到达该网站。因此,摆在众多网站面前的一个现实问题是,网站流量的访问入口已经被百度这些大搜索巨头所垄断,网站的生杀大权事实上已经被掌握在了别人手中。一旦被搜索引擎“屏蔽”,就很有可能导致网站失去流量。对于搜索引擎“竞价排名”的方式,中小网站虽然不满,但为了生存,大多数都敢怒不敢言。

  现在摆在他们面前的只有两条路:如果想逃避被百度封杀的厄运,要么屈服于它,参与竞价推广,任其宰割;要么向反垄断部门举报,或到法院起诉,通过打官司,寻求公正。

  对王冠珏而言,摆在他面前的这两条路,没有一条坦途。

  “生死之战”

  就在濒临绝望的时候,8月1日起施行的《反垄断法》,让王冠珏瞬间下定了决心:“我看到了希望。只要法律是公正的,哪怕我失败,也要去摸这个老虎屁股。否则,你投入再多,由它来主宰,这种状况永远也无法改变。”

  10月31日,在送往国家工商总局反垄断处的《反垄断调查申请书》中,李长青律师认为,百度对其他网站的封杀,是滥用市场支配地位的行为,造成两个严重的社会后果:其一、百度的封杀行为在实际上消灭了许多网络经济中的市场竞争主体,从根本上破坏了公平的市场竞争秩序,严重损害了社会主义市场经济的活力;其二、出于商业目的人工干预搜索结果的行为损害了社会大众的利益,不符合公众对于信息公开、客观的要求。其行为与敲诈勒索无二。这种网络霸权主义,不仅应该受到道义上的谴责,而且应该受到行政和法律的制裁。

  他建议:执法机构对百度使用的搜索技术规则和搜索过程进行调查;制定搜索技术规范和搜索市场服务规范,强化对搜索引擎服务的管理;责令百度停止其滥用市场支配地位封杀其他网站的违法行为,并处以1.7444亿元人民币的罚款(《中华人民共和国反垄断法》第47条规定:经营者违反本法规定,滥用市场支配地位的,由反垄断执法机构责令停止违法行为,没收违法所得,并处上一年度销售额百分之一以上百分之十以下的罚款。2007年百度全年营业收入为17.444亿人民币,根据以上规定,可以对其处以1.7444亿元人民币的罚款)。

  中国互联网协会互联网政策与资源工作委员会学术专家胡钢曾对媒体表示,搜索引擎的“推广方式”或“赞助商链接”在本质上依然属于广告。但由于崭新性,搜索引擎尚处在广告法的监管盲区,这使得搜索引擎服务商得以明目张胆地大打“擦边球”。

  中国政法大学副教授吴景明则认为,我国《广告法》第13条早已规定:广告应当具有可识别性,能够使消费者辨明其为广告。而搜索行业的竞价排名未能被明确划归到广告范围,类似搜索引擎这类新技术应用带来的问题该如何适用法律,目前尚无定论,“这凸显我国相关立法的滞后”。

  互联法网总监赵占领也认为:“这类事件反映出我国互联网领域还存在很多法律空白或争议之处。比如广告法和反不正当竞争法如何适用于网络环境下?搜索引擎运营商在用户没有购买竞价排名的情况下,不收录用户的网站究竟该如何定性?是否属于强制交易行为?这都需要提供证据来证明搜索引擎运营商此举的初衷是为了达成交易。”

  目前,国内对百度的竞价排名虽然诟病颇多,但在制约手段的建立上处于真空状态,缺乏相应的措施。在业界评论家看来,如果国内搜索控制舆论没有相关的法律法规来制裁,总有一天,网络自由也将会沦为资本的附属品。

  现在,也许是政府部门着手解决这个问题的最佳时间。10月31日,李长青律师送材料到国家工商总局反垄断处时,一位官员告诉他:“内部也正在开会,研讨这方面的问题呢。”

  在等待行政申请结果的同时,他正忙着收集证据,准备一旦时机成熟,要与百度对簿公堂,展开一场面对面的“生死之战”。而“一旦这个口子打开了,救活的就不仅仅是全民医药网这一家了,而是所有的中小网站和中国的互联网经济。”李长青律师说。

posted @ 2008-11-09 22:08 bt下载 阅读(206) | 评论 (0)编辑 收藏

这是 Mashable bt搜集的最新 Web 开发工具箱,包括拖放式 Web 程序创建工具,代码库,项目管理,测试程序,以及支持各种编程语言的框架,从 Ajax 到 Ruby 到 Python。这是第二部分。

  参考与资料


COfundOS - 一个讨论开源软件,寻找投资的平台。 http://www.5a520.cn
Mac Yenta - 独立 Mac 开发者的社会化网络平台
CorkDump - 一个关于常用资源(代码片段,CSS,Flash 等)讨论板。
All Developers Network - 开发者社会化网络
CodePlex - 来自微软的开源项目托管站点


UnmatchList - 开发设计者的资源库
developerAnalytics - 社会媒体评价与报告,帮助你发现有潜力的社会媒体应用。
CollabFinder - 一个供开发设计者协同工作的地方。
测试,监控,Bug 跟踪,项目管理



CloudStatus - 对 Web 上最流行云服务进行观察

BetaBitz - 一个帮助你寻找 Beta 测试者的地方

observu - 免费的网站与服务器监测服务

UserFix - Bug 报告与功能请求站点

OctaGate SiteTimer - 用来测试你的站点的访问时延



Cuzillion - 简单的页面测试与检查程序

Mob4Hire - 为你的移动应用程序需要大量测试者

Beanstalk - 一个托管的服务,用来浏览跟踪版本控制,包含对Basecamp 以及 Campfire 等同类服务的集成。

BUGtrack - 项目管理,Bug 跟踪

UserZoom - 用户体验测试平台


devunity - 曾是一个 Beta 版 Bug 跟踪服务,现已成为社会化开发平台
BuiltWith - 对任何站点提供技术分析与 SEO 信息服务
fixx - Bug 跟踪,包含移动设备界面与协同功能
BugWiki - 一个简易的 Bug 跟踪系统
litmus - 基于 Web 的测试程序,在不同浏览器上检查你的设计


Bugtagger - 一个包含标签机制的 Bug 跟踪程序,方便找到每个 Bug 是与什么相关的
FEED Validator - 验证你的 Atom, RSS 以及 KML 聚合服务
pastebin - Debug 工具允许你协同工作以找到问题所在
JUnit.org - 一个测试框架,编写并执行自动测试程序
  Ruby 以及 Ruby on Rails 资源与工具


Open Source Rails - 一个用来展示基于开源 Ruby on Rails 站点的地方
Exceptional - Rails 程序异常跟踪与管理工具
TuneUp - 使用 Rails 插件检查你的程序的性能
heroku - Ruby on Rails平台,无需安装配置,直接在浏览器中写代码。
RSpec 1.1.8 - Ruby 的开发框架,包括 Scenario 框架与代码示例框架



Lovd By Less - 一个开源的 Ruby on Rails 社会网络平台
Merb - 一个 Ruby 框架,包含广泛功能
Camping - 一个 Ruby 微框架
  Ajax, Java & JavaScript 资源与工具


Javxs - 在线工具,将 HTML 转换为 JavaScript
frevvo - 一个 Ajax 表单创建工具,包括 XML 支持与拖放式控制
AjaxDaddy - Ajax 程序演示
WaveMaker - 可视化,开源 Ajax 所见即所得编辑器
AppJet - JavaScript 程序编写平台



SproutCore - 一个 JavaScript 框架,用来创建桌面质量的 Web 程序
Bungee Connect - Ajax Web 程序平台,跨浏览器支持
Spring - 企业 Java 应用平台,旨在提高开发效率与程序质量
jQuery - 一个用于 Ajax Web 开发的 JavaScript 库。
KSS - 使用该框架,无需编写任何代码就可以开发基于 javaScript 的 UI
    PHP 资源与工具


Flow3 - 一个最初用于 TYPO3 5.0 的 PHP 框架,但可以独立使用
Prado - 一个基于组件的 PHP 5 编程框架,面向对象,事件驱动
  Perl 资源与工具


Mason - 基于 Perl 的 网站开发引擎,包含 Debug, 模板等工具
  Flash 资源与工具


OpenLaszlo - 富 Internet 平台,结合 Flash 与 DHTML,但只需一次编写
  Python 资源与工具


GTK+ - 一个用于 Python 的 GUI 开发工具套件
Wing IDE - 专业的 Python 开发环境,提供30天试用
Cheetah - 一个开源的,基于 Python 的模板引擎与代码生成工具

posted @ 2008-11-06 19:51 bt下载 阅读(206) | 评论 (0)编辑 收藏

新闻来源:mashable.com
这是 Mashable bt搜集的最新 Web 开发工具箱,包括拖放式 Web 程序创建工具,代码库,项目管理,测试程序,以及支持各种编程语言的框架,从 Ajax 到 Ruby 到 Python。这是第一部分。

Web 程序创建类


DreamFace - 一个用来创建个性化 Web 程序的框架。

Organic Incentive - 以拖放式界面创建 Web 饰件 http://www.5a520.cn

dbFLEX - 商务程序开发平台。

app2you - 在线创建与定制 Web 程序。

Qrimp - 一个便宜的数据库平台,基于你周围的数据(如 Excel)创建应用程序。





Lightspoke - 拖放式程序创建工具,动态过滤,排序,真正的关系数据库后台。

Tersus - 可视化程序创建工具,无需编写代码。

Qt - 跨平台应用程序框架,可以同时开发应用与界面。


代码库与代码搜索




byteMyCode - 代码搜索

Snipplr - 帮你存储,管理所有代码片段。

ErrorKey - 错误代码搜索引擎。

findJAR.com - JAR 文件搜索

github - 代码库,既支持公共代码,又支持私人代码,私人代码通过 SSH 以及 SSL 访问。



merobase - 搜索组件。

Codebase - 代码库,技术支持与安装部署跟踪程序。

CONFiles - 配置文件的在线存储与分享

CodeSnippets - 公共代码库,也支持私人代码

GWT-Ext - 免费的,可下载的饰件库


开发环境,平台与框架


SocialGO - 社会化网络托管平台,包括消息,视频聊天,会员资料,照片分享,博客等
Pringo - 社会化网络平台,功能包括视频,MP3 支持,图片库,圈子,podcasting 等。
slinkset - 一个用于创建社会化新闻站点的在线平台
iWidgets - 社会化 Syndication 平台,允许你将你的内容聚合到社会化网络
WackWall - 一个 Hosted 的社会化网络平台




WhiteLabelDating.com - 一个创建约会,社会网络,社区站点的平台,允许以自己公司的名义创建。
ONEsite - 社会网络平台,包括博客,照片与视频库,评分与标签,消息板,私人消息等
jinity - 免费的社会网络平台,包括消息板,聊天,圈子,日志,投票,新闻等
Magnify.net - 网站视频工具,包括全套媒体工具
ShoutEm - 微博客与社会网络平台



Soceeo - 社会网络平台,包含文件分享,新闻,投票等
Swift - 移动站点创建工具,包括多种设计选项,支持 RSS Feed,多媒体等
SnappVille - 社会网络平台,包括组,博客工具,即时消息等
Ning - 社会网络平台,允许使用自己的品牌,包括会员资料,事件列表,甚至 Facebook 集成。
mixxt - 社会网络平台,包括事件,论坛等
zembly - 一个用来创建社会应用的的平台,目前处于 Beta 版。Yuku - 一个社区平台,可定制,拥有很强大的系统管理工具SocialEngine - 基于 PHP 的社会网络平台,功能包括 multi-part profiles,子网,搜索友好 URL,博客,圈子等。Cappuccino - 一个用来创建桌面品质 Web 程序的开源框架Jaws - 一个用户友好 CMS 平台。   综合开发工具


Tabifier - 对你的代码进行自动缩进。
Sms2do - 一个用来评测和演示 SMS 程序的免费工具。
Pretty Printer - 源代码格式化工具,支持 PHP, JavaScript, CSS 等
Jitterbit - 一个开源集成方案,提高可扩充性与性能
Bitizer - 二进制,十进制,16进制,Base 36 以及 ASCII 转换工具



thmbnl - 显示你站点中那些链接网页的缩略图
ID Selector - 一个 OpenID 工具
consoleFISH - 免费的,基于 Web 的 SSH 服务器访问
form site - 用来创建自定义表单
99Polls - 用来创建投票与调查



Warehouse - 一个非常漂亮的代码库浏览服务,支持多代码库以及非常完善的权限控制
rendur 2.1 - 一个沙箱程,让你一边写代码,一边生成页面
Languify - 翻译管理系统
ROR Sitemap Generator - 顾名思义,这是一个 ROR 网站地图生成工具
MicroMaps - 用来生成交互式地图,放在你的网站



Newsfeed Maker - 为你的网站或博客创建 News Feed
WriteMaps - 网站地图在线生成工具
Project Kenai - 免费的开源项目或代码托管站点
Launch Splash - 为你还没有开通的网站免费生成一个欢迎页面
Browser Shell - 基于浏览器的 SSH 工具
foigo - 创建自定义表单,调查,以及数据库AggData - Premade lists for your development projects.SnapCasa - 网站缩略图工具Versionshelf - 代码库安全管理   Mashups 与 APIs


The Echo Nest - 音乐相关的开发服务 API,包括歌手资料,音乐推荐等功能
Zeep Mobile - 为你的站点添加基于文本的消息系统
Clickatell - 一个短消息网关,让你的网站通过多中连接方式发短消息
Nonoba - 在线游戏开发 API,支持多玩家。
Zong - 移动支付平台,包含开发 API



Web Shots Pro - 一个 API,开发者可用来在他们的程序中添加网站缩略图。
Pushpin - 一个简单易用的在线地图 API,支持大量标记以及众多其它功能
Datamash - Create widgets and mashups for your site with information anywhere on the Web.借助网络上的众多信息为你的站点创建 widgets 与 mashups
Spicy Pipes - Mashup builder.

posted @ 2008-11-06 19:50 bt下载 阅读(239) | 评论 (0)编辑 收藏

原文作者:miguelcarrasco
原文链接:Who Wants To Beat-Google?
翻译:小猪哥

谁不想打败Google呢?很宏伟的目标,但怎样做到呢?每个人对此都有自己的魔幻方法。微软一度要以440亿美元收购Yahoo!,还在R&D投资 bt几十亿,纵然财力如此雄厚,他能做到么?有人认为需要更多的网页检索,有人认为应当有更好的界面,这个问题的答案仁者见仁,智者见智。

    而且现在来做这件事情(打败Google)再合适不过。随着经济危机的来临,大批大批的web 2.0 公司即将破产,那些仅仅依赖互联网生存的公司也即将倒闭。即便强如Google也在去年受到了冲击,其股价去年700美元每股,而今跌到286(作者发稿时)。现在看来,互联网免费的午餐已经消失。

    然而微软却一直保持着强劲的势头,因为他非常多元化而且在一个领域做得实在太优秀了——软件!他有着难以想象的money,手中有难以置信的全球智慧人群(接近100,000雇员),同时他还拥有最富有梦想的一些领导者在运筹帷幄。如果有谁能够做出更好的搜索引擎,那毫无疑问就是微软。而Google会退缩么,当然也不会。

社交图(Social Graph)


Facebook经常谈论的Social Graph着实强大,因此Facebook得以很了解你。他知道你的朋友是谁、你住在哪里、你在哪儿工作……他有图片、video以及你感兴趣的东西。他甚至知道你在哪个社交圈、你想参加什么活动。因而可以说Facebook比你的朋友都了解你。

搜索怎么了(What’s Wrong With Search Today?)

    当我试着用“GAC”一类的来搜索的时候,返回的结果令我感到荒唐——加拿大抵制协会(Geological Association of Canada)。我是一个软件开发者,Facebook、Twitter和LinkedIn 都知道这一点,但是Google对此一无所知。所以返回的有效搜索寥寥无几。我妈妈搜索一个关键词跟我搜索一个关键词得到的返回完全相同。但是我妈妈喜爱 的是手工艺,我喜欢的是软件开发,我们应该得到不同的结果才对。

    为什么没有人利用社交图的数据呢?单纯拷贝Google搜索模式、换个Logo是行不通的,人们更换搜索需要理由。在搜索中添加内容才是出路。

    比尔盖茨在过去的几年里一而再再而三地提到:搜索的道路还很长。几个月前我听到的解决方案——新的界面、一直鼠标滚动的搜索结果(never ending scrolling),这些显然不是比尔盖茨想说的。Scrolling endlessly所以你就不用选页了?这显然不是解决方式。

    微软真正应当做到的是:当用Google和Live Search搜索的时候,Live Search返回的结果更好。而且不是好一点,要好很多才行。

微软能做什么(So What Can Microsoft Do?)

    毫无疑问,微软有业内最优秀的开发者、架构师和工程师,同样也有大笔大笔的钱可以投到搜索中(这一点从他购买Yahoo! 就能够看出来)。然而微软要想赢得搜索战所缺少的东西也很明了:他们需要创意和行动路线,也即“作战计划”。Windows, Internet Explorer和Office,微软当年都不是第一个,但他做出了比其他操作系统更好的操作系统,比其他office套件更好的office套件,比其 他浏览器更好的IE,而且他还让所有这些应用能够无缝地运行在一起。所以如果微软拥有战略,并且能够正确实施,Live Search将会迅速得到难以想象的市场占有率。

Live Search 与Facebook关联(Live Search and Facebook Connect)

    微软应当充分利用Facebook connect,并将之与Live Search关联。使用Facebook connect,Facebook用户能够在Microsoft Live Search中关联到他们资料数据和认证证书。通过关联搜索、结合用户的资料数据,这个搜索就是“终极搜索引擎”。

Microformats将是搜索的未来(Microformats are the future of Search)


    Microformats比其他任何浏览器都好,以hCalander, hCard和 hReview开始。如果你还从未听过Microformats,赶紧查查,你就会知道他为什么这么重要。到目前为止,网络上大部分的数据都是完全无序的。举个例子你输入“Contact Miguel Carrasco”搜索,你会搜到我的博客但仅此而已。但你想要找到的是我的联系卡片。下面是我使用hCalander Microformat来为Winnipeg.net User Group创建一个事件的实例。

   1: <div class="vevent" id="hcalendar-Winnipeg-.net-User-Group-September-Event">
   2:     <a class="url" href="http://dotnetwired.com/">
   3:     <abbr class="dtstart" title="2008-09-30T06:00-06:0000">September 30, 2008  6</abbr> –
   4:     <abbr class="dtend" title="2008-09-30T08:00-06:00">8am</abbr> : 
   5:     <span class="summary">Winnipeg .net User Group September Event</span> at
   6:     <span class="location">17th Floor - One Lombard Place - Winnipeg, Manitoba, Canada</span></a>

   7:     <div class="description">What could possibly be better than enjoying some free pizza and pop with your peers while be entertained / educated by a presentation on a single .Net topic? Well, how about an open forum that includes some of the hottest topics in software development to date?! To keep the meeting energized, we will be limiting each topic to 20 minutes, and what's more, each topic will have a subject matter expert on hand to facilitate the session.
   8: 
   9:     Come prepared with questions, project stories, and ideas to one of the most unique user group sessions we have ever had.
  10: 
  11:     Topics will include:
  12: 
  13:     What is BizTalk
  14:     A Real World Silverlight Application
  15:     What is NHibernate
  16:     Why Continuous Integration Is Critical
  17:     Open Forum Free-for-All Session</div><div class="tags">Tags:
  18:     <a rel="tag" href="http://eventful.com/events/tags/winnipeg">winnipeg</a><a rel="tag" href="http://eventful.com/events/tags/user%20group"> user group</a><a rel="tag" href="http://eventful.com/events/tags/.net"> .net</a><a rel="tag" href="http://eventful.com/events/tags/microsoft"> microsoft</a></div>
  19: 
  20: </div>

    一个支持Microformat的搜索引擎可以在搜索结果中得到正确的信息,并且链接到网址来为事件注册

完美的搜索界面(The Complete Search Interface)

    大家也许都忘记了,Google刚诞生出来的那会,没有blogs,Video也不大,Facebook和其他社交网络还在娘胎呢。然而搜索的未来在于内容。人们每月花费成百上千个钟头在社交网络、新网址和博客。他们持续地向这些玩意中提供了大量他们的信息:喜欢什么?朋友是谁?下周做什么?现在什么心情?未来三周可能去哪玩……

    我个人就至少在网络上使用至少20种不同的社交服务,所以说搜索引擎不能只返给我简单的数据,而应当利用这些数据返给我我想要的内容。比如,我已经在网上吵了好几天说我下周要去迈阿密。

    在Facebook,我创建了几个我将要在迈阿密参加的活动;在Digg,我dugg了几个水中呼吸器的信息;在Last.fm,我创建了几个标题为“Miami Plane Ride”的音乐列表。在Facebook我从朋友那儿收到了几个回帖称我不应当错过迈阿密的几个酒吧和跳舞俱乐部。其他朋友推荐了那儿的几处海滩,还给了照片。

    如果我去Google搜索跳舞俱乐部,最顶上的三个搜索结果跟我要找的一点关系都没有。如图:



图片11
    正如我说的,没有一个搜索结果对我有用,是不是我的搜索条件太为难Google了?于是我又输入了“Miami”,让我们再看看结果:


图片22

    现在起码我得到了一些结果能让我看到迈阿密的跳舞俱乐部,但是哪个是朋友推荐我的呢?为什么我要的结果不能直接出现在我的面前?为什么没有图片,或者最好再有video?消费者的评论在哪儿呢?

    使用Live Complete Search,,输入“跳舞俱乐部”,迅速在我的搜索结果中出现了内容,并且将结果局限到了迈阿密。并不是因为我想去迈阿密,搜索才得到这样的结果,而是因为我twitter了我的朋友问他们迈阿密最好的跳舞俱乐部在哪儿,因此,搜索找出了我想要的结果。



图片33

    第一条结果是Nikki Beach,正是我朋友告诉我的那个。搜索中还有一张图片,他们留给我的评论也能在搜索页面中看到,还有电话号码也以microformats的形式出现 在网页中,我还能够在这儿使用Twitter, Digg或者 Facebook得到更详细的信息。而且,Live Complete Search知道我在Last.FM创建了一个Miami播放列表,所以还在搜索中加入了一个链接。

    当然这只是个例子,但我想从中你已经能够看到了精髓。

Building Live Social Profile
    Google已经证明你并不需要拥有所有的数据,因为有人会提供而Google只是帮你找到它们,令人感到发笑的是许多企业纷纷克隆Google的方法。 微软有互联网上第一位的IM——MSN Messenger,每个用户都有一个Live 账号,有些人还有Live Spaces的账号。我不知道你怎样,但在我看来使用Live Spaces的并不多。我点击了一下我MSN的好友,发现很多人从未用过Live Spaces,即使有使用的人,可能使用的几率也不及Facebook之类的百分之一。

    我的建议是微软应当设法将Live Spaces变成人气旺盛的(“Live”) Spaces,从而用户可以通过互联网将他们的社交状况传上去,这将创建一个终极社交档案(social profile)和终极个人网页(social “my page”)。


图片44
建议界面(The Proposed Interface)

    建议的Live Search的界面非常简单。它默认提供完整的搜索容量,包含互联网上的一切并将搜索结果放在合适的位置。比如,使用完全搜索,你会得到一些网页、 blog、帖子和一些视频,也可能有写Digg文章。如果只想搜索自己的社交图呢?没问题,只需要点击“Social”,搜索结果马上只呈现出与你有关的 结果。

    而且,Live Search的界面中能够插入许多过滤器,比如“搜索”和“儿童”。学校可以管理网络从而只允许“搜索”模式,父母可以管好自己的孩子只允许“儿童”模 式。通过Live Spaces和 Live Profile连接这些系统,微软将创建出比Google PageRank强大许多的搜索,用户的天平也开始摆向了这边。



图片55
搜索的最终思想(Final Thoughts on Search)

    希望你能够意识到,社交内容、microformats、和一个能够提供整个网络的完美界面将是搜索的下一次飞跃。拥有更加接近社交图的搜索结果比PageRank或者PageRank的克隆更容易统计互联网

posted @ 2008-11-05 21:57 bt下载 阅读(191) | 评论 (0)编辑 收藏

毋庸置疑,对于所有研究互联网新媒体公司的同仁们而言,blogbus是一个绝佳的案例,他不是BT bsp。

1,在门户BSP大举进攻下,专业BSP日渐没落。blogbus偏安于上海,能发展的有声有色,不易。刚看到Jenny发的blogbus六周年的活动。可以说,blogbus的发展路线值得所有web2.0公司学习。

 编者注:如在百度中搜索 甜性涩爱色即是空 爱的色放出现的问题说知道了。

2,blogbus能走到现在,跟公司团队的黄金组合关系很大。资深的互联网人士:横戈;资深媒体研究专家:魏武挥;资深广告营销界人士:jenny。我想,国内所有希望通过互联网赚钱的web2.0公司都应该参考下这种团队。不管是思路、见地。还有资源,客户的说教。

3,blogbus走出的商业模式,将是未来很长一段时间,不少国内2.0公司必须的一步。原因很简单,中国互联网广告规模虽然上涨很快,但依然停留在初级阶段,缺乏专业细分的广告网络(代理)公司推动。加上客户认知度较低,web2.0公司必须肩负推动广告挖掘的重任。

4,所以,细分的广告网络(代理)公司在国内会越来越有前景,其中一部分会来源于公关公司的升级,另一部分会来自于当下大量掌握广告客户投放资源的4A公司;再有一个就是新媒体或者是社会化媒体公司自身,在这点上blogbus和feedsky都是个例子。David Wolf说,“中国的问题在于我们点子的太简单”,其实更准确点说是缺专营的广告营销公司。

5,所以,有人会问:blogbus是广告公司,还是互联网公司?其实,blogbus作为一个新媒体或者是社会化媒体平台,已经聚集了百万级的人群,背靠这些人群挖掘出了不小的商业价值,这已经说明了一切。很多更大用户量级的公司,尚不及此。你说google是互联网公司,还是广告公司?除了不断膨胀的互联网业务,google也正在成为更大的广告代理或分销商。所以,我说过,新媒体要变成广告公司

6,blogbus最近推出的几个业务,非常值得把玩。一个是基于blog平台推出的SNS功能,我非常认同魏武挥的说法,因为用户和营销需求去增加blog平台的互动功能,显然SNS是增加互动关联的成熟方式。但绝不是把blog变成一个SNS平台。

7,另一个更有意思的则是《城客》,简单说,城客是一个依托于blogbus平台的杂志;它其实是blogbus线上资源的一个延伸(内容低成本+现有用户群),这也是我看好它的一个因素;赶巧的是,同期还有一个纯粹靠整合网上内容的印刷杂志《博客天下》。形式相同,思路却是迥异。

8,我记得,blogbus下面还有一个做口碑营销的“吆喝城”。

9,blogbus会成为一种现象,尤其是在冬天。

posted @ 2008-11-03 11:34 bt下载| 编辑 收藏

TreeMap是红黑树算法的实现,实现了SortedMap接口,要注意的是它不在使用哈希表,存储方式是一个特殊的二叉树,有关红黑树:
http://baike.baidu.com/view/133754.htm  http://www.bt285.cn

这篇文章介绍的不错,我之前没有听说过二叉树,我就是看这篇文章加上看一下TreeMap的源代码才搞懂红黑树算法的.

 

这里不打算研究TreeMap的源代码了,因为完全是一个算法的实现,如果对这个算法不了解,肯定看不懂,我也有很多地方不是没有完全看明白,这里就谈谈TreeMap的使用吧.

 

 

TreeMap的声明:public class TreeMap extends AbstractMap implements SortedMap,Cloneable, java.io.Serializable
所以我们要知道SortedMap接口:
SortedMap表示的是一个排序的Map
public interface SortedMap extends Map
增加了几个方法的定义
SortedMap headMap(Object toKey)
SortedMap tailMap(Object fromKey)
SortedMap subMap(Object fromKey, Object toKey)
Object firstKey()
Object lastKey()

 

 

既然TreeMap是有序的,自然要求元素是可以比较大小的,如果构造函数指定Comparator的话,就使用这个Comparator比较大小,如果没有指定Comparator的话,就使用自然排序(元素要实现Comparable接口).如果这两个都不可用,就等着出错吧.

现看一下该接口的定义:
public interface Comparable{
   public int compareTo(Object o);
}
该接口定义类的自然顺序,实现该接口的类就可以按这种方式排序.
一般要求:
e1.equals((Object)e2)和e1.compareTo((Object)e2)==0具有相同的值,
这样的话我们就称自然顺序就和equals一致.
这个接口有什么用呢?
如果数据或者List中的元素实现了该接口的话,我们就可以调用Collections.sort或者Arrays方法给他们排序.

如果自然顺序和equals不一致的话,如果出现在Sorted Map和Set里面,
就会出现预想不到的逻辑错误,可能你调用add的时候添加不了,而集合里面确没有这个元素.具体的讨论要接口哈希表的应用.

 

 

 

public interface Comparator {
  int compare(Object o1, Object o2);
  boolean equals(Object obj);
}

定义了两个方法,其实我们一般都只需要实现compare方法就行了,因为类都是默认从Object继承
所以会使用Object的equals方法.
Comparator一般都作为一个匿名类出现,对于没有实现Comparable的对象的集合,排序的时候
需要指定一个Comparator.

这里举例说明
对于实现了Comparable的类我们就用最简单的Integer
List list=new ArrayList();
list.add(new Integer(3));
list.add(new Integer(53));
list.add(new Integer(34));
Collections.sort(list);

对于没有实现Comparable的,我们就用Object,按照hashCode大小来排序.
List list= new ArrayList();
list.add(new Object());
list.add(new Object());
list.add(new Object());
Collections.sort(list,new Comparator(){ public int compare(Object o1, Object o2){
                    return (o1.hashCode()-o2.hashCode());
})

因为是二叉树,所以一般查找时间复杂度为 o(lg(n)),这个效率当然没有HashMap的效率高.不过TreeMap比HashMap功能强大,如果不需要排序的话当然不会用TreeMap,如果需要排序的话,HashMap无法胜任,当然要用TreeMap了,它可以求子Map.所以这个是适用场合问题,无法比较他们.
 
另外,我们也习惯了,有Map就会跟一个Set,我们都可以猜到TreeSet和通过TreeMap实现的一个SortedSet的实现.不过我觉的TreeSet好像比TreeMap用的场合多一些,求子集是很常用的呀!!

posted @ 2008-10-30 20:59 bt下载 阅读(3262) | 评论 (1)编辑 收藏

以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名、移动文件的目的。不过后来经常发现问题,真的很bt,File#renameTo(File)方法会返回失败(false),文件没有移动,又查不出原因,再后来干脆弃用该方法,自己实现一个copy方法,问题倒是再也没有出现过。

昨天老板同学又遇到这个问题,File#renameTo(File)方法在windows下面工作的好好的,在linux下偶尔又失灵了。回到家我扫了一遍JDK中File#renameTo(File)方法的源代码,发现它调用的是一个本地的方法(native method),无法再跟踪下去。网上有人说该方法在window下是正常的,在linux下面是不正常的。这个很难说通,SUN不可能搞出这种平台不一致的代码出来啊。

后面在SUN的官方论坛上看到有人提到这个问题“works on windows, don't work on linux”,后面有人回复说是“file systems”不一样。究竟怎么不一样呢?还是没有想出来...

后面在一个论坛里面发现了某人关于这个问题的阐述:
In the Unix'esque O/S's you cannot renameTo() across file systems. This behavior is different than the Unix "mv" command. When crossing file systems mv does a copy and delete which is what you'll have to do if this is the case.

The same thing would happen on Windows if you tried to renameTo a different drive, i.e. C: -> D:
终于明白咯。

做个实验:

  • File sourceFile = new File("c:/test.txt");   
  • File targetFile1 = new File("e:/test.txt");   
  • File targetFile2 = new File("d:/test.txt");   
  • System.out.println("source file is exist? " + sourceFile.exists()   
  •     + ", source file => " + sourceFile);   
  • System.out.println(targetFile1 + " is exist? " + targetFile1.exists());   
  • System.out.println("rename to " + targetFile1 + " => "  
  •     + sourceFile.renameTo(targetFile1));   
  • System.out.println("source file is exist? " + sourceFile.exists()   
  •     + ", source file => " + sourceFile);   
  • System.out.println(targetFile2 + " is exist? " + targetFile2.exists());   
  • System.out.println("rename to " + targetFile2 + " => "  
  •     + sourceFile.renameTo(targetFile2));  



  • 注意看结果,从C盘到E盘失败了,从C盘到D盘成功了。因为我的电脑C、D两个盘是NTFS格式的,而E盘是FAT32格式的。所以从C到E就是上面文章所说的"file systems"不一样。从C到D由于同是NTFS分区,所以不存在这个问题,当然就成功了。

    果然是不能把File#renameTo(File)当作move方法使用。

    可以考虑使用apache组织的commons-io包里面的FileUtils#copyFile(File,File)和FileUtils#copyFileToDirectory(File,File)方法实现copy的效果。至于删除嘛,我想如果要求不是那么精确,可以调用File#deleteOnExit()方法,在虚拟机终止的时候,删除掉这个目录或文件。

    BTW:File是文件和目录路径名的抽象表示形式,所以有可能是目录,千万小心。
    下面我写的一个实现方法

    /**
      * 使用FileChannel拷贝文件
      *
      * @param srcFile
      * @param destFile
      * @throws IOException
      */
     public static void copyUseChannel(File srcFile, File destFile)
       throws IOException {
      if ((!srcFile.exists()) || (srcFile.isDirectory())) {
       return;
      }

      if (!destFile.exists()) {
       createFile(destFile.getAbsolutePath());
      }

      FileChannel out = null;
      FileChannel in = null;
      try {
       out = new FileOutputStream(destFile).getChannel();
       in = new FileInputStream(srcFile).getChannel();
       ByteBuffer buffer = ByteBuffer.allocate(102400);
       int position = 0;
       int length = 0;
       while (true) {
        length = in.read(buffer, position);
        if (length <= 0) {
         break;
        }
        // System.out.println("after read:"+buffer);
        buffer.flip();
        // System.out.println("after flip:"+buffer);
        out.write(buffer, position);
        position += length;
        buffer.clear();
        // System.out.println("after clear:"+buffer);
       }

      } finally {
       if (out != null) {
        out.close();
       }
       if (in != null) {
        in.close();
       }
      }
     }

    posted @ 2008-10-27 10:15 bt下载 阅读(1655) | 评论 (2)编辑 收藏

    CSDN首页推荐了一篇文章,说两位退休的美国大学教授上书反对将Java作为编程教学语言,对此我表示高度认同。对于Java,我并不反感,而且相信它在工业应用中的地位不可取代,但是,我一直反对将Java作为主要的编程教学语言,因为教学语言承担着与生产语言不同的任务,它必须能够帮助学生奠定坚实的技术基础,塑造核心技术能力。在这方面,Java不能够胜任。

    1990年代中期以前,美国的计算机编程入门教育以Pascal为主。我的一位美国程序员朋友至今还怀念他与Pascal为伴的高中年代。到了1990年代中后期,由于ANSI C语言“纠正”了早期C语言的一些不适合编程教学的问题,因此成为很多美国高中和大学编程入门课的教学语言。1998年,美国指导编程教学的一个协会推荐将C++作为入门教学语言,在当时引起很大的反响,认为是编程教育方面的一个重要进步。但遗憾的是,C++非常复杂,而当时C++语言的教育体系又非常不成熟,因此很多地方的教学方法不得当,把学生迅速拖入无边无际的语言细节当中,引起了学生痛苦的抱怨。大约经过两三年不成功的实践之后,在本世纪初,美国计算机教育界普遍接受Java作为编程入门语言。此后在很短的时间里,Java迅速成为美国高中和大学里的首选编程教学语言,老师教得轻松,学生学得甜蜜,所以这个局面一直持续到现在。

    而在中国,BASIC语言及其变体一直到1990年代中期都还是“算法语言”课程的主要教学内容,充分折射出当时中国计算机教学与工业应用之间的脱节。只是到了1990年代后期,C语言才确立了在中国工科计算机编程入门教育中的主流地位。到现在为止,大部分工科学生都“必修”“C程序设计语言”这门课程。不过事实上,根据我的了解,这门课程的总体教学质量相当糟糕,大部分学生可以说是满怀希望而来,两手空空而去。在这种情况下,中国高校计算机编程入门教育已经开始悄悄向Java过渡了。据我所知,有一些名校已经开始将Java设为编程入门课程,并且认为这是与国际接轨进步标志。

    在我的朋友圈子里,大多数真正的一线开发者和技术领导者,对于将Java作为入门教学语言的“发展方向”都持质疑态度。他们中很多人目前主要的工作都集中在Java上,因此这种态度并非来自所谓语言宗教情绪,而是来自他们招聘和实际工作中的感受。他们发现,只学习Java、C#、VB等“现代”编程语言的学生,精于拿来主义,长于整合和快速开发,思维活跃,生产效率高,让他们来做直截了当的、有章可循的、非研究性和非创新性的工作比较合适,但是基础不扎实,对计算机系统的理解薄弱,处理细节和矛盾的能力不足,一旦他们熟悉的套路用不上,则缺少自主分析问题、解决问题的知识、能力和经验。

    今天看到两位教授的“上书”,才知道原来他们也有同感。只不过这两位教授说的更直白,直接反对将Java作为入门编程语言,而是冒天下之大不韪,公然号召开历史倒车,要求退回到C、C++、Lisp和Ada去。

    我是支持两位教授的。我认为,Java、C#、VB和其它虚拟机之上的语言都不适合作为专业程序员的入门教学语言。在中国还非常缺乏具有创新和独立解决问题的高水平程序员的局面下,我们应该认真做好的事情是努力提高C/C++的教学质量,而不是图快活转向Java。

    教学语言的选择是至关重要的事情。作为大多数学生第一种需要认真学习理解的编程语言,教学语言将会成为他们中间很多人的“编程母语”,深深地烙印在学生的思维方式中。这个编程母语要帮助学生破除计算机和软件的神秘感,建立对于程序的基本认识和对计算机模型的最初理解。在后续专业基础课和专业课程的学习中,这门编程语言应该作为主要工具贯穿始终,帮助学生认识计算机系统,掌握算法与数据结构技能,熟悉操作系统概念,理解编译原理知识,理解软件抽象及软件设计的基本思想,完成一定量的课程及课外项目实践,建立正确的软件开发实践习惯。不但如此,这种教学语言必须是工业界的主流语言,否则学生学非所用,学习动力无法保证。

    按照这个标准来衡量,Java适合于作为主要的编程教学语言吗?我不这么认为。首先,我承认Java在教学上有一些优势,比如其开发环境和工具支持非常成熟,有助于培养学生正确的编程习惯;Java是当今第一工业主流语言,标准类库非常全面,可以迅速地开发具有实际用途的程序,有助于激发和保持学生的兴趣;而在数据结构、算法、编译原理的教学方面,Java也毫不落于下风,在软件抽象设计(面向对象)方面,Java还有着明显的优势;特别是在并行编程的教学方面,Java 1.5 concurrency包提供的优势是压倒性的。尽管有如上这些优势,但Java作为教学语言存在着一个致命的缺陷,即它是一个虚拟机语言,这一点就足以把它从教学语言的名单上去掉。作为一个虚拟机语言,Java对开发者隔绝了下层的真实系统,从而构造了一个近乎完美的环境,在这个环境里,世界上只有一种机器,一个操作系统,内存是无限的,所有的机器都具有相同的字节顺序和一致的类型约定,为了设计的优美而牺牲速度永远是正义行为,从反射到运行时自动加载,从完备的容器类到统一字符编码,一大堆漂亮的功能都可以不费吹灰之力唾手而得。要是这个世界上每台计算机都是一个Java机器,每项编程任务都可以在这样一个近乎完美的环境中开发,那毫无以为,Java是最合适的编程教学语言。但是事实上呢?这样一个完美的环境是Java力量的源泉,但这却不是真实的世界。在真实世界里,我们可能面对非常原始的环境,苛刻的运行时限制,复杂多变的系统环境,令人窒息的细节魔鬼,要对付这些东西,需要开发者具有在应对复杂性,自己构造环境,在诸多限制条件下寻找解决方案的能力。而这种能力,被无数人无数次地证明是软件开发、特别是软件创新的核心能力。把Java作为教学语言,恰恰会导致这种核心能力的缺失。除此之外,如果耐心观察的话,不难发现,几乎在任何软件领域里的创新性成果都首先是由C/C++语言实现的,原因很简单,Java是站在C/C++基础之上的,只有C/C++先把大路趟开,Java才能够顺势而上。

    相反,尽管C/C++语言作为教学语言有很多的不足,比如不同环境下开发模式差异大,细节繁多,开发效率低,容易犯错,测试和调试困难,学习者难以保持动力,等等,但是这些问题都可以解决。而C/C++的关键优点,是能够让学习者在真实的计算机抽象上、在大量的细节和矛盾中学会思考,学会解决问题,学会了解真实的系统,知轻重,明生死,从而建立核心能力。掌握了C/C++ bt语言,再去学习和理解Java、C#、Python、Ruby和其它语言,就比较容易达到更高的境界。反之,如果习惯了舒舒服服躺在完美世界里当阔少,那就很难有勇气面对真实的世界。当然,很多开发者认为,现在更重要的能力是理解业务、整合现有资源的能力,而不是处理底层细节的技术。这种说法放在个人身上没有问题,但是不能成为整个编程教育的指导思想。我们需要各个层面上的人才,精通业务和设计的架构师固然很重要,但能够在底层作出创新成果的编程高手实际上更为稀缺和珍贵,很多时候也能够创造更大的价值。而且,更重要的是,一个精通系统知识的开发者在往上走的时候不会遇到大的障碍,而一个只知道拼装组合的“高级设计师”,往往连往下看的勇气都没有。

    Java的另外一个问题,是其所倡导的繁琐设计风格,一个对象套一个对象,一个对象叠一个对象,概念之间彼此横七竖八地互相依赖,人为制造出一大堆貌似精美、实则累赘的所谓设计。这个问题我已经批评过多次,并且相信这股歪风一定会最终被人们抛弃,Java最终会归于质朴。但是在这一天到来之前,Java对于初学者来说,很可能蒙住他们的双眼,使他们看不到软件设计中最可贵的简单性和优美的统一,体会不到数据和程序的统一。在这一点上,C表现的非常好,而C++如果教学得体,可以做的更好。

    当然,这并不是为现在的C/C++教学辩护。恰恰相反,从我了解的情况来看,目前普通高校的C/C++教学质量非常令人担忧。学生学不会,而且越学越没有兴趣,老师则感到教起来很棘手,迫于现实情况往往选择敷衍了事。反而是教Java,无论如何学生还能学到一点东西,对就业也有直接的帮助。至于学生的核心能力确实,发展后劲不足等问题,就让他们在现实工作中自己解决吧。坦率地说,这种想法也很有道理。不过,从教学角度来说,我认为老师们还是应该积极考虑如何提高C/C++的教学质量。毕竟学生阶段是十分宝贵的,基础不在这个时期夯实,将来想弥补,就算不是完全不可能,也将付出十倍的代价。本着对学生职业生涯的负责态度,还是应该帮助学生达到这个阶段应该达到的目标。在两位教授的公开信里,也充分表达出这个意思。

    我赞成的编程教育过程,应当是以C/C++(基本上是C)为主线,贯穿起算法、数据结构、系统原理、编译和数据处理、软件设计和组件技术等关键知识领域,让学生能够从根本上理解现代软件系统的原理和构造,并通过有效的练习建立正确的软件设计观念和良好的工程实践习惯。在这个基础上,无论将来是深入学习C++,还是进入Java的繁荣世界,或者拥抱Python、Ruby,甚至于走向Web开发,都会心领神会,势如破竹。

    posted @ 2008-10-14 19:38 bt下载| 编辑 收藏

    第1章基础知识

    1.1. 单钥密码体制

    单钥密码体制是一种传统的加密算法,是指信息的发送方和接收方共同使用同一把密钥进行加解密。

    通常,使用的加密算法比较简便高效,密钥简短,加解密速度快,破译极其困难。但是加密的安全性依靠密钥保管的安全性,在公开的计算机网络上安全地传送和保管密钥是一个严峻的问题,并且如果在多用户的情况下密钥的保管安全性也是一个问题。

    单钥密码体制的代表是美国的DES

    1.2. 消息摘要

    一个消息摘要就是一个数据块的数字指纹。即对一个任意长度的一个数据块进行计算,产生一个唯一指印(对于SHA1是产生一个20字节的二进制数组)。

    消息摘要有两个基本属性:

    • 两个不同的报文难以生成相同的摘要
    • 难以对指定的摘要生成一个报文,而由该报文反推算出该指定的摘要

    代表:美国国家标准技术研究所的SHA1和麻省理工学院Ronald Rivest提出的MD5

    1.3. Diffie-Hellman密钥一致协议

    密钥一致协议是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。

    先决条件,允许两名用户在公开媒体上交换信息以生成"一致"的,可以共享的密钥

    代表:指数密钥一致协议(Exponential Key Agreement Protocol)

    1.4. 非对称算法与公钥体系

    1976年,Dittie和Hellman为解决密钥管理问题,在他们的奠基性的工作"密码学的新方向"一文中,提出一种密钥交换协议,允许在不安全的媒体上通过通讯双方交换信息,安全地传送秘密密钥。在此新思想的基础上,很快出现了非对称密钥密码体制,即公钥密码体制。在公钥体制中,加密密钥不同于解密密钥,加密密钥公之于众,谁都可以使用;解密密钥只有解密人自己知道。它们分别称为公开密钥(Public key)和秘密密钥(Private key)。

    迄今为止的所有公钥密码体系中,RSA系统是最著名、最多使用的一种。RSA公开密钥密码系统是由R.Rivest、A.Shamir和L.Adleman俊教授于1977年提出的。RSA的取名就是来自于这三位发明者的姓的第一个字母

    1.5. 数字签名

    所谓数字签名就是信息发送者用其私钥对从所传报文中提取出的特征数据(或称数字指纹)进行RSA算法操作,以保证发信人无法抵赖曾发过该信息(即不可抵赖性),同时也确保信息报文在经签名后末被篡改(即完整性)。当信息接收者收到报文后,就可以用发送者的公钥对数字签名进行验证。 

    在数字签名中有重要作用的数字指纹是通过一类特殊的散列函数(HASH函数)生成的,对这些HASH函数的特殊要求是:

    1. 接受的输入报文数据没有长度限制;
    2. 对任何输入报文数据生成固定长度的摘要(数字指纹)输出
    3. 从报文能方便地算出摘要;
    4. 难以对指定的摘要生成一个报文,而由该报文反推算出该指定的摘要;
    5. 两个不同的报文难以生成相同的摘要

    代表:DSA





    回页首


    第2章在JAVA中的实现

    2.1. 相关

    Diffie-Hellman密钥一致协议和DES程序需要JCE工具库的支持,可以到 http://java.sun.com/security/index.html  或是www.bt285.cn 下载JCE,并进行安装。简易安装把 jce1.2.1\lib 下的所有内容复制到 %java_home%\lib\ext下,如果没有ext目录自行建立,再把jce1_2_1.jar和sunjce_provider.jar添加到CLASSPATH内,更详细说明请看相应用户手册

    2.2. 消息摘要MD5和SHA的使用

    使用方法:

    首先用生成一个MessageDigest类,确定计算方法

    java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");

    添加要进行计算摘要的信息

    alga.update(myinfo.getBytes());

    计算出摘要

    byte[] digesta=alga.digest();

    发送给其他人你的信息和摘要

    其他人用相同的方法初始化,添加信息,最后进行比较摘要是否相同

    algb.isEqual(digesta,algb.digest())

    相关AIP

    java.security.MessageDigest 类

    static getInstance(String algorithm)

    返回一个MessageDigest对象,它实现指定的算法

    参数:算法名,如 SHA-1 或MD5

    void update (byte input)

    void update (byte[] input)

    void update(byte[] input, int offset, int len)

    添加要进行计算摘要的信息

    byte[] digest()

    完成计算,返回计算得到的摘要(对于MD5是16位,SHA是20位)

    void reset()

    复位

    static boolean isEqual(byte[] digesta, byte[] digestb)

    比效两个摘要是否相同

    代码:

    import java.security.*;
                public class myDigest {
                public static void main(String[] args)  {
                myDigest my=new myDigest();
                my.testDigest();
                }
                public void testDigest()
                {
                try {
                String myinfo="我的测试信息";
                //java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5");
                java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
                alga.update(myinfo.getBytes());
                byte[] digesta=alga.digest();
                System.out.println("本信息摘要是:"+byte2hex(digesta));
                //通过某中方式传给其他人你的信息(myinfo)和摘要(digesta) 对方可以判断是否更改或传输正常
                java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1");
                algb.update(myinfo.getBytes());
                if (algb.isEqual(digesta,algb.digest())) {
                System.out.println("信息检查正常");
                }
                else
                {
                System.out.println("摘要不相同");
                }
                }
                catch (java.security.NoSuchAlgorithmException ex) {
                System.out.println("非法摘要算法");
                }
                }
                public String byte2hex(byte[] b) //二行制转字符串
                {
                String hs="";
                String stmp="";
                for (int n=0;n<b.length;n++)
                {
                stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
                if (stmp.length()==1) hs=hs+"0"+stmp;
                else hs=hs+stmp;
                if (n<b.length-1)  hs=hs+":";
                }
                return hs.toUpperCase();
                }
                }

    2.3. 数字签名DSA

    1. 对于一个用户来讲首先要生成他的密钥对,并且分别保存

      生成一个KeyPairGenerator实例

         java.security.KeyPairGenerator  keygen=java.security.KeyPairGenerator.getInstance("DSA");
                          如果设定随机产生器就用如相代码初始化
                      SecureRandom secrand=new SecureRandom();
                      secrand.setSeed("tttt".getBytes()); //初始化随机产生器
                      keygen.initialize(512,secrand);     //初始化密钥生成器
                      否则
                      keygen.initialize(512);
                      生成密钥公钥pubkey和私钥prikey
                      KeyPair keys=keygen.generateKeyPair(); //生成密钥组
                      PublicKey pubkey=keys.getPublic();
                      PrivateKey prikey=keys.getPrivate();
                      分别保存在myprikey.dat和mypubkey.dat中,以便下次不在生成
                      (生成密钥对的时间比较长
                      java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));
                           out.writeObject(prikey);
                      out.close();
                      out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
                           out.writeObject(pubkey);
                      out.close();
                      


    2. 用他私人密钥(prikey)对他所确认的信息(info)进行数字签名产生一个签名数组

      从文件中读入私人密钥(prikey)

         java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
                          PrivateKey myprikey=(PrivateKey)in.readObject();
                      in.close();
                      初始一个Signature对象,并用私钥对信息签名
                      java.security.Signature signet=java.security.Signature.getInstance("DSA");
                      signet.initSign(myprikey);
                      signet.update(myinfo.getBytes());
                      byte[] signed=signet.sign();
                      把信息和签名保存在一个文件中(myinfo.dat)
                      java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));
                            out.writeObject(myinfo);
                      out.writeObject(signed);
                      out.close();
                      把他的公钥的信息及签名发给其它用户
                      


    3. 其他用户用他的公共密钥(pubkey)和签名(signed)和信息(info)进行验证是否由他签名的信息

      读入公钥
      java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
      PublicKey pubkey=(PublicKey)in.readObject();
      in.close();

      读入签名和信息
      in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
      String info=(String)in.readObject();
      byte[] signed=(byte[])in.readObject();
      in.close();

      初始一个Signature对象,并用公钥和签名进行验证
      java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
      signetcheck.initVerify(pubkey);
      signetcheck.update(info.getBytes());
      if (signetcheck.verify(signed)) { System.out.println("签名正常");}

      对于密钥的保存本文是用对象流的方式保存和传送的,也可可以用编码的方式保存.注意要
      import java.security.spec.*
      import java.security.*

      具休说明如下

      • public key是用X.509编码的,例码如下:
          byte[] bobEncodedPubKey=mypublic.getEncoded(); //生成编码
                            //传送二进制编码
                            //以下代码转换编码为相应key对象
                            X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
                            KeyFactory keyFactory = KeyFactory.getInstance("DSA");
                            PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
                            


      • 对于Private key是用PKCS#8编码,例码如下:
         byte[] bPKCS=myprikey.getEncoded();
                            //传送二进制编码
                            //以下代码转换编码为相应key对象
                            PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(bPKCS);
                            KeyFactory keyf=KeyFactory.getInstance("DSA");
                            PrivateKey otherprikey=keyf.generatePrivate(priPKCS8);
                            


    4. 常用API

      java.security.KeyPairGenerator 密钥生成器类
      public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException
      以指定的算法返回一个KeyPairGenerator 对象
      参数: algorithm 算法名.如:"DSA","RSA"

      public void initialize(int keysize)

      以指定的长度初始化KeyPairGenerator对象,如果没有初始化系统以1024长度默认设置

      参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数

      public void initialize(int keysize, SecureRandom random)
      以指定的长度初始化和随机发生器初始化KeyPairGenerator对象
      参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数
      random 一个随机位的来源(对于initialize(int keysize)使用了默认随机器

      public abstract KeyPair generateKeyPair()
      产生新密钥对

      java.security.KeyPair 密钥对类
      public PrivateKey getPrivate()
      返回私钥

      public PublicKey getPublic()
      返回公钥

      java.security.Signature 签名类
      public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException
      返回一个指定算法的Signature对象
      参数 algorithm 如:"DSA"

      public final void initSign(PrivateKey privateKey)
      throws InvalidKeyException
      用指定的私钥初始化
      参数:privateKey 所进行签名时用的私钥

      public final void update(byte data)
      throws SignatureException
      public final void update(byte[] data)
      throws SignatureException
      public final void update(byte[] data, int off, int len)
      throws SignatureException
      添加要签名的信息

      public final byte[] sign()
      throws SignatureException
      返回签名的数组,前提是initSign和update

      public final void initVerify(PublicKey publicKey)
      throws InvalidKeyException
      用指定的公钥初始化
      参数:publicKey 验证时用的公钥

      public final boolean verify(byte[] signature)
      throws SignatureException
      验证签名是否有效,前提是已经initVerify初始化
      参数: signature 签名数组

       */
                      import java.security.*;
                      import java.security.spec.*;
                      public class testdsa {
                      public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception {
                              testdsa my=new testdsa();
                      my.run();
                      }
                      public void run()
                      {
                      //数字签名生成密钥
                      //第一步生成密钥对,如果已经生成过,本过程就可以跳过,对用户来讲myprikey.dat要保存在本地
                      //而mypubkey.dat给发布给其它用户
                      if ((new java.io.File("myprikey.dat")).exists()==false) {
                      if (generatekey()==false) {
                      System.out.println("生成密钥对败");
                      return;
                      };
                      }
                      //第二步,此用户
                      //从文件中读入私钥,对一个字符串进行签名后保存在一个文件(myinfo.dat)中
                      //并且再把myinfo.dat发送出去
                      //为了方便数字签名也放进了myifno.dat文件中,当然也可分别发送
                      try {
                      java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
                        PrivateKey myprikey=(PrivateKey)in.readObject();
                      in.close();
                      // java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509);
                       //java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec
                        String myinfo="这是我的信息";    //要签名的信息
                      //用私钥对信息生成数字签名
                      java.security.Signature signet=java.security.Signature.getInstance("DSA");
                      signet.initSign(myprikey);
                      signet.update(myinfo.getBytes());
                      byte[] signed=signet.sign();  //对信息的数字签名
                      System.out.println("signed(签名内容)="+byte2hex(signed));
                      //把信息和数字签名保存在一个文件中
                      java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));
                        out.writeObject(myinfo);
                      out.writeObject(signed);
                      out.close();
                      System.out.println("签名并生成文件成功");
                      }
                      catch (java.lang.Exception e) {
                      e.printStackTrace();
                      System.out.println("签名并生成文件失败");
                      };
                      //第三步
                      //其他人通过公共方式得到此户的公钥和文件
                      //其他人用此户的公钥,对文件进行检查,如果成功说明是此用户发布的信息.
                      //
                      try {
                      java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
                         PublicKey pubkey=(PublicKey)in.readObject();
                      in.close();
                      System.out.println(pubkey.getFormat());
                      in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
                      String info=(String)in.readObject();
                      byte[] signed=(byte[])in.readObject();
                      in.close();
                      java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
                      signetcheck.initVerify(pubkey);
                      signetcheck.update(info.getBytes());
                      if (signetcheck.verify(signed)) {
                      System.out.println("info="+info);
                      System.out.println("签名正常");
                      }
                      else  System.out.println("非签名正常");
                      }
                      catch (java.lang.Exception e) {e.printStackTrace();};
                      }
                      //生成一对文件myprikey.dat和mypubkey.dat---私钥和公钥,
                      //公钥要用户发送(文件,网络等方法)给其它用户,私钥保存在本地
                      public boolean generatekey()
                      {
                      try {
                      java.security.KeyPairGenerator  keygen=java.security.KeyPairGenerator.getInstance("DSA");
                       // SecureRandom secrand=new SecureRandom();
                      // secrand.setSeed("tttt".getBytes()); //初始化随机产生器
                      // keygen.initialize(576,secrand);     //初始化密钥生成器
                      keygen.initialize(512);
                      KeyPair keys=keygen.genKeyPair();
                      //  KeyPair keys=keygen.generateKeyPair(); //生成密钥组
                      PublicKey pubkey=keys.getPublic();
                      PrivateKey prikey=keys.getPrivate();
                      java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));
                        out.writeObject(prikey);
                      out.close();
                      System.out.println("写入对象 prikeys ok");
                      out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
                      out.writeObject(pubkey);
                      out.close();
                      System.out.println("写入对象 pubkeys ok");
                      System.out.println("生成密钥对成功");
                      return true;
                      }
                      catch (java.lang.Exception e) {
                      e.printStackTrace();
                      System.out.println("生成密钥对失败");
                      return false;
                      };
                      }
                      public String byte2hex(byte[] b)
                      {
                      String hs="";
                      String stmp="";
                      for (int n=0;n<b.length;n++)
                      {
                      stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
                      if (stmp.length()==1) hs=hs+"0"+stmp;
                      else hs=hs+stmp;
                      if (n<b.length-1)  hs=hs+":";
                      }
                      return hs.toUpperCase();
                      }
                      }


    2.4. DESede/DES对称算法

    首先生成密钥,并保存(这里并没的保存的代码,可参考DSA中的方法)

    KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);

    SecretKey deskey = keygen.generateKey();

    用密钥加密明文(myinfo),生成密文(cipherByte)

    Cipher c1 = Cipher.getInstance(Algorithm);

    c1.init(Cipher.ENCRYPT_MODE,deskey);

    byte[] cipherByte=c1.doFinal(myinfo.getBytes());

    传送密文和密钥,本文没有相应代码可参考DSA

    .............

    用密钥解密密文

    c1 = Cipher.getInstance(Algorithm);

    c1.init(Cipher.DECRYPT_MODE,deskey);

    byte[] clearByte=c1.doFinal(cipherByte);

    相对来说对称密钥的使用是很简单的,对于JCE来讲支技DES,DESede,Blowfish三种加密术

    对于密钥的保存各传送可使用对象流或者用二进制编码,相关参考代码如下

       SecretKey deskey = keygen.generateKey();
                byte[] desEncode=deskey.getEncoded();
                javax.crypto.spec.SecretKeySpec destmp=new javax.crypto.spec.SecretKeySpec(desEncode,Algorithm);
                   SecretKey mydeskey=destmp;

    相关API

    KeyGenerator 在DSA中已经说明,在添加JCE后在instance进可以如下参数

    DES,DESede,Blowfish,HmacMD5,HmacSHA1

    javax.crypto.Cipher 加/解密器

    public static final Cipher getInstance(java.lang.String transformation)
                throws java.security.NoSuchAlgorithmException,
                NoSuchPaddingException

    返回一个指定方法的Cipher对象

    参数:transformation 方法名(可用 DES,DESede,Blowfish)

    public final void init(int opmode, java.security.Key key)
    throws java.security.InvalidKeyException

    用指定的密钥和模式初始化Cipher对象

    参数:opmode 方式(ENCRYPT_MODE, DECRYPT_MODE, WRAP_MODE,UNWRAP_MODE)

    key 密钥

    public final byte[] doFinal(byte[] input)
                throws java.lang.IllegalStateException,
                IllegalBlockSizeException,
                BadPaddingException
                

    对input内的串,进行编码处理,返回处理后二进制串,是返回解密文还是加解文由init时的opmode决定

    注意:本方法的执行前如果有update,是对updat和本次input全部处理,否则是本inout的内容

    /*
                安全程序 DESede/DES测试
                */
                import java.security.*;
                import javax.crypto.*;
                public class testdes {
                public static void main(String[] args){
                testdes my=new testdes();
                my.run();
                }
                public  void run() {
                //添加新安全算法,如果用JCE就要把它添加进去
                Security.addProvider(new com.sun.crypto.provider.SunJCE());
                String Algorithm="DES"; //定义 加密算法,可用 DES,DESede,Blowfish
                String myinfo="要加密的信息";
                try {
                //生成密钥
                KeyGenerator keygen = KeyGenerator.getInstance(Algorithm);
                SecretKey deskey = keygen.generateKey();
                //加密
                System.out.println("加密前的二进串:"+byte2hex(myinfo.getBytes()));
                System.out.println("加密前的信息:"+myinfo);
                Cipher c1 = Cipher.getInstance(Algorithm);
                c1.init(Cipher.ENCRYPT_MODE,deskey);
                byte[] cipherByte=c1.doFinal(myinfo.getBytes());
                System.out.println("加密后的二进串:"+byte2hex(cipherByte));
                //解密
                c1 = Cipher.getInstance(Algorithm);
                c1.init(Cipher.DECRYPT_MODE,deskey);
                byte[] clearByte=c1.doFinal(cipherByte);
                System.out.println("解密后的二进串:"+byte2hex(clearByte));
                System.out.println("解密后的信息:"+(new String(clearByte)));
                }
                catch (java.security.NoSuchAlgorithmException e1) {e1.printStackTrace();}
                catch (javax.crypto.NoSuchPaddingException e2) {e2.printStackTrace();}
                catch (java.lang.Exception e3) {e3.printStackTrace();}
                }
                public String byte2hex(byte[] b) //二行制转字符串
                {
                String hs="";
                String stmp="";
                for (int n=0;n<b.length;n++)
                {
                stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
                if (stmp.length()==1) hs=hs+"0"+stmp;
                else hs=hs+stmp;
                if (n<b.length-1)  hs=hs+":";
                }
                return hs.toUpperCase();
                }
                }


    2.5. Diffie-Hellman密钥一致协议

    公开密钥密码体制的奠基人Diffie和Hellman所提出的 "指数密钥一致协议"(Exponential Key Agreement Protocol),该协议不要求别的安全性先决条件,允许两名用户在公开媒体上交换信息以生成"一致"的,可以共享的密钥。在JCE的中实现用户alice生成DH类型的密钥对,如果长度用1024生成的时间请,推荐第一次生成后保存DHParameterSpec,以便下次使用直接初始化.使其速度加快

    System.out.println("ALICE: 产生 DH 对 ...");
                KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
                aliceKpairGen.initialize(512);
                KeyPair aliceKpair = aliceKpairGen.generateKeyPair();

    alice生成公钥发送组bob

    byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

    bob从alice发送来的公钥中读出DH密钥对的初始参数生成bob的DH密钥对

    注意这一步一定要做,要保证每个用户用相同的初始参数生成的

       DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();
                KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
                bobKpairGen.initialize(dhParamSpec);
                KeyPair bobKpair = bobKpairGen.generateKeyPair();

    bob根据alice的公钥生成本地的DES密钥

       KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
                bobKeyAgree.init(bobKpair.getPrivate());
                bobKeyAgree.doPhase(alicePubKey, true);
                SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");

    bob已经生成了他的DES密钥,他现把他的公钥发给alice,

          byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

    alice根据bob的公钥生成本地的DES密钥

           ,,,,,,解码
                KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
                aliceKeyAgree.init(aliceKpair.getPrivate());
                aliceKeyAgree.doPhase(bobPubKey, true);
                SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");

    bob和alice能过这个过程就生成了相同的DES密钥,在这种基础就可进行安全能信

    常用API

    java.security.KeyPairGenerator 密钥生成器类
    public static KeyPairGenerator getInstance(String algorithm)
    throws NoSuchAlgorithmException
    以指定的算法返回一个KeyPairGenerator 对象
    参数: algorithm 算法名.如:原来是DSA,现在添加了 DiffieHellman(DH)

    public void initialize(int keysize)
    以指定的长度初始化KeyPairGenerator对象,如果没有初始化系统以1024长度默认设置
    参数:keysize 算法位长.其范围必须在 512 到 1024 之间,且必须为 64 的倍数
    注意:如果用1024生长的时间很长,最好生成一次后就保存,下次就不用生成了

    public void initialize(AlgorithmParameterSpec params)
    throws InvalidAlgorithmParameterException
    以指定参数初始化

    javax.crypto.interfaces.DHPublicKey
    public DHParameterSpec getParams()
    返回
    java.security.KeyFactory

    public static KeyFactory getInstance(String algorithm)
    throws NoSuchAlgorithmException
    以指定的算法返回一个KeyFactory
    参数: algorithm 算法名:DSH,DH

    public final PublicKey generatePublic(KeySpec keySpec)
    throws InvalidKeySpecException
    根据指定的key说明,返回一个PublicKey对象

    java.security.spec.X509EncodedKeySpec
    public X509EncodedKeySpec(byte[] encodedKey)
    根据指定的二进制编码的字串生成一个key的说明
    参数:encodedKey 二进制编码的字串(一般能过PublicKey.getEncoded()生成)
    javax.crypto.KeyAgreement 密码一至类

    public static final KeyAgreement getInstance(java.lang.String algorithm)
    throws java.security.NoSuchAlgorithmException
    返回一个指定算法的KeyAgreement对象
    参数:algorithm 算法名,现在只能是DiffieHellman(DH)

    public final void init(java.security.Key key)
    throws java.security.InvalidKeyException
    用指定的私钥初始化
    参数:key 一个私钥

    public final java.security.Key doPhase(java.security.Key key,
    boolean lastPhase)
    throws java.security.InvalidKeyException,
    java.lang.IllegalStateException
    用指定的公钥进行定位,lastPhase确定这是否是最后一个公钥,对于两个用户的
    情况下就可以多次定次,最后确定
    参数:key 公钥
    lastPhase 是否最后公钥

    public final SecretKey generateSecret(java.lang.String algorithm)
    throws java.lang.IllegalStateException,
    java.security.NoSuchAlgorithmException,
    java.security.InvalidKeyException
    根据指定的算法生成密钥
    参数:algorithm 加密算法(可用 DES,DESede,Blowfish)

    */
                import java.io.*;
                import java.math.BigInteger;
                import java.security.*;
                import java.security.spec.*;
                import java.security.interfaces.*;
                import javax.crypto.*;
                import javax.crypto.spec.*;
                import javax.crypto.interfaces.*;
                import com.sun.crypto.provider.SunJCE;
                public class testDHKey {
                public static void main(String argv[]) {
                try {
                testDHKey my= new testDHKey();
                my.run();
                } catch (Exception e) {
                System.err.println(e);
                }
                }
                private void run() throws Exception {
                Security.addProvider(new com.sun.crypto.provider.SunJCE());
                System.out.println("ALICE: 产生 DH 对 ...");
                KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
                aliceKpairGen.initialize(512);
                KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); //生成时间长
                // 张三(Alice)生成公共密钥 alicePubKeyEnc 并发送给李四(Bob) ,
                //比如用文件方式,socket.....
                byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
                //bob接收到alice的编码后的公钥,将其解码
                KeyFactory bobKeyFac = KeyFactory.getInstance("DH");
                X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec  (alicePubKeyEnc);
                PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);
                System.out.println("alice公钥bob解码成功");
                // bob必须用相同的参数初始化的他的DH KEY对,所以要从Alice发给他的公开密钥,
                //中读出参数,再用这个参数初始化他的 DH key对
                //从alicePubKye中取alice初始化时用的参数
                DHParameterSpec dhParamSpec = ((DHPublicKey)alicePubKey).getParams();
                KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
                bobKpairGen.initialize(dhParamSpec);
                KeyPair bobKpair = bobKpairGen.generateKeyPair();
                System.out.println("BOB: 生成 DH key 对成功");
                KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
                bobKeyAgree.init(bobKpair.getPrivate());
                System.out.println("BOB: 初始化本地key成功");
                //李四(bob) 生成本地的密钥 bobDesKey
                bobKeyAgree.doPhase(alicePubKey, true);
                SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");
                System.out.println("BOB: 用alice的公钥定位本地key,生成本地DES密钥成功");
                // Bob生成公共密钥 bobPubKeyEnc 并发送给Alice,
                //比如用文件方式,socket.....,使其生成本地密钥
                byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
                System.out.println("BOB向ALICE发送公钥");
                // alice接收到 bobPubKeyEnc后生成bobPubKey
                // 再进行定位,使aliceKeyAgree定位在bobPubKey
                KeyFactory aliceKeyFac = KeyFactory.getInstance("DH");
                x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
                PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);
                System.out.println("ALICE接收BOB公钥并解码成功");
                ;
                KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
                aliceKeyAgree.init(aliceKpair.getPrivate());
                System.out.println("ALICE: 初始化本地key成功");
                aliceKeyAgree.doPhase(bobPubKey, true);
                // 张三(alice) 生成本地的密钥 aliceDesKey
                SecretKey aliceDesKey = aliceKeyAgree.generateSecret("DES");
                System.out.println("ALICE: 用bob的公钥定位本地key,并生成本地DES密钥");
                if (aliceDesKey.equals(bobDesKey)) System.out.println("张三和李四的密钥相同");
                //现在张三和李四的本地的deskey是相同的所以,完全可以进行发送加密,接收后解密,达到
                //安全通道的的目的
                /*
                * bob用bobDesKey密钥加密信息
                */
                Cipher bobCipher = Cipher.getInstance("DES");
                bobCipher.init(Cipher.ENCRYPT_MODE, bobDesKey);
                String bobinfo= "这是李四的机密信息";
                System.out.println("李四加密前原文:"+bobinfo);
                byte[] cleartext =bobinfo.getBytes();
                byte[] ciphertext = bobCipher.doFinal(cleartext);
                /*
                * alice用aliceDesKey密钥解密
                */
                Cipher aliceCipher = Cipher.getInstance("DES");
                aliceCipher.init(Cipher.DECRYPT_MODE, aliceDesKey);
                byte[] recovered = aliceCipher.doFinal(ciphertext);
                System.out.println("alice解密bob的信息:"+(new String(recovered)));
                if (!java.util.Arrays.equals(cleartext, recovered))
                throw new Exception("解密后与原文信息不同");
                System.out.println("解密后相同");
                }
                }
    posted @ 2008-10-13 19:31 bt下载| 编辑 收藏

    关于应用服务器和web服务器的整合,有很多的资料了,可是都讲的半生不熟的。根据这几天整合tomcat 和 iis 的经验,再次聊聊这个话题。

    首先我们应该对应用服务器和web服务器有一个清晰的概念。所谓的应用服务器,就是提供应用的服务器,这里的应用有很多,比如java应用,ruby 应用,或者 c#应用。

    那么什么是web服务器呢?就是提供了web功能的服务器,主要就是http服务,包括图片的下载,等等一系列和web相关的。

    好吧,你会问为什么我们不能直接使用应用服务器呢?应用服务器也提供了http服务,比如tomcat。

    那么我们从实际出发。当你浏览一个网页的时候,什么情况下你会觉得速度很慢?我们仅仅考虑页面本身。那当然是图片越多显示得越慢。

    好吧,我们至少认识到一点,一些静态资源,例如图片,会严重影响页面打开的速度。当然,这仅仅是一个方面。

    那么web服务器有什么用呢?web服务器一个优点就是在处理静态信息上。例如一些静态的html,图片,等等其他静态的东西。

    那为什么tomcat不能具备这些优点?这个问题我们可以换一个说法:为什么会计不能做市场营销呢?

    所以嘛,大家要分工明确,应用服务器就做好它该做的:如何解释一个jsp,如何处理java文件等等,做好这一点就足够了。而web服务器也做好它该做的:如何快速向浏览器传递信息,如何快速地让浏览器下载图片。

    那你又问了,那为啥tomcat还提供一个http服务?那不是让你开发方便嘛!千万别把tomcat的http服务当成是一个web服务器。

    说了这么多,那么我们对应用服务器和web服务器的整合也应该心里有数了。就拿tomcat和iis整合来说事吧!

    我们到底想干什么呢?很明显,我们想让tomcat 处理对 java应用的请求,而iis应该处理图片,css 等等其他静态资源的事情。

    具体的细节不谈了,无非就是配置 ispai_redirect 这个东东。因为我们主要说的分工问题,所以还是说说这个 uriworkermap.properties 文件。

    这个文件就是处理分工的用的。例如我定义成如下这个样子:
    /www.5a520.cn /eshop/*.do=ajp13
    /www.5a520.cn /eshop/dwr/interface/*=ajp13
    /www.5a520.cn /eshop/dwr/*=ajp13
    /www.bt285.cn /eshop/js/*=ajp13

    那么就告诉了 isapi_redirect , 以上4种请求,都交给tomcat处理。
    那么其他的请求呢?当然是交给 iis了。

    如果我定义成这个样子:
    /* = ajp13

    这下可惨了,iis被你浪费了,就好像你招聘了一个会计和一个推销的人员,但是让会计干财务的活之外,还干了推销。而推销人员给闲置了。

    至于 uriworkermap.properties  的详细配置,可以参考 tomcat 网站,上面有详细的讲解。


    两种服务器的整合虽然不难,但是如果不明白其中的意义和原理,一旦项目配置有所变化,那就是没有葫芦就画不出来瓢了。
    posted @ 2008-10-08 21:17 bt下载| 编辑 收藏

    mysql slow log 是用来记录执行时间较长(超过long_query_time秒)的sql的一种日志工具.

    启用 slow log

    有两种启用方式:
    1, 在my.cnf 里 通过 log-slow-queries[=file_name]
    2, 在mysqld进程启动时,指定--log-slow-queries[=file_name]选项

    比较的五款常用工具

    mysqldumpslow, mysqlsla, myprofi, mysql-explain-slow-log, mysqllogfilter


    mysqldumpslow, mysql官方提供的慢查询日志分析工具. 输出图表如下:
    主要功能是, 统计不同慢sql的
    出现次数(Count), 
    执行最长时间(Time), 
    累计总耗费时间(Time), 
    等待锁的时间(Lock), 
    发送给客户端的行总数(Rows), 
    扫描的行总数(Rows), 
    用户以及sql语句本身(抽象了一下格式, 比如 limit 1, 20 用 limit N,N 表示).

    mysqlsla, hackmysql.com推出的一款日志分析工具(该网站还维护了 mysqlreport, mysqlidxchk 等比较实用的mysql工具)
    整体来说, 功能非常强大. 数据报表,非常有利于分析慢查询的原因, 包括执行频率, 数据量, 查询消耗等.

    格式说明如下:
    总查询次数 (queries total), 去重后的sql数量 (unique)
    输出报表的内容排序(sorted by)
    最重大的慢sql统计信息, 包括 平均执行时间, 等待锁时间, 结果行的总数, 扫描的行总数.

    Count, sql的执行次数及占总的slow log数量的百分比.
    Time, 执行时间, 包括总时间, 平均时间, 最小, 最大时间, 时间占到总慢sql时间的百分比.
    95% of Time, 去除最快和最慢的sql, 覆盖率占95%的sql的执行时间.
    Lock Time, 等待锁的时间.
    95% of Lock , 95%的慢sql等待锁时间.
    Rows sent, 结果行统计数量, 包括平均, 最小, 最大数量.
    Rows examined, 扫描的行数量.
    Database, 属于哪个数据库
    Users, 哪个用户,IP, 占到所有用户执行的sql百分比

    Query abstract, 抽象后的sql语句
    Query sample, sql语句

    除了以上的输出, 官方还提供了很多定制化参数, 是一款不可多得的好工具.

    mysql-explain-slow-log, 德国人写的一个perl脚本.
    http://www.willamowius.de/mysql-tools.html

    功能上有点瑕疵, 不仅把所有的 slow log 打印到屏幕上, 而且统计也只有数量而已. 不推荐使用.
    mysql-log-filter, google code上找到的一个分析工具.提供了 python 和 php 两种可执行的脚本.
    http://code.google.com/p/mysql-log-filter/
    功能上比官方的mysqldumpslow, 多了查询时间的统计信息(平均,最大, 累计), 其他功能都与 mysqldumpslow类似.
    特色功能除了统计信息外, 还针对输出内容做了排版和格式化, 保证整体输出的简洁. 喜欢简洁报表的朋友, 推荐使用一下.
    myprofi, 纯php写的一个开源分析工具.项目在 sourceforge 上.
    http://myprofi.sourceforge.net/

    功能上, 列出了总的慢查询次数和类型, 去重后的sql语句, 执行次数及其占总的slow log数量的百分比.
    从整体输出样式来看, 比mysql-log-filter还要简洁. 省去了很多不必要的内容. 对于只想看sql语句及执行次数的用户来说, 比较推荐.

    总结

    工具/功能 一般统计信息 高级统计信息 脚本 优势
    mysqldumpslow 支持 不支持 perl mysql官方自带
    mysqlsla 支持 支持 perl 功能强大,数据报表齐全,定制化能力强.
    mysql-explain-slow-log 支持 不支持 perl
    mysql-log-filter 支持 部分支持 python or php 不失功能的前提下,保持输出简洁
    myprofi 支持 不支持 php 非常精简
    posted @ 2008-10-07 23:33 bt下载| 编辑 收藏

    一、Java编码是怎么回事?

    对于使用中文以及其他非拉丁语系语言的开发人员来说,经常会遇到字符集编码问题。对于Java语言来说,在其内部使用的是UCS2编码(2个字节的Unicode编码)。这种编码并不属于某个语系的语言编码,它实际上是一种编码格式的世界语。在这个世界上所有可以在计算机中使用的语言都有对应的UCS2编码

    正是因为Java采用了UCS2,因此,在Java中可以使用世界上任何国家的语言来为变量名、方法名、类起名,如下面代码如下:


    class 中国
    {
        
    public String 雄起()
        {
             
    return "中国雄起";
        }
    }

    中国 祖国 
    = new 中国();
    System.out.println(祖国.雄起());

        哈哈,是不是有点象“中文编程”。实际上,也可以使用其他的语言来编程,如下面用韩文和日文来定义个类:

    class 수퍼맨
    {
        
    public void スーパーマン() {  }
    }

        实际上,由于Java内部使用的是UCS2编码格式,因为,Java并不关心所使用的是哪种语言,而只要这种语言在UCS2中有定义就可以。

        UCS2编码中为不同国家的语言进行了分页,这个分页也叫“代码页”或“编码页”。中文根据包含中文字符的多少,分了很多代码页,如cp935cp936等,然而,这些都是在UCS2中的代码页名,而对于操作系统来说,如微软的windows,一开始的中文编码为GB2312,后来扩展成了GBK。其实GBKcp936是完全等效的,用它们哪个都行。

    二、Java编码转换

       
    上面说了这么多,在这一部分我们做一些编码转换,看看会发生什么事情。

        先定义一个字符串变量:

        String gbk = "
    中国"; // “中国”在Java内部是以UCS2格式保存的

        用下面的语言输出一定会输出中文:

    System.out.println(gbk);

        实现上,当我们从IDE输入“中国”时,用的是java源代码文件保存的格式,一般是GBK,有时也可是utf-8,而在Java编译程序时,会不由分说地将所有的编码格式转换成utf-8编码,读者可以用UltraEdit或其他的二进制编辑器打开上面的“中国.class”,看看所生成的二进制是否有utf-8的编码(utf-8ucs2之间的转换非常容易,因为utf-8ucs2之间是用公式进行转换的,而不是到代码页去查,这就相当于将二进制转成16进制一样,4个字节一组)。如“中国”的utf-8编码按着GBK解析就是“涓  浗”。如下图所示。



    如果使用下面的语言可以获得“中国”的utf-8字节,结果是6(一个汉字由3个字节组成)

    System.out.println(gbk.getBytes("utf-8").length);

    下面的代码将输出“涓  浗”。

    System.out.println(new String(gbk.getBytes("utf-8"), "gbk"));   

    由于将“中国“的utf-8编码格式按着gbk解析,所以会出现乱码。

    如果要返回中文的UCS2编码,可以使用下面的代码:

    System.out.println(gbk.getBytes("unicode")[2]);

    System.out.println(gbk.getBytes("unicode")[3]);

    前两个字节是标识位,要从第3个字节开始。还有就是其他的语言使用的编码的字节顺序可能不同,如在C#中可以使用下面的代码获得“中国“的UCS2编码:

    String s = "
    ";

    MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[0].ToString());

    MessageBox.Show(ASCIIEncoding.Unicode.GetBytes(s)[1].ToString());

        使用上面的java代码获得的“中“的16进制UCS2编码为4E2D,而使用C#获得的相应的ucs2编码为2D4E,这只是C#Java编码内部使用的问题,并没有什么关系。但在C#Java互操作时要注意这一点。

        如果使用下面的java编码将获得16进制的“中”的GBK编码:

    System.out.println(Integer.toHexString(0xff & xyz.getBytes("gbk")[0]));

    System.out.println(Integer.toHexString(0xff & xyz.getBytes("gbk")[1]));

    “中”的ucs2编码为2D4EGBK编码为D6D0

        读者可访问如下的url自行查验:

        http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT

        当然,感兴趣的读者也可以试试其他语言的编码,如“人类”的韩语是“인간의”,如下面的代码将输出“인간의”的cp949ucs2编码,其中cp949是韩语的代码页。


    String korean = "인간의"// 共三个韩文字符,我们只测试第一个“인”

    System.out.println(Integer.toHexString(
    0xff & korean.getBytes("unicode")[2]));

    System.out.println(Integer.toHexString(
    0xff & korean.getBytes("unicode")[3]));

    System.out.println(Integer.toHexString(
    0xff & korean.getBytes("Cp949")[0]));

    System.out.println(Integer.toHexString(
    0xff & korean.getBytes("Cp949")[1]));

     

    上面代码的输出结果如下:

    c7

    78

    c0

    ce

        也就是说“”的ucs2编码为C778cp949的编码为C0CE,要注意的是,在cp949中,ucs2编码也有C0CE,不要弄混了。读者可以访问下面的url来验证:

    http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT

    http://www.bt285.cn/content.php?id=1196863

    Java支持的编码格式

    三、属性文件

    Java中的属性文件只支持iso-8859-1编码格式,因此,要想在属性文件中保存中文,就必须使用UCS2编码格式("uxxxx),因此,出现了很多将这种编码转换成可视编码和工具,如Eclipse中的一些属性文件编辑插件。

    实际上,"uxxxx编码格式在javaC#中都可以使用,如下面的语句所示:

    String name= ""u7528"u6237"u540d"u4e0d"u80fd"u4e3a"u7a7a" ;

    System.out.println(name);

        上面代码将输出“用户名不能为空”的信息。将"uxxxx格式显示成中文非常简单,那么如何将中文还原成"uxxxxx格式呢?下面的代码完成了这个工作:


    String ss = "用户名不能为空";
    byte[] uncode = ss.getBytes("Unicode");
    int x = 0xff;
    String result 
    ="";
    for(int i= 2; i < uncode.length; i++)
    {
        
    if(i % 2 == 0) result += "\\u";
        String abc 
    = Integer.toHexString(x & uncode[i]);            
        result 
    += abc.format("%2s", abc).replaceAll(" ""0");               
    }
    System.out.println(result);

     

        上面的代码将输出如下结果:


    \u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a

        好了,现在可以利用这个技术来实现一个属性文件编辑器了。

    四、Web中的编码问题

        大家碰到最多的编码问题就是在Web应用中。先让我们看看下面的程序:

     

    <!--  main.jsp  -->

      
    <%@ page language="java"  pageEncoding="utf-8"%>

      
    <html>
          
    <head>

          
    </head>

          
    <body>
              
    <form action="servlet/MyPost" method="post">
                  
    <input type="text" name="user" />
                  
    <p/>
                  
    <input type="submit"  value="提交"/>
              
    </form>

          
    </body>
      
    </html>


        下面是个Servlet

      package servlet;

      import java.io.IOException;
      import java.io.PrintWriter;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;

      
    public class MyPost extends HttpServlet
      {

          
    public void doPost(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException
          {
              String user 
    = request.getParameter("user");
              System.
    out.println(user);
          }
      }


        如果中main.jsp中输入中文后,向MyPost提交,在控制台中会输出“中国”,一看就是乱码。如果将IE的当前编码设成其他的,如由utf-8改为gbk,仍然会出现乱码,只是乱得不一样而已。这是因为客户端提交数据时是根据浏览器当前的编码格式来提交的,如浏览器当前为gbk编码,就以gbk编码格式来提交。 这本身是不会出现乱码的,问题就出在Web服务器接收数据的时候,HttpServletRequest在将客户端传来的数据转成ucs2上出了问题。在默认情况下,是按着iso-8859-1编码格式来转的,而这种编码格式并不支持中文,所以也就无法正常显示中文了,解决这个问题的方法是用和客户端浏览器当前编码格式一致的编码来转换,如果是utf-8,则在doPost方法中应该用以下的语句来处理:

        request.setCharacterEncoding("utf-8");

        为了对每一个Servlet都起作用,可以将上面的语句加到filter里。

        另外,我们一般使用象MyEclipse一样的IDE来编写jsp文件,这样的工具会根据pageEncoding属性将jsp文件保存成相应的编码格式,但如果要使用象记事本一样的简单的编辑器来编写jsp文件,如果pageEncodingutf-8,而在默认时,记事本会将文件保存成iso-8859-1ascii)格式,但在myeclipse里,如果文件中有中文,它是不允许我们保存成不支持中文的编码格式的,但记事本并不认识jsp,因此,这时在ie中就无法正确显示出中文了。除非用记事本将其保存在utf-8格式。如下图:


     

    http://blog.csdn.net/wangdei/archive/2008/10/07/3030758.aspx
    posted @ 2008-10-07 22:36 bt下载 阅读(500) | 评论 (0)编辑 收藏

         摘要: 在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading 为true的话,要在应用层内把关系集合都初始化,如 company.getEmployees(),否则Hibernate抛session already closed Exception;    Op...  阅读全文
    posted @ 2008-10-05 15:01 bt下载| 编辑 收藏

    本文以http://www.bt285.cn 网站为例,为刚做完第一阶段的性能优化作一个总结,希望能给大家抛砖引玉。
    我的这个网站刚上线不久,因为时间比较仓促,所以先发布,再来优化性能。经过优化后从数据看是非常明显的,不过你访问的时候可能还是比较慢,因为目前我的服务器带宽只有电信2M独享,呵呵,见笑了吧!穷,没办法。这个网站主要以分享图片为主题,功能比较简单。将来也不会做的复杂,因为你从名字中就可以看出 eaful , easy is beautiful. 呵呵。

    我的性能优化分两个阶段实现:
    第一阶段:前台性能优化
    主要指减小页面输出流,完善客户端cache策略。
    第二阶段:后台性能优化
    主要包括数据库优化,cache优化,算法优化和Page Stream Cache。
    目前完成了第一阶段,第二阶段估计在10月国庆节完成。下面详细介绍第一阶段的性能优化。

    1)为静态文件独立域名
    因为我的网站主要是图片,每张图片就有50-60K,以后访问量大的时候会独立一台图片服务器,以减轻应用服务器的压力,所以为静态文件的URL独立一个二级域名(bt.bt285.cn),为什么不独立一个顶级域名,因为考虑到cookie共享等因素,比如有些图片必须登陆后访问。

    2)优化客户端cache
    比如一些静态文件,如图片,css文件,js文件等不用每次都更新,所以使用永久cache。方法是在response头中设置Cache-Control 为max-age=99999999,大概缓存3年左右吧。如果css文件修改了怎么办呢,所以这里的关键点是在URL中放入版本参数。如:http://www.bt285.cn/content.php?id=1196863 v1222319367387其中v1222319367387是版本信息,当文件修改后,就修改这个版本号输出链接。这样浏览器发现这是一个新URL,所以会重新请求。
    这里要注意的是只对有含有版本号的URL缓存,否则一旦客户端永久cache你就不能让他何时更新了。如更改了js文件,客户端没有更新,这样可能报错了你也不知道。
    对图片的链接,就算不包含版本号,也至少让他缓存到凌晨过期(使用Expires头)。这样不会每次刷新页面都更新图片。而且就算图片有修改,最多也是晚一天看到罢了。

    3)合并css,js文件
    我本来有3个css文件,5个js文件。首次打开的时候要请求8次,虽然现代浏览器支持长连接,但还是没有放到一个文件中快,只要下载一次就够了。我把css文件合并为一个,js文件合并为一个,效果很明显。我这里使用的合并不是发布期手工合并,而是运行期根据配置合并,在应用启动时合并载入在内存中。
    谢谢quake wang的提醒:把css中的小图片合成一张大图片,然后在css中调节显示位置。但这里需要注意的是修改图片时,要保持原图片的位置不变,并且不影响其他图片的位置。我目前的做法是给每个小图片一定的空余空间,如一个30*30px的图片,我给它在大图中的空间是50×50px,这样的话以后这个图片需要变大的话,不会影响右边和下边的图片了。如果超过50×50px,就给它100×100px,反正是某个整数的倍数,这样便于在css中调节显示位置。

    4)压缩文本输出
    css文件,js文件,html文件都是文本输出,都可以用gzip压缩,而且有立竿见影的效果。我的200K的js文件压缩后只有49K了,还是很满意的。也可以考虑在压缩前用ShrinkSafe先瘦身,它可以把注释去掉,缩短变量名的方法减小js文件,以我200K的js文件为例,瘦身后只有 100K了,但是用gzip压缩,只能压到39K,感觉效果不是很明显,而且据说有eval的bug,所以我这里没有采用。还可以考虑对css文件, html文件进行瘦身,比如删除两边的空格,回车等,但我觉的使用了gzip压缩,删除和不删除空格,压缩效果应该不会相差太大,所以也没有采用。

    以下是我在firefox中使用firebug测试性能的截图,优化前和优化后的效果比较。

    优化前:


    优化后:


    以上是firfox首次打开http://www.bt285.cn/content.php?id=1196863的截图,整整提高了1秒多。第二次打开就更快了,几乎所有东西静态文件都在客户端有缓存。

    也可以使用http://www.bt285.cn/1196863/pic/ 甜性涩爱 来分析页面下载性能。
    优化前:
    Object Size Totals
    Object type Size (bytes) Download @ 56K (seconds) Download @ T1 (seconds)
    HTML: 46442 9.46 0.45
    HTML Images: 10354 2.46 0.45
    CSS Images: 19620 6.31 2.50
    Total Images: 29974 8.77 2.95
    Javascript: 186931 38.66 2.39
    CSS: 16635 4.12 0.89
    Multimedia: 0 0.00 0.00
    Other: 0 0.00 0.00

    优化后:
    Object Size Totals
    Object type Size (bytes) Download @ 56K (seconds) Download @ T1 (seconds)
    HTML: 45412 9.25 0.44
    HTML Images: 10354 2.46 0.45
    CSS Images: 0 0.00 0.00
    Total Images: 10354 2.46 0.45
    Javascript: 47708 9.71 0.45
    CSS: 4028 1.00 0.22
    Multimedia: 0 0.00 0.00
    Other: 0 0.00 0.00

    优化前和优化后的效果还是很明显的,但是js文件中使用了prototype.js这个js文件,有126K,以后有时间的话会把这个文件替换掉。
    posted @ 2008-10-01 15:40 bt下载| 编辑 收藏