博文

目前显示的是 2014的博文

关于google drive及google docs的一些吐槽

据说在国外,google docs是非常流行的。我最近4个月因为工作原因天天要用它,下面吐吐槽优点1。搜索功能强大。首先它支持全文检索。如果我的电脑里有大量的文档,那么全文检索是很重要的功能。相比与操作系统内置的全文检索来说,google drive的全文检索速度很快(一秒内出结果),而且在查全率、结果排序上也绝对比操作系统内置的要好的多。和grep相比,自然也是好的多。因为grep对二进制文件几乎不支持(比如pdf/ms word),而且当文件个数多的时候查找速度极慢。 它的全文搜索甚至强大到可以按照语义搜索,比如查找有山的照片。其次,它支持很复杂的谓词。具体文档请见这里:https://developers.google.com/drive/web/search-parameters。 举些例子:title='xxx.txt' 查找文件名为xxx.txt的文件mimeType contains 'image/' 查找所有的图片2。 google docs 免费且易用。确实能在一定程度上取代MS office,节省了软件购买成本。3。 支持外链。不光图片可以外链,html/css/js都可以。我可以直接放一个静态的网站上去。但是外链功能有两个问题目前还不支持自定义域名,只能使用google的域名。Google会自动封禁含有版权风险的内容。不知道它是怎么判断的,总之如果它觉得可能是盗版,那么就不能外链。缺点1。 不能指定目录搜索。比如我想在"2014"这个文件夹里搜索"月报",它会把别的文件夹里的也搜出来。它的WEB UI的搜索不能指定文件夹名,永远在能在所有文件夹里面一起搜。解决办法是:自己写个工具通过api来搜。2。 文件可重名。同一个文件夹下,可以有两个同名的文件。这个功能看似很强大,其实很恶心。这会让同步工具陷入两难的境地,它在同步的时候必须给重名的文件强制重命名,并且很小心的维护好和原来文件的对应关系,否则稍有差错就会导致文件内容被错误的覆盖,然后被用户骂死。甚至连google自己都栽在这样的bug上了。如果某个被公开发布到web上的目录下有两个同名文件,那么这两个文件在web的列表中都会消失,而且无法通过web直接访问。3。 google docs文件不能同步到本地。google…

Linux程序链接时-lpthread对程序正确性的影响

理论上来说,多线程程序在链接时应该加上-lpthread或者-pthread。实际上很多时候忘记加这个也能链接过去,最近我线上的一个重要服务经常卡死,CPU使用率很高。用pstack看,经常是停留在这样的地方:
# 0x0000003a21e0e054 in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x0000003a21e0bca1 in pthread_cond_signal@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#2 0x00007f04f8e0696d in __db_pthread_mutex_unlock () from /usr/lib64/libdb-4.7.so
#3 0x00007f04f8e0655d in __db_tas_mutex_unlock () from /usr/lib64/libdb-4.7.so
#4 0x00007f04f8ea6b8e in __db_cursor_int () from /usr/lib64/libdb-4.7.so
#5 0x00007f04f8ebd9af in __db_cursor () from /usr/lib64/libdb-4.7.so
#6 0x00007f04f8ebe2c0 in __db_get () from /usr/lib64/libdb-4.7.so
#7 0x00007f04f8ebe63b in __db_get_pp () from /usr/lib64/libdb-4.7.so
大部分CPU都被__db_tas_mutex_unlock和__db_tas_mutex_lock这两个函数占去了。按理说unlock一个mutex不该占用太多cpu才对。(后来我发现这是bdb的mutex的实现太畸形太挫了)
我在网上发现有个工程师遇到了和我类似的问题
http://www.jimmo.org/threads-blocked-in-pthread_cond_signal-on-linux/ 他说如果忘记链接到pthread库,可能导致条件变量所依赖的mutex没有被正确初始化,而导致程序死锁等。理论上来说是这样的,但是实际上我没有办法重现作者的实验。
我发现libdb-4.7.so中pt…

ATS的HTTPS握手失败的排错经历

我用ATS搭了一个测试网站,然后用curl访问的时候发现CentOS 6可以访问,但是CentOS4就不行。CentOS 4下curl报告:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure然后我用openssl s_client -connect myhost.com:443 -state -debug -tls1 -msg看到的message回复是这样:read from 0xb644fc0 [0xb689760] (5 bytes => 5 (0x5))
0000 - 15 03 01 00 02 .....
read from 0xb644fc0 [0xb689765] (2 bytes => 2 (0x2))
0000 - 02 28其中0x15代表的是alert,而0x28代表的handshake failure然后我在CentOS6下测试用sslv3去连接,发现也不行。curl会报告Cannot communicate securely with peer: no common encryption algorithm(s).我的这个curl用的是NSS而不是Openssl。后来,我找到了一个网站,https://www.ssllabs.com/ssltest/, 可以在线检查ssl server的SSL兼容性。它提示说我,我这个测试服务器只有使用SNI的才能连接。于是我恍然大悟啊。ATS的配置文件ssl_multicert.config中,我以前是这么写的ssl_cert_name=/etc/trafficserver/ssl/server.crt ssl_key_name=/etc/trafficserver/ssl/server.key需要改成:dest_ip=* ssl_cert_name=/etc/trafficserver/ssl/server.crt ssl_key_name=/etc/trafficserver/ssl/server.key其中dest_ip=*的意思是The corresponding certificate will be used as the global default…

当ATS遇上curl: 记ATS的一次故障排查经历

不是最近懒了不写blog,而是每天到家都10点以后了,实在累得没力气。这周花了很多时间排查一个bug。我刚做了一项架构升级,把某个项目所用的http server换成了ATS。这种小破事儿按理说1-2天就可以完成,结果耗费了我3-4周。我把http server替换成ATS后,放在线上用真实流量一跑,发现性能跟不上。大部分请求(超过70%)都因为处理超时而返回5xx类型的错误。而我把压力降低到每秒只有50-100个请求,情况还是如此。在我们这套系统的架构中,ATS后面还有一个后端服务器,ATS主要充当的是反向代理的作用。client <-------> ATS <-------> 后端而经线上测试发现,从client到ATS之间有1万多个已建立(established)的TCP连接,从ATS到后端之间也是。这是极不正常的。因为我们每秒的请求数很低啊!!!!在我们的设计中,ATS和后端之间是短连接,它每收到一个请求都会去连后端,用完后关闭。我第一个反应是,会不会是ATS用完这个连接之后没有关??我给后端的服务进程加了些日志,让它每关闭一条连接都打一条日志。发现,情况并非如此。基本上每秒新建多少就关闭多少,大体上相等。而且,我在测试环境中,用curl把真实的线上请求一条条的发给ATS做测试,也没有发现问题。连接在处理完后被立即断掉了。可见这块代码没什么问题。我认为,既然后端收到了tcp close请求,那么依然存在这么多已建立连接只有一个可能:后端处理太慢。为了验证我的想法,我用netstat查ATS和后端之间已建立的连接有哪些,随便挑一个,然后用lsof找出它的文件描述符(fd),然后去/proc下找到这个fd,就能看到这个连接是什么时候建立的。发现大部分连接都持续了3-5分钟以上。顿时释然。这也就解释了为什么会有几万个连接。于是我继续找瓶颈。很遗憾的是,disk io几乎没有。ATS和后端是处于同一台机器上,走lo接口,所以网络瓶颈不存在。于是我猜是CPU。因为我看见负载飘动在10-20之间。kernel的event进程经常被唤醒,占用了大量CPU。但是这我没法整,我主要看用户态的代码哪里有问题。每秒才几十个HTTP请求,瓶颈怎么也不能出在kernel的TCP栈上,对吧?于是我用perf继续查,然后发现后端的服务器在管理已建立的连接的时候,…

Fedora on MBP 问题一览

我在我的Mac Book Pro上装了一个Fedora作为办公用。风扇控制apple没有使用标准的SMBus,它自己定制了一个smc模块。由于不知道它具体是怎么工作的,所以Linux对applesmc的支持极差。风扇控制模块是坏的,所以CPU经常过热。表现在经常收到mce事件CPU7: Core temperature above threshold, cpu clock throttled (total events = 3)mce: [Hardware Error]: Machine check events logged用sensors命令可以看到CPU温度经常在90度以上。实际上应该在87度以下。bugzilla上相关链接:https://bugzilla.redhat.com/show_bug.cgi?id=924570https://bugzilla.kernel.org/show_bug.cgi?id=14514解决办法:安装这个针对mbp的fan control 软件 https://github.com/dgraziotin/Fan-Control-Daemon并且手动把最低风速调到3000echo 3000 > /sys/devices/platform/applesmc.768/fan1_minecho 3000 > /sys/devices/platform/applesmc.768/fan2_minsmc经常会报错,发送命令失败:kernel: applesmc: send_byte(0xe0, 0x0300) fail: 0x40 kernel: applesmc: F1Tg: write data fail 分辨率首先是分辨率的问题。我的笔记本的分辨率是2880x1800,大多数程序不是为这么高的分辨率设计的。于是Fedora19下显示效果就特别差,字小的看不清。windows下可以调整DPI,其中win 8.1对这个的支持就比较好,win 7就很差。升级到Fedora 20后,这个问题有很大改善。升级到Fedora 21后有更大的改善。但是chrome不是DPI aware的,暂时的做法就是把chrome的zoom level调大。不要试图调大chrome的默认字体,否则连google都无法正常使用了。Intel显卡驱动…

OneDrive -> GoogleDrive迁移中

我正在把我的网盘从微软的OneDrive迁移到Google的GDrive中。主要是受新公司的氛围影响,貌似大家都很喜欢google docs。目前OneDrive和Google Drive的价格基本一样。但是迁移的过程中我发现以下几个问题:OneDrive的打包下载功能太糟了。不支持中文文件名。它会在zip包中输出一个mapping文件,你自己根据这个重新把名字恢复过来。google drive虽然没有这个限制,但是google限制zip包不得大于2G。Google允许同一个文件夹下有两个同名的文件,但是OneDrive不行。Google这么做其实会让人很confused。Google对微软Office文档支持不好。Office的文档(比如doc、ppt、excel)在OneDrive上可以通过网页直接打开并且编辑,但是在Google Drive上要先转成Google自己的格式(doc -> gdoc)才行。转换的过程中会丢失很多格式信息。比如,word中的图,不能显示中文!Google格式的文档(比如gdoc)不能在本机打开或搜索。如果你在用客户端做同步,那么Google格式的文档文件,在本地只是一个url而已。所以你既不能对它做本地搜索,也不能用word打开它。Google Drive的搜索目前还很初级,很难用。Google不支持指定目录的搜索。比如,我想在当前目录下搜一下文件名含有"WLAN"的文件,这么简单常用的功能,Google做不到。同步算法不一样。Google在客户端文件夹内保存了同步状态。如果要在两台电脑之间同步文件,OneDrive允许我在两台电脑之间,直接copy,但是Google Drive不行。Google会把我copy来的文件当作是新增的文件,再上传一次。OneDrive的客户端在中国目前还是可以顺畅使用的,Google Drive不行。所以总的来说,就功能性而言,OneDrive比GoogleDrive好太多。起码不用去转换文件格式啊。另外说点题外话,我觉得对码工来说,所需要的所有软件,现在都已经可以运行在浏览器里了。比如ssh. Chrome有官方的Secure Shell,就是功能太弱了,不支持Key Forwarding,不支持中文输入。收发邮件,有网页版的outlook,挺好用的攥写文档,有micros…

点点互动真是网游圈的黑马

中技控股刚刚发布公告,中技香港以96,113.00 万美元的价格 收购 Diandian Interactive Holding 100%股权。中技控股以9,300.00 万元人民币的价格收购点点互动(北京)科技有限公司 100%股权 。这起收购案被称为游戏圈史上最大的并购案。根据此次交易的价格,点点互动已迈入网络游戏圈的第二梯队。位于腾讯、网易、盛大、畅游之后,与完美世界旗鼓相当。完美世界目前的市值是9.8亿美元。点点互动由钟英武和关毅涛于2010年成立,为钟英武实际控制。点点互动的母公司是趣加游戏。趣加游戏约有200名员工。2012年完成了1300万美金的A轮融资,2013年7400万美金的B轮融资。点点互动的主要产品Family Farm据称每月收入在1000-2000万RMB之间,只能说表现平平吧。点点互动2014年上半年的收入为1.98亿RMB,而与它相同市值的完美世界,今年上半年营收为18.2亿RMB,相差9倍.

azure真是远远没法和AWS比

VM经常突然自动重启按照官方说法,大约两种情况会导致VM自动重启(无任何前兆通知)Windows Azure 大约每 2-3 个月更新一次主机环境,以确保始终为平台上运行的所有应用程序和虚拟机提供安全的环境当检测到主机服务器故障时,Windows Azure 服务会自动修复,在该服务器上运行的 VM 会迁移到其他主机所以这种事情就跟大姨妈一样,差不多每个月都会遇到。更详细信息请参考官方博客 《Why did my Azure VM restart?》用户在留言板上把微软骂出翔了。也许你会说,谁叫用户不做HA的。请看下一条Load Balancer功能太简陋Azure没有7层交换,它的Load Balancer不支持session粘滞,不识别cookie。不支持HTTPS。调度方式Round Robin Only!!!没有MySQL云服务虽然Azure有SQL服务,但是那是SQL Server啊!不是MySQL!如果你实在想要,可使用一个第三方厂商cleardb提供的addon,需另外付费。由于VM经常无前兆的重启,所以自己想搭建稳定的MySQL服务极难。如果要把MySQL的监控和主从切换做成全自动化,一般的创业公司根本没那么强的实力。再要么,你就24 oncall,准备随时切换吧。p.s.谁知道tomcat的mysql jdbc pool如何做成自动切换MySQL Server地址?它是配置在context.xml中,在app启动的时候初始化的。我能想到的是就是每次要切换数据库地址的时候,人工上去改,然后重启tomcat。再要么就是自建DNS,但是我还没整过。可是DNS又得做HA,这尼玛…… 我买你云服务到底买了个啥啊!最后推荐一下cnblogs的运维博客:写了很多关于阿里云和Azure的坑http://www.cnblogs.com/cmt/tag/%E9%98%BF%E9%87%8C%E4%BA%91/http://www.cnblogs.com/cmt/tag/%E4%BA%91%E8%AE%A1%E7%AE%97/

新疆奇葩的便民卡(良民证)制度

新疆出了一个便民卡制度,没有这个卡新疆户口的人就不能在外地租房子、住酒店、就医、出差。 哪怕你去一下你们家旁边那个隔壁县,也得先办便民卡。租房子不仅得要便民卡,还得要流动人口准住通知书、居住证。下面转载一下政府公告伊宁市人民政府关于启用流动人口便民联系卡的通告 根据新疆维吾尔自治区综治办、公安厅《关于印发<流动人口便民联系卡和特定居住证统一样式>的通知》要求,2014年5月1日在全疆启用流动人口便民联系卡。现就伊宁市启用流动人口便民联系卡相关事宜通告如下:1、便民联系卡是流动人口在流入地经商、务工、务农、租房、居住登记及申领居住证的凭证,享受流入地便民服务的载体、维护自身合法权益的手段。2、便民联系卡有效期为一年,自签发之日起计算。3、新疆维吾尔自治区行政区域内年满十六周岁以上,离开户籍所在地(经常居住地)县级行政区域到其他行政区域居住的外出务工、务农、经商人员和外出就医、学习、探亲及其他原因需要在流入地租赁房屋的人员,必须在外出前到户籍所在地(经常居住地)村(社区)综治工作站(警务室)申领便民联系卡。4、流动人口到达流入地之日起3个工作日内,应当持本人身份证和便民联系卡到流入地所属村(社区)综治工作站(警务室)申报居住登记。5、年满16周岁以上的流动人口拟在现居住地居住30日以上的,应当在申报居住登记的同时申领居住证(探亲、旅游、就医、出差等人员除外)。6、如需在流入地租赁房屋,须持出租人房屋租赁证、本人身份证、便民联系卡到居住地村(社区)综治工作站(警务室)领取流动人口准住通知书,与出租人签定房屋租赁合同后方可入住。流动人口无便民联系卡的,不得在流入地租赁房屋。7、对不按照规定申报居住登记、申领居住证和便民联系卡的流动人口和未按照规定办理出租房屋备案登记和房屋租赁证的出租人,将按照《新疆维吾尔自治区流动人口服务和管理办法》及相关法律法规依法处罚;对不履行责任的用工单位和出租房屋业主,将按照《中华人民共和国治安管理处罚法》和《新疆维吾尔自治区流动人口服务和管理办法》从严处理,造成严重后果的依法追究法律责任。本通告自2014年5月1日起施行。这样的制度如果在全国推广开来,简直不堪设想。

在guice中使用jndi以及jdbc pool

实现JndiProviderclassJndiProvider<T> implementsProvider<T> { @Inject Context context; final Class<T> type; final String name; publicJndiProvider(Class<T> type, String name){ this.type = type; this.name = name; } public T get(){ try { return type.cast(context.lookup(name)); } catch (NamingException e) { thrownew RuntimeException(e); } } } 这个Provider的构造函数传入两个参数:type 要查找的对象的类型,比如javax.sql.DataSource.classname 是指resource name。在web.xml中配置的那个。绑定DataSource的实现在ServletModule或者其它某个Module的配置中写bind(javax.naming.Context.class).to(javax.naming.InitialContext.class); bind(javax.sql.DataSource.class).toProvider( new JndiProvider<javax.sql.DataSource>(javax.sql.DataSource.class, "java:/comp/env/jdbc/mydb")); 那么当你想用javax.sql.DataSource类型的对象时,它就会绑定到JNDI中名为"java:/comp/env/jdbc/mydb"的实例。
但是这么做有个问题,InitialContext不是thread safe的(所以不能做成Singleton),但是构造一个InitialContex…

A Double-Checked Locking Error in JDK

我昨天在使用javax.xml.bind.DatatypeConverter这个类的时候发现,它内部隐藏了一个Singleton的实现,而且是有问题的。代码大概如下:finalpublicclassDatatypeConverter{ // delegate to this instance of DatatypeConverterprivatestatic DatatypeConverterInterface theConverter = null; privatestaticsynchronizedvoidinitConverter(){ theConverter = new DatatypeConverterImpl(); } publicstatic String parseString( String lexicalXSDString ){ if (theConverter == null) initConverter(); return theConverter.parseString( lexicalXSDString ); } } 其中,theConverter这个变量在声明的时候没有加上volatile修饰符。参考:《The "Double-Checked Locking is Broken" Declaration》

2014/07/02 网站系统升级

我刚把这台服务器的操作系统从Red Hat Enterprise 6.5升级到Red Hat Enterprise 7.0。目前我感受到的操作系统的变化如下:不再支持32位。虽然依然可以用虚拟机运行32位,但是AWS不支持这个了。AWS中运行它的方式也从半虚拟化变成了HVM。apache从2.2升级到2.4。但是因为mod_spdy一直不支持apache 2.4,所以本站就只好暂时放弃spdy了。用systemd替换了SysV 和 Upstart 。所以不要用service xxx start了,换成systemd start xxx。另外,journalctl 我也非常用不习惯,每次都要加上--no-pager。官方源中MySQL被换成了MariaDB 5.5。不过没关系,大不了自己手动从dev.mysql.com下载rpm。kernel升级到了3.10。另外,十分感谢AWS提供了t2.micro这种新型的micro实例来替代之前的t1.micro。速度差别十分十分显著。我感觉这两种虚拟机主要的差别有以下几点:cpu的调配划分上硬盘从EBS only变成了SSD(鸟枪变火箭炮啊!)内存从600MB升级到了1GB昨天我还试用了一下Google Compute Engine,因为它的服务器在台湾,从国内访问连通性很差,作罢。稍等,我再试一试azure。

互联网个性化广告的隐私条款对比

微软"作为我们尊重你的隐私的持续承诺的一部分,我们将不会利用你的文档、照片或其他个人文件,或者你的电子邮件、聊天、视频通话或语音邮件等内容对你进行有目的的广告投放"并且,微软允许用户关闭个性化广告。如果你关闭了,那么虽然广告依然继续展示,但是"the ads you get won't be personalized anymore by Microsoft Advertising." ,同时,微软依然会继续搜集你的个人信息用于其它方面,比如MSN的首页个性化推荐,microsoft downloads里的个性化搜索。Google隐私一直是GMail一直被诟病之处。比如,GMail会根据邮件内容展示内容相关的广告,而微软绝对不会这么做。Google即便你Opt out了个性化广告,"you may still see contextual ads based on the message you are reading as well as other relevant ads." https://support.google.com/mail/answer/6603?hl=en百度百度网盟可以禁用个性化广告别的我还没留意。

关于限制性股票和期权的一点个人看法

限制性股票(RSU)和期权是公司激励员工的常用方式。我作为非专业的人士讲下我的看法。
限制性股票是股票的买入和(或)卖出受限制。举个例子,某公司决定给你4000股的股票,但是你现在不能卖。每工作满1年,你就可以卖出1000股。具体哪天卖随便看你,你也可以全留到10-20年后再卖。换种说法就是,每工作满1年就送给你1000股的股票,连续4年。
期权是你获得一种权利,在将来的某个时间段可以以固定的价格买入该公司一定数量的股票。比如你可以100美元的价格在2015-01-01至2020-12-31时间内买入百度公司的总计2000股的股票。买入后你可以长期持有,也可以立即卖出。如果百度在这个时间段的股价一直低于100美元,那么你可以放弃此权利。直观来看,股价上涨对你有好处,股价下跌对你没风险,但这是错的!
天上不会白掉馅饼
很多人以为限制性股票和期权是公司白送给你的,其实不是。对员工来说,谈offer的时候完全可以要求多要点现金,少要点股票和期权,或者多要点现金,少要点股票和期权。对公司来讲,发放这些也都是有成本的。所以股票也好,期权也好,都是你拿工资买的!
比如,某司提供两种offer供你选择。
选项1是每月1万块钱现金,一年发12个月,共计12万。
选项2是每月5000块钱现金,一年发12个月,但是每工作满1年就再发给你价值6万块钱的股票,股价以入职日那天的价格计算。比如你入职那天股价是10块钱一股,那么就每年给你发6000股。这样算下来,每年就是6万工资+6万股票,total也是12万。
这两个offer你选择哪个(暂不考虑税率的问题)? 肯定是第一个啊!谁都知道拿到手的才是最真实的!
那假如选项2是每月5000现金+每年9万块钱的股票呢?你选哪个?为什么?
我说的买入受限制是指,股价按入职日的价格计算,但是入职日不由你决定,那天的股价可能很高。如果是给你现金让你自己操盘,你必然选择一个相对低谷的时候买。RSU流动性受限导致它相对于普通股来说价值要打一个折扣。HR说给你了6万元的RSU,并不代表这些RSU真的值6万。
期权的杠杆效应
再比如。B司给你两个选择,除了基本工资外,提供
选项1:连续4年,每年1000股的股票
选项2:8000股的期权,行权价是3美元。每年归属25%,分4年归属完毕。即到第一年年末时,你就能卖出2000股的期权了。到第四年末,所有这8000股期…

quick sort的时间复杂度的定量分析

对quick sort算法的复杂度做一下更精确的分析。quick sort是典型的分治(divide-and-conquer)算法。算法描述如下:从待排序数组中选取一个作为划分元素(pivot)用pivot把待排序数组分成两部分,使得一部分大于pivot,一部分小于pivot。对这两个子数组分别递归调用此算法示例代码:选取数组的第一个元素做pivot。template <typename Iterator> void quick_sort(Iterator begin, Iterator end) { auto len = end - begin; if (len <= 1) return; auto p = *begin; typedef decltype(p) T; Iterator iter = std::partition( begin + 1, end, [&p](const T & d)->bool { return p>=d; }); std::iter_swap(iter - 1, begin); quick_sort(begin, iter - 1); quick_sort(iter, end); } 基本上是个程序员都知道quick sort的平均时间复杂度为O(nlogn),最坏为O(n^2)。昨天我又重新看了一下Hoare在1962发的那篇关于quick sort的论文,下面对quick sort所需的比较次数做一下精确分析。quick sort的效率与划分是否平衡息息相关。假设我们选取的pivot恰好是这个数组的第k大元素, 那么由它划分而得到的两个子数组的长度分别为k-1和n-k。假设pivot是第k大的元素的概率是\(p_k\)。假设对n个元素进行quick sort所需要的平均比较次数为\(Q_n\),那么有$$ Q_n=n-1+\sum_{k=1}^n{p_k * (Q_{k-1} + Q_{n-k})} $$上式前面的n-1是指划分成两个子数组需要进行n-1次比较,后面是对不同的\(p_k\)计算数学期望。随机取pivot的quick sort继续假设pivot是从输入的数组均匀随机选取的,那么有\(p_k=1/n\)$…

用牛顿迭代法求整数的平方根

这是一个挺常见的面试题,解法也五花八门。下面的代码用牛顿迭代法解决这个问题。因为输入和输出都是整数,所以只要前后两项相差小于1,就可以终止了intsqrt(int x){ if (x < 0) abort(); if (x == 0) return0; if (x == 1) return1; double t = x >> 1; t = (t + x / t) / 2; while (true) { double v = (t + x / t) / 2; if (fabs(v - t) < 1) { t = v; break; } t = v; } t=floor(t); if (t * t > x) t--; return t; } 我本来想用有理数运算来代替double,后来发现不行,迭代次数过多后,如果分子分母约分约不下去,就溢出了。上面这段代码其实也就只能应付面试,实际有很多比这个更优的方案,比如打表

一套适用用App的自动登录协议

很多App都是在启动的时候就自动给用户注册一个账号,先用着,稍后再绑定邮箱和密码。因此,我在前人的基础上设计了这样一套协议注册:客户端用不对称密钥算法(如RSA、ECDSA)生一对密钥,然后把公钥发给服务器,服务器把公钥插入到数据库中,返回一个新生成的userid登录:服务器发给客户端一个32位随机数r1客户端自己再生成一个32位随机数r2,然后把r1,r2,userid用memcpy的方式合起来,用私钥计算出一个签名s1,然后把r1,r2,userid,s1发给服务器。服务器收到答复后,先看那个随机数r1是不是刚才它发给客户端的。然后根据userid从数据库里面查出客户端的公钥,用它验证数字签名是有效的。(可选) 在完成前三步后,服务器把r2,r1用memcpy的方式合起来,用私钥计算出一个签名s2,然后把s2发给客户端。客户端收到后用服务器的公钥验证下签名,这样它就相信这个服务器不是假冒的。这要求服务器的公钥证书要实现内置在客户端中。 以上注册和登录的过程都可放在后台,不需要用户交互。不对称加密算法推荐使用ECDSA,比如ECDSA-128,因为它的公钥很短,计算很快。 但是,其实,生随机数很耗费CPU的。我在想怎样修改它让它能更好的避免DDOS攻击。

中信银行的理财产品不要买,我被骗了

我最近手上有点闲钱,想做点低风险的投资。于是就考虑了以下四种方式:货币基金 (余额宝之类),大部分都在4%-5%之间。国债逆回购(204001等),28天的最近3%-4%左右。银行的理财产品,大部分在5.2%到6%左右。P2P信贷。我只看了一下招行的,半年期5.8%到6%左右,一发售就告罄,抢不到。上面的名词看不懂没关系,看懂结论就行了:余额宝的收益率最高、流动性最高,且风险几乎最低。表面上看银行的理财产品收益率最高,比货币基金高大约1个百分点呢。1个百分点的差距,50个万的资金每3个月就相差1000块钱,够给女朋友买个包了。请先假设我有50万,并继续假设我有女朋友,不然后面没得聊了。下面主要分析银行理财产品的收益率和风险。收益率的骗局我在网上搜了一下发现中信银行有一个半年期收益率6%的理财产品,我就立马跑去了要求开户。你好,我叫王大锤,万万没想到中信银行的理财经理告诉我,他们网站标的有问题。半年期6%的理财产品实际上5.8%。因为他们有两个代码,一个是百万起售的,那个真的是6%,另一个是5万起售的,那个是5.8%,如果你仔细阅读产品说明书,能发现这个差别。他一边给我讲这个我一边瞄了一眼理财部坐着的客户,发现全是头发花白的大妈和奶奶,我有点担心我是不是来错了地方,怎么看着这么像诈骗场所。我要是真有100万,我才不买理财呢,我干嘛不直接买信托?你银行拿了我的钱不也是去买信托了,我还得给你交50-60%的手续费,我傻啊我?但是我觉得5.8%还是比余额宝什么的高,买吧。我小心翼翼的多问了一句:起息日什么时候?他告诉我,一周后。我大吃一惊!还是按50万来算,每天的利息是80块钱,7天就是560。尼玛这不是钱啊!理财经理告诉我,你可以办7天通知存款嘛。利率1%点几,可以弥补一下。事实证明他又在忽悠我,根本不可能,因为资金来回转需要时间,剩下实际不够7天,恰好不够7天!接着,我又问,有没有明天就起息的。他说有1个月和2个月的,后天起息的,你明天买也来得及。我觉得他说的对,于是我就买了。但是预期收益率只有5.4%,因为期限短。好吧,反正来都来了,卡都办了,怎么说也还是比余额宝高。于是我就买了。等我回来之后仔细阅读了下产品说明,发现,实则不然。我还是被银行骗了。我买的产品代码是B140A0104,名义收益计算天数35天,募集期5月7日到5月8日,扣款日5月9日,到期日6月13日,…

字符串匹配(1): 朴素字符串匹配的实现及复杂度分析

问题描述:在字符串t中寻找字符串p第一次出现的位置实现:C语言版本://Find the first occurrence of find in s. char *strstr(const char *t, const char *p) { char c, sc; size_t len; if ((c = *find++) != '\0') { len = strlen(p); do { do { if ((sc = *t++) == '\0') return (NULL); } while (sc != c); } while (strncmp(t, p, len) != 0); s--; } return ((char *)t); } C++版本:(下面这段代码仅仅是为了做算法分析而写的demo,不要在实际项目中使用它,因为它效率很差。)#include <string> #include <iostream> std::string::size_type find(const std::string &t, const std::string &p) { if (t.length() < p.length()) return std::string::npos; std::string::size_type end = t.length() - p.length(); for (std::string::size_type i = 0; i <= end; ++i) { bool mismatch = false; for (std::string::size_type j = 0; j != p.length(); ++j) { if (t[i + j] != p[j]) { mismatch = true; break; } } if (!mismatch) { return i; } } return std::string::npos; }…

CentOS的gcc版本对比表

CentOS 4.x2005年gcc 3.4CentOS 5.x2007年gcc 4.1CentOS 6.x2011年gcc 4.4CentOS 7.x2014年gcc 4.8这张表对每个做Linux 服务器端开发的C++程序都挺有用的。用来估计代码的兼容性。https://gcc.gnu.org/projects/cxx0x.html

Linux下pthread_t会被快速重用

我最近写的有个程序有点bug,我想加点调试信息,把每个mutex的owner记录下来,谁拿过它,什么时候释放了。然后我意外的发现,pthread_t就跟fd一样,是一个会被快速重用的东西。
测试代码:
#include <iostream> void* f(void* p){ std::cout<<"run"<<std::endl; } intmain(){ pthread_t t1; pthread_create(&t1,NULL,f,NULL); pthread_join(t1,NULL); std::cout<<t1<<std::endl; pthread_t t2; pthread_create(&t2,NULL,f,NULL); pthread_join(t2,NULL); std::cout<<t2<<std::endl; std::cout<<pthread_equal(t1,t2)<<std::endl; return0; } 运行结果:
run
139979191514880
run
139979191514880
1
所以一个更好的替代是使用gettid系统调用,获得线程在内核中的task id。但是,glibc拒绝为此系统调用提供封装,所以只能自己写一个封装:
inline pid_t my_gettid(void){ return syscall(SYS_gettid); } update:Windows下有类似的问题。GetCurrentThreadId()的返回值也是会重复的。我还没找到不重复的替代品。

DIY基于Android的路由器和机顶盒

为什么要DIY为了安全。 目前世面上主流的家用路由器(比如tplink、dlink、netgear)都有内置后门,问题很严重。为了把机顶盒和路由器合在一起。 为了翻墙方便。硬件准备硬件方面我考察了3种方案:cubietruck(即cubieboard3)。基于ARM架构。优点是支持sata、千兆网卡。但是计算能力较弱,CPU是cortex A7双核,内存频率只有480Mhz。售价540左右。Radxa。基于ARM架构。优点是计算能力强,CPU是cortex A9四核1.6GHz,内存DDR3 800MHz。缺点是IO较弱,网卡只有百兆,没有sata接口。售价600左右。Atom D2550。 基于intel x86架构。优点是基于x86,程序安装移植方便,计算能力超强,双以太网卡。整机配好价格大概800-1000左右。最后还是选择了Radxa。目前世面上在售的路由器,除了小米和netgear的某几款是基于ARM,其它的都是基于MIPS芯片组。运算能力远远要弱的多。所以那些把NAS和路由做在一起的,要么选好CPU售价上千,那么就是瞎扯淡。操作系统的考虑 Radxa支持两种操作系统ubuntu和android。两种我都试了一段时间,如果只是做软路由,那么当然是ubuntu更好。用起来就跟x86的linux没啥区别。但是如果还想用它接电视看个视频啥的,那还是android好。随着Android步入客厅,基于android的TV game也许会是一个新兴市场。安装步骤首先在Google Play里面找Terminal Emulator和busybox装上。因为我要用wget来下载ssh server,然后运行。ssh server本来在Google Play里有DroidSSH,好像挺流行的。但是它说什么地区限制,不让我装。我就只好自己编译一个。安装ndk。下载dropbear,然后改若干处。(等我有空把我改过的dropbear 6.2上传到github去)然后编译openssl、squid、unbound等等。我发现很多程序原本就不支持交叉编译,比如squid,它要先编译一个可执行文件,用它生成一个C++的源代码文件,然后把这个新生成的源文件加进去再编译。但是在交叉编译环境中,编译出来的程序是ARM的,我执行gcc的机器是x86的,没办法执行啊!还好这些小问题都可以…

以JIT的方式执行C/C++程序

传统来说,我们编译c/c++程序的方式是:先把每个源文件编译成obj文件$(CXX) -c xxx.cpp -o xxx.o然后把obj文件和其它静态库、动态库链接在一起成为一个可执行文件(ELF/PE)$(CXX) -o xxx xxx1.o xxx2.o xxx3.o -lpthread -lxxxxLLVM加入了一种与机器无关的中间语言IR,使得我们可以像Java一样,半编译半解释的执行C/C++程序。把C/C++源文件编译成LLVM字节码clang在加了-emit-llvm和-c之后,输出的是llvm的bytecode文件(*.bc)例如:$ clang++ -emit-llvm -stdlib=libc++ -fno-use-cxa-atexit -I/data/test2 -o gtest-all.cc.bc -c /data/test2/gtest-all.cc$ clang++ -emit-llvm -stdlib=libc++ -fno-use-cxa-atexit -I/data/test2 -o test.cpp.bc -c /data/test2/test.cppllvm-link能把多个bytecode文件链接成一个bc文件。$ llvm-link test.cpp.bc gtest-all.cc.bc -o hello 执行字节码lli能直接执行bc文件。$ lli -use-mcjit hello.bc 这么做的优点是,bytecode文件只需要生成一次,但是却可以在不同的硬件平台上执行。比如既能在intel x86的CPU上执行,又能在arm上执行。(我已经拿我的RK3188的板子试过)。
程序依赖的额外的动态库可以用-load参数加上。比如$ lli -use-mcjit -load /lib/x86_64-linux-gnu/libssl.so.1.0.0 hello.bc 使用CMake编译不能总停留在Hello World上。要找实际项目做测试。于是我找了curl。它可以通过cmake构建。我先从官网上下载了7.36.0的源代码,然后按正常流程先跑了一次cmake,让它把所有的Makefile和link.txt都生好。但是不执行make指令。然后我修改它原来的CMakeLists.txt,修改其编译规则。在最前…

cortex-a9的运算性能测试

我最近买了一个国产的arm开发板,我想比较一下它和我的台式机的性能差别。最后我觉得,家里自建服务器还是用intel的方案吧,比如DN2800MT之类。ARM只适合移动设备。测试环境:机器1:硬件:mac mini 2012, CPU是i5-3210M CPU @ 2.50GHz,1个物理CPU,双核,超线程,所以在操作系统里看起来是4个CPU。
软件:Ubuntu 13.10 x86_64。 kernel是3.11.0-18-generic。机器2:硬件:radxa开发板。Soc是瑞芯微rk3188,CPU 是4核的cortex-A9@1.6GHz,内存2GB DDR3 @ 800Mhz. 其它详细的硬件信息见这里:http://radxa.com/specification/
软件:Linaro 13.09。C++容器测试:PC的软件环境:编译器: gcc 4.8.1
编译参数:--std=c++11 -mtune=native -march=native -fno-strict-aliasing -O3 -DNDEBUGARM的软件环境:编译器: gcc 4.7.3
编译参数:--std=c++0x -mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=hard -D__ARM_ARCH=7 -fno-strict-aliasing -O3 -DNDEBUG用一段简单的C++程序,单线程顺序插入1024个整数到std::vector<int>或std::list<int>中,计算耗时。耗费的时间来自getrusage函数。把user mode和kernel mode的总时间加起来。结果:PCARMvector插入1.4亿条每秒3000万条每秒list插入3000万条每秒500万条每秒 由于我的程序是单线程,所以这里比较的是单核的性能。大概有5、6倍的差距。OpenSSL的RSA性能测试:PC的软件环境:OpenSSL 1.0.1e 11 Feb 2013ARM的软件环境:OpenSSL 1.0.1c 10 May 2012测试内容:测试每秒能进行多少次RSA 4096签名或验证RSA 4096签名。这里用的是预编译的包,所以没有针对特定CPU进行优化。结果:PCARM4线程签名/秒216274线程验证/秒13…

绘制二叉树

图片
最近我在学习二叉树相关的很多算法,于是我就在想,能不能把二叉树画出来看看。比如下图这样:问题的细化我们想要在一个平面的画布上绘图,比如一个800像素x600像素的bitmap。首先把这个画布切成一个个正方形的格子(tile)。每个格子的大小比如是20x20。每个格子里面只放一个二叉树节点。我们需要寻找一个算法,给二叉树的每个节点计算出一个(x,y)的值,来对应我们画好的格子。一旦把(x,y)的值确定下来,剩下就是画圆圈、画线的工作了,就简单多了。那么依据什么规则来确定x,y的值呢?Trees impose a distance on the nodes; no node should be closer to the root than any of its ancestors.Nodes at the same level of the tree should lie along a straight line, and the straight lines corresponding to the levels should be parallel.The relative order of nodes on any level should be the same as in the level order traversal of the tree.For a binary tree, a left child should be positioned to the left of its parent and a right child to the right.A parent should be centred over its children.A subtree of a given tree should be drawn the same way regardless of where it occurs in the tree.根据上面的第二条规则,y的值其实很容易获得,它就对应节点的level值。所以对二叉树进行层序遍历即可。所以问题的核心是给每个二叉树节点计算横坐标x的值!一个最直接的做法是,直接以中序遍历的序号作为横坐标的值。用这样的算法,画前序遍历为{2,1,6,4,3,5,8,7}的二叉搜索树,结果为:用这样的算法,画前序遍历为{…

一些技术视频资源

最近在国外一些网站上找到了一些很有趣的视频资源。一. USENIX的会议视频。USENIX原名Unix Users Group,在它的网站上能下载到从2008年到现在的所有会议视频 https://www.usenix.org/conferences/multimedia ,一般是480p的 。由于我个人比较喜欢读usenix的paper,它比较偏工业界。所以我很喜欢看他们的演讲。二. Google Developers At Youtube有每年Google各种技术会议的视频。比如Google I/O,Dev Summit等。很多都是720p的高清。三. MIT算法系列入门:6.046和6.006。进阶:6.854/18.415J: Advanced Algorithms (Fall 2013)。这个课2013年的视频在youtube上"Karger Skoltech"的Channel里。https://www.youtube.com/watch?v=QnPl_Y6EqMo&list=PL2B4EEwhKD-NbwZ4ezj7gyc_3yNrojKM9 可惜清晰度很低。高级:6.851: Advanced Data Structures 。 这个课的视频有720p高清版,但是内容确实非常难。他讲的东西是我在任何书上都学不到的,所以耐心听吧。

在windows下使用llvm+clang

图片
clangFreeBSD和Mac下C/C++语言的默认编译器。如果你在苹果下做过开发,那么应该对它很熟悉。
这套工具链有很多优点:
代码很新,架构优良。 错误信息更友好。 静态检查功能更强大。 版权限制小,易于自定义模块来扩展它的功能。 背后有Apple和Google这两家商业公司的大力支持。比如XCode现在只支持clang而不支持gcc。 支持JIT。这使得C/C++可以像java那样半编译半解释,一次编译到处执行。 支持所有主流的操作系统。 clang只是一个前端,它背后用来生成二进制机器码的叫llvm。
llvm+clang 在windows下有两种,一个是用mingw编译的,使用gcc的头文件和库。一个是用vc编译的,使用vc的头文件和库。
mingw版本的下载地址是:http://llvm.org/releases/3.6.1/LLVM-3.6.1-win32.exe 这是由官方提供的
vc版本的下载地址是:
google drive下载
这是我自己编译的,32位版本。 想自己编译clang的可参考我之前的文章.
我建议你安装vc版本的。
因为优点是:
它编译出来的是更原生态的程序。不依赖于mingw,只依赖于vc的dll。 我自己编译的这个版本功能更全,包含了llvm的JIT执行器、clang的扩展工具(如把老风格的代码转换成c++11)等等。 性能更高。 但也有一些缺点:
必须依赖于visual studio。请先安装visual studio再安装llvm。 没有安装visual studio的可以从微软的官方网站下载: http://www.microsoft.com/en-us/download/details.aspx?id=40778 。
如果已经有visual studio但是版本不是2013的,请安装vc 2013的可再分发包:http://www.microsoft.com/en-us/download/details.aspx?id=40784
clang安装好以后,你可以先打开它下面的bin目录看一眼,里面有30多个exe。主要比较常用的是:
clang: C语言编译器,类似于gccclang++: C++编译器,类似于g++。clang++只是clang的一个别名。lld: 链接器,类似于ld。但是默认不用它,默认用…

在windows下用vc编译llvm+clang

图片
1. 安装cmake(www.cmake.org)和python、perl 2. 安装visual studio 3. 下载源代码aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/llvm-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/cfe-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/compiler-rt-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/lldb-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/lld-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/clang-tools-extra-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/polly-4.0.1.src.tar.xz
aria2c -x 5 -j 5 -k 1M http://releases.llvm.org/4.0.1/openmp-4.0.1.src.tar.xz

全部解压之后,按照下面的规则放置

mv cfe-4.0.1.src llvm-4.0.1.src/tools/clang
mv compiler-rt-4.0.1.src llvm-4.0.1.src/projects/compiler-rt
mv clang-tools-extra-4.0.1.src llvm-4.0.1.src/tools/clang/tools/extra
mv lldb-4.0.1.src llvm-4.0.1.src/tools/lldb
mv openmp-4.0.1.src llvm-4.0.1.src/projects/openmp
mv lld-4.0.1.src llvm-4.0.1.sr…

在tomcat应用中获得原始IP

Apache/Nginx 通常被放在tomcat前作为http代理。例如:browser -> apache -> tomcat 但是缺点是丢失了很多原有的网络信息:ip、hostname、protocol(用的是http还是 https)比如,当java程序想生成http重定向请求的时候会遇到麻烦。因为HTTP头部的Location字段的值必须是绝对URL。重定向的问题勉强可以交给前面的proxy来解决(让apache重写header),但是藏在http body中的各种链接问题就棘手多了。比如当从一个html页面载入一个外部资源时,资源的链接到底是写http的还是https的呢?通过修改apache和tomcat的配置,可以让这个问题得到较为完美的解决。首先是要apache把这些丢失的信息通过http header发到后面去。一. Host字段HTTP头部的Host字段用来写网站的域名。如果服务器(此处指tomcat)需要支持virtual host,即同一个IP服务多个域名,那么这个字段很重要。在配置mod_proxy时加上ProxyPreserveHost,就会让apache往后端转发的时候,Host字段依然填它从browser收到的那个域名。二. Apache默认会发送的字段默认情况下apache在做http逆向代理时会给后端发送以下字段X-Forwarded-For client的IP地址X-Forwarded-Host client所请求的域名,即client发来的的http header中Host字段的值。X-Forwarded-Server 这台代理服务器(apache)的域名。三. 需要添加的纵使有了以上信息,我们还是不知道client用的到底是http还是https访问的apache。所以要加下面这行:RequestHeader set X-Forwarded-Proto "https" env=HTTPS这行代码的意思是,如果当前含有"HTTPS"这个环境变量,那么往后端转发请求时,在头部加上X-Forwarded-Proto字段,值为"https"。类似的还可添加其它信息。如HTTPS/SPDY的具体信息,假如前端用的是spdy,那么当前请求不仅具有HTTPS这个环境…

AWS又“试用”了一年

这两天把我个人网站的服务器挪了一下。原因是amazon web service一年的免费试用马上就要到期了,所以我就又申请了一个新账号,继续试用。哈哈。不用换信用卡,换一个新的email就行了。这次重做系统的时候,我考虑再三,最终选用了32位的Linux。因为amazon ec2免费的实例只有600MB内存,而对于大多数程序来说,64位的要比32位的占用更多内存。(因为指针变大了)然后我开通了RDS服务,就不自己建mysql server了,确实省事不少。先用着再说吧。顺便,AWS China的小哥打电话告诉我,最多2-3个月内,中国区就要正式商用了。然后我又看了下Google App Engine,这个比较讨厌的是和Google Apps捆绑销售了。要在Google App Engine上绑定域名,必须先把域名绑到Google Apps上去。而Google Apps已经没有免费版。

关于Interface和Callback的一些杂记

Java中有一个名为interface的关键字用于定义接口类 ,"an interface is a group of related methods with empty bodies"C++中没有这个关键字,但是对于只含有纯虚函数的C++类来说,它和Java中的Interface也差不多。interface常被用来实现callback。比如我们正在写一个http服务器,它每收到一个http请求就去执行一些特定的代码。为了把基础框架和应用层代码分开,callback就是很好的模式。C语言中既没有类也没有虚函数,所以在C的函数库中,callback通常用一个函数指针加一个void*来实现。那个void*可以被用来传递任意句柄。通常来说,我把那个void*就看成是this指针。C++中实现functor的三种方式:函数指针 + void*struct/class重载operator()lambda表达式这三种都可以统一被转换成std::function。callback有时会让C/C++的内存管理变得很复杂。如果能做到谁分配谁释放,那么内存管理就再简单不过了。但是常常并非如此。假设我们有一个事件(event)管理器,它有一个事件循环,每当收到一个新事件,就去调用这个事件对应的callback。但是我们的程序又是多线程的,所以这个事件管理器本身必须被锁保护。那么就存在一个问题,callback执行的时候,应处于临界区内还是外?即,此时该线程是否持有事件管理器内的锁? 答案通常是"不",为了避免死锁。就算没有死锁,在这种情况下是否依然能触发并处理新事件?非常复杂。如果callback执行的时候并不拥有事件管理器的任何锁,但是它又要访问事件管理器,那么就存在一个问题:如何维护事件管理器的生命周期?如果我在本次事件处理中调用了事件管理器的shutdown方法呢?这时就得靠引用计数来解决问题。事件管理器内部得有一个引用计数器。初始值为1。每调用一次callback之前加1,完成之后减1。this->ref++;
this->unlock();
do_callbacks(.....);
this->lock();
this->ref--;
if(!this->ref) delete this;API: base cl…

How to download the CBS news videos

视频的url:在这个网站http://www.cbsnews.com/上能在线观看CBS的视频节目,比如Evening News, 60 minutes, Face the Nation等等。随便打开一个视频节目的播放页,然后打开网页源代码,搜索mp4,就能看到这样的东西{"pid":"ZqQdf4uXVkZE","bitrate":764000,"uri":"rtmp://cp98363.edgefcs.net/ondemand/?auth=cbs&aifp=v001&slist=media/2014/01/05/107395139598/<break>media/2014/01/05/107395139598/ftn_0105_NEWfull_796.mp4"},"tablet":{"pid":"tv78ObYUA_eM","bitrate":740000,"uri":"http://download.cbsnews.com/media/mpx/2014/01/05/107395139598/ftn_0105_NEWfull_740.mp4"},"mobile":{"pid":"S8jlI1_h4UwZ","bitrate":240000,"uri":"http://download.cbsnews.com/media/mpx/2014/01/05/107395139598/ftn_0105_NEWfull_240.mp4"} 它对应的是一个视频的不同格式。其中740.mp4和796.mp4是分辨率最高的,分辨率是640x360。这两个文件基本一样,区别是796.mp4的音频是48khz的,而740.mp4是22khz的。域名都是download.cbsnews.com,只是后面的网址略有区别。如:http://download.cbsnews.com/media/2014/02/09/144224…