关于SPDY

摘自:http://www.williamlong.info/archives/3119.html

相关参考:

http://zh.wikipedia.org/wiki/SPDY

http://www.chromium.org/spdy

http://www.chromium.org/spdy/spdy-proxy-examples

 

SPDY 是 Google 开发的基于传输控制协议 (TCP) 的应用层协议 ,开发组正在推动 SPDY 成为正式标准(现为互联网草案)。SPDY 协议旨在通过压缩、多路复用和优先级来缩短网页的加载时间和提高安全性。(SPDY 是 Speedy 的昵音,意思是更快)

  SPDY 与 HTTP 的关系

SPDY 协议只是在性能上对 HTTP 做了很大的优化,其核心思想是尽量减少连接个数,而对于 HTTP 的语义并没有做太大的修改。具体来说是,SPDY 使用了 HTTP 的方法和页眉,但是删除了一些头并重写了 HTTP 中管理连接和数据转移格式的部分,所以基本上是兼容 HTTP 的。

Google 在 SPDY 白皮书里表示要向协议栈下面渗透并替换掉传输层协议(TCP),但是因为这样无论是部署起来还是实现起来暂时相当困难,因此 Google 准备先对应用层协议 HTTP 进行改进,先在 SSL 之上增加一个会话层来实现 SPDY 协议,而 HTTP 的 GET 和 POST 消息格式保持不变,即现有的所有服务端应用均不用做任何修改。

因此在目前,SPDY 的目的是为了加强 HTTP,是对 HTTP 一个更好的实现和支持。至于未来 SPDY 得到广泛应用后会不会演一出狸猫换太子,替换掉 HTTP 并彻底颠覆整个 Internet 就是 Google 的事情了。

  为什么要重新建立一个 SPDY ?

距离万维网之父蒂姆·伯纳斯-李发明并推动 HTTP 成为如今互联网最流行的协议已经过去十几年了(现用 HTTP 1.1 规范也停滞了 13 年了),随着现在 WEB 技术的飞速发展尤其是 HTML5 的不断演进,包括 WebSockets 协议的出现以及当前网络环境的改变、传输内容的变化,当初的 HTTP 规范已经逐渐无法满足人们的需要了,HTTP 需要进一步发展,因此 HTTPbis 工作组已经被组建并被授权考虑 HTTP 2.0 ,希望能解决掉目前 HTTP 所带来的诸多限制。而 SPDY 正是 Google 在 HTTP 即将从 1.1 跨越到 2.0 之际推出的试图成为下一代互联网通信的协议,长期以来一直被认为是 HTTP 2.0 唯一可行选择。

  HTTP 协议的不足

  1. 单路连接 请求低效

HTTP 协议的最大弊端就是每个 TCP 连接只能对应一个 HTTP 请求,即每个 HTTP 连接只请求一个资源,浏览器只能通过建立多个连接来解决。此外在 HTTP 中对请求是严格的先入先出(FIFO)进行的,如果中间某个请求处理时间较长会阻塞后面的请求。

(注:虽然 HTTP pipelining 对连接请求做了改善,但复杂度增加很大,并未普及)

  2. HTTP 只允许由客户端主动发起请求

服务端只能等待客户端发送一个请求,在可以满足预加载的现状是一种桎梏。

  3. HTTP 头冗余

HTTP 头在同一个会话里是反复发送的,中间的冗余信息,比如 User-Agent、Host 等不需要重复发送的信息也在反复发送,浪费带宽和资源。

  SPDY 协议的优点

  1. 多路复用 请求优化

SPDY 规定在一个 SPDY 连接内可以有无限个并行请求,即允许多个并发 HTTP 请求共用一个 TCP会话。这样 SPDY 通过复用在单个 TCP 连接上的多次请求,而非为每个请求单独开放连接,这样只需建立一个 TCP 连接就可以传送网页上所有资源,不仅可以减少消息交互往返的时间还可以避免创建新连接造成的延迟,使得 TCP 的效率更高。

此外,SPDY 的多路复用可以设置优先级,而不像传统 HTTP 那样严格按照先入先出一个一个处理请求,它会选择性的先传输 CSS 这样更重要的资源,然后再传输网站图标之类不太重要的资源,可以避免让非关键资源占用网络通道的问题,提升 TCP 的性能。

  2. 支持服务器推送技术

服务器可以主动向客户端发起通信向客户端推送数据,这种预加载可以使用户一直保持一个快速的网络。

  3. SPDY 压缩了 HTTP 头

舍弃掉了不必要的头信息,经过压缩之后可以节省多余数据传输所带来的等待时间和带宽。

  4. 强制使用 SSL 传输协议

Google 认为 Web 未来的发展方向必定是安全的网络连接,全部请求 SSL 加密后,信息传输更加安全。

  SPDY 协议的意义

按照 Google 的说法,SPDY 被创造出来的唯一目的就是让 Web 更快(strive to make the whole web fast),其名字 SPDY(Speedy) 也似乎在暗示着这一点。那么 SPDY 的意义又在哪里呢?

  1. 普通用户:

对于使用者来说,隐藏在浏览器下面的 SPDY 相比 HTTP 没有任何区别,但是我们可以感觉到 Google 服务在 Chrome 下异常的快,这就是 SPDY 的功劳了。此外网站信息传输加密后不用担心信息被截取等,大大增加了安全性和保密性。

  2. 前端人员:

对于前端工程师们来说,提升页面效率是一件很重要的事情,目前大多采用像 CSS Sprites 等方法来优化网站,对于因为页面加载时每张图片、icon 都请求一个连接甚至采用在不同页面引用不同图片来降低一个页面内图片的请求数量。而现在有了 SPDY 的请求优化可以将请求顺序进行重排,这样可以在很大程度上缓解页面加载时图片请求带来的影响。例如像极客公园的报名页面,如果报名用户过多,例如极客公园 2012年创新大会或极客公园第 27 期长城会,可以很明显的感觉出头像的请求会拖累整体页面加载变慢甚至变卡,相信对于这点,经常上淘宝或刷微博的会深有体会,一旦网速稍微慢点就会出现页面 加载异常,还有像苹果 App Store(除去服务器因为地区的延迟),豌豆荚这类应用分发平台上应用图标刷新缓慢等,如下面这个视频所示。

  3. 运维人员:

SPDY 在降低连接数目的同时,还使得服务器上每个客户端占用的资源也减少,从而可以释放出更多内存和 CPU 。此外 SPDY 综合起来可以将浏览速度提升一倍,页面加载延迟方面的改进达 64% 。

  众家支持的 SPDY 协议

如果你在使用 Chrome 浏览器,同时使用像 Gmail 等 Google 的网络服务的话,其实你已经不再是通过 HTTP 访问这些服务了。在浏览器打开 chrome://net-internals/#spdy 就会发现你已经在使用 SPDY 协议了。(除了包括 Google 自家的 Gmail、Google Plus 等 Google 系服务外,其他公共站点例如 Twitter 和 Webtide 也已经支持该协议。在国内,基于 WebKit 的豌豆荚 2.0 也曾表示将引进Chrome的SPDY技术来进一步提升速度。

SPDY 的实现需要浏览器客户端和 Web 服务器同时支持。在客户端浏览器这快 Google自家的 Chrome 和Chromium 全系列不用说,都已经支持SPDY; Mozilla 家的 Firefox 自 Firefox 13 也默认开启对 SPDY 的支持。而亚马逊家的 Silk 利用 SPDY 的深度其实不比 Google 自家的 Chrome 和 Firefox 差。

在Web 服务器方面包括最流行和最广泛的 Apache 在内,Netty、Jeety、Varnish、Erlang 和 Hightide 应用服务器以及面向 node.js 的服务器也都已经宣布支持 SPDY。( Nginx 也表示将支持 SPDY)

  如何部署 SPDY?

近日 Google 正式发布了适用于最流行 Web 服务器 Apache 的插件 mod_spdy,将其下载安装后你的 Apache 服务器就能使用 SPDY 协议与兼容 SPDY 协议的浏览器如 Chrome、FireFox 等进行通信。像之前所说的那样,SPDY 是运行在 HTTPS 上,非 HTTPS 流量并不会受到 mod_spdy 影响。

  SPDY 部署要求:

1. Apache 2.2 (≥2.2.4)

2. mod_ssl 模块开启

  SPDY 部署步骤:

  1. 下载 mod_spdy 模块

下载页面下载对应系统的安装包

  2. 安装 mod_spdy 模块

在系统终端运行下面命令行

  dpkg -i mod-spdy-*.deb
apt-get -f install

-系统为 Debian/Ubuntu

————————————————————

  yum install at (if you do not already have ‘at’ installed)
rpm -U mod-spdy-*.rpm

-系统为 CentOS/Fedora

  3. 重启服务器(Apache)

  sudo /etc/init.d/apache2 restart (Debian/Ubuntu)

  4. 确定开启与否

打开 Chrome 浏览器,输入并前往 chrome://net-internals/#spdy 页面,查看主机名称是否出现在标识栏中。如果出现说明已经部署完毕,如果没有出现去服务器错误日志(error.log)里查询。

  未来的web基础?

在最新的协议文档里 Google 重新将 SPDY 分为了两层,其中一层被描述为 HTTP-like,大有取代 HTTP 的意图(Google 最近的一篇文章已经直呼 SPDY 为“a replacement for HTTP”)。同时 HTTP 2.0 标准制定工作组(HTTPbis)也表示,SPDY 很有希望接替当前的 HTTP 传输实现

考虑到 Chrome 和安卓的份额以及标准的推动,相信 SPDY 会有一个好前景。因此选择此刻支持 SPDY 也是明智的选择。

 

附:

浏览器是如何探测web server是否支持SPDY的?

The way Chrome achieves this backward-compatibility is by using the SSL Next Protocol Negotiation (NPN) extension during SSL handshaking. When the browser is establishing an SSL session, it mentions to the server that it’s willing to speak SPDY (as part of the ClientHello message). If the server also speaks SPDY, it can communicate that fact back to the client. If the client sees that the server supports SPDY, it proceeds to send SPDY messages over the newly established connection once the SSL handshaking is complete. Otherwise, it sends HTTP messages. The cool thing about this approach is that it doesn’t add any additional network round trips.

摘自: http://news.ycombinator.com/item?id=3030164

思考

在使用负载均衡的情况下,spdy会有什么问题吗?

javascript 中parent和window的概念

在多层iframe嵌套时,parent和window如何理解?

window和parent在IE和Firefox中的实现有些不太一样。

 

w3c中有如下叙述:http://www.w3schools.com/jsref/obj_window.asp

Window Object

The window object represents an open window in a browser.

If a document contain frames (<frame> or <iframe> tags), the browser creates one window object for the HTML document, and one additional window object for each frame.

 

1. 既然每个frame有自己的window,window.name为什么还一样?

 

 

参考资料:

http://www.w3schools.com/jsref/obj_navigator.asp

http://www.w3school.com.cn/htmldom/dom_obj_window.asp

 

关于无src的iframe的使用

这里演示了一个没有src的iframe,它存在的意义在于:

写在其内部的元素的样式不会受到父页面的css的影响。
使用”move”按钮,可以将form表单所在的浮层移动到iframe中,也可以从iframe中移动出来
通过移动前后的比较,你可以发现input元素的样式发生了变化,因为外部页面设置了样式
这里面还有一个有意思的现象:
我让iframe去appendChild一个iframe外部的div时,并不是复制一个div,而是直接移动div到目标位置(更像是我有些外行)

关于登录浮层的开发

缘起

最近考虑开发一个登录浮层,可以放置到任何的页面,使用方只需要引用JS,并对JS添加几项配置就可以使用。

遇到的问题:

1. 如果浮层中使用iframe的方式,则存在内外通信的跨域问题(可能这个比较方便解决)

2. 如果不适用iframe的方式,则很容易导致浮层和页面中的css的冲突(这个后患无穷)

 

分析:

考察了一下腾讯的登录浮层,果然,他们是使用了iframe的方式,我想,可能iframe会有一些问题,但这应该是正道

 

需要解决的问题:

1. 浮层内部如何与浮层外部通信,如:登录成功事件、关闭登录浮层事件。

 

思考:

对于一个没有src属性的iframe,其内部的脚本执行和父页面之间存在跨域问题吗?如果没有跨域问题,则完全可以使用外部的js来绘制iframe里面的内容

关于web页面的JS错误监控

一般来讲,server端的脚本错误可以通过日志来方便的监控,而web页面上的错误经常是通过用户反馈才知道的,甚至会因为环境问题无法重现而难以解决,下面介绍一种常见的web页面错误的收集、监控方法。

1. 对JS错误的监控,示例脚本:

或许你已经看到了,这哪里是“示例”,这分明就是从线上环境中抄来的;恩,不错,但是适合不适合自己,还需斟酌,这里只介绍一种思想; 举一反三一下,或许在你的强大的try…catch.. 之下,window.onerror基本没机会触发了,那么也可以在自己的catch中添加类似的逻辑,将意外的错误上传到服务器上,然后对这种错误信息做监控

2. 当然,不仅仅针对JS,比如flash等,也可以使用类似的手段

3. 我想,这应该是一个基础的功能,应该有一个基础的类库来支持,比如,badjs.qq.com 似乎是专门来做这个事情的,应该有专门的人来负责“上报错误脚本”的开发和上报错误的监控

 

从HTTP协议到PHP中的cookie 编码

 

实例脚本:

 

请求和响应:

输出:

结论:

  1. setcookie函数会对cookie的value做一次urlencode编码
  2. 客户端(浏览器)不会对cookie的value做任何转码
  3. PHP的server端在解析提交的cookie时,会对cookie的value做一次urldecode然后初始化到$_COOKIE数组中

延伸:

如果使用setrawcookie函数,对cookie的value不做urlencode,那么value中如果含有 “;”,则上行cookie的编码会是什么样的呢?(因为上行的多个cookie是靠”;”开分隔的)

测试代码:

结果:

 

结论:

1. 设置cookie时,cookie的value是需要urlencode的; 毕竟http协议中cookie的设置如下:

cookie的属性之间使用”;” 来分隔的,如果cookie的value中含有 “;” ,自然也不会当做value的一部分的

2. PHP对于上行的cookie也是做urldecode的(尽管多个cookie之间的分隔符不是”&”)

3.  从协议层不难看出,cookie名字也是不能有特殊字符的,就像value中不能函数特殊字符一样

 

PHP中setcookie的部分实现:

从上面实现,我们不难发现,cookie名字中不能含有哪些字符;而对于cookie值,如果允许编码,则允许任意字符了

 

注意

PHP中setcookie对value的编码使用的是urlencode:

1. urlencode对有些字符是不编码的,有些时候会带来不必要的麻烦

2. urlencode会将空格编码为’+’,而有些解码函数如JS中的 unescape 、decodeURIComponent 并不会将 ‘+’ 解码为空格的,于是cookie中的’hello world’,使用JS从cookie中取出后就会成为’hello+world’

针对上面两个问题,建议:

1. 自己对cookie值做rawurlencode,使用setrawcookie来设置cookie

2. 自己对cookie值做rawurlencode,使用header函数来set-cookie

 

关于cron

cron程序

cron程序用来周期性地启动某些进程。它通常使用crond程序或者crontab程序进行控制,你可以简单地把crond守护进程和crontab程序看成一个,它们实际是用同样的方式执行的,只是方法不同。

要使用cron的功能,首先需要启动crond守护进程,   我们先介绍最简单的设置cron的办法。在Linux系统中,cron程序的行为由/etc/crontab文件控制,这个文件由若干个部分组成,一般情 况下,它包括设置执行参数的部分和实际的命令部分,我们用一个示意性的crontab文件来描述它的基本格式:

#/etc/crontab

SHELL=/bin/bash

PATH=/sbin:/bin:/usr/sbin:/usr/bin

MAILTO=root

HOME=/

在一串#上面的部分是为cron设置的环境,这个环境现在设置的是使用bash。其他行的意义一目了然。

cron的执行语句,每个语句占据一行,代表一个作业设置,行可以由6个或者7个栏目构成,7个栏目的语句格式是

[分钟] [小时] [日期] [月份] [周中的天数] [用户] [命令]      分钟和小时就是你准备执行命令的钟点,日期则指的是月中的日期

例如,一个典型的crontab登记项可以写成      30 4 1 * * root rm -f /var/log/httpd/*

这里的五个时间域有两个是*号,表示通配,因此这里的时间域就是每个月的1日早晨4:30,执行命令的用户身份是root,后面的部分是命令。连起 来就是在每个月的1日4:30自动删除/var/log/httpd下面的所有文件。容易看出问题发生在同时设置日期和星期几的两个域的时候。例如,0 0 13 * 5到底是代表每月的13日零点,还是每星期五的零点,或者必须是“黑色的星期五”才能执行呢?     答案是这样的一个写法代表所有的13日加上所有的星期五都会执行这个命令。这一点是比较容易出现问题的地方。

当你书写crontab文件时一定要注意,crond程序设计得比较成问题,它要求每行必须以回车结尾:你可以在文件末尾加上几个空行,这不会影响crond运行,但是如果你的最后一行忘了加上一个回车,那么crond程序将会忽略这一行,不去执行对应的作业。

每个时间域都可以使用列表来设置多个值,例如,你想让某个任务在每天的2:00,4: 00和6:00运行,那么时间域的部分应该写成      0 2,4,6 * * *      另外一个常用的cron时间域符号是/,它代表“每”。举个例子来说,你想让某个任务每隔5分钟执行一次,当然你可以在分钟域中用 0,5,10,15,20,….55来处理这个问题, 但是你也可以用这样的方式来设置时间域:     */5 * * * *     在时间域中,可以使用减号代表集合,例如,在小时域中的8-12和8,9,10,11,12是等价的。

也可以用六个域来表示crontab表项,这时用户身份项被省略,其他各项的含义不变。     一般情况下,只要crond守护进程在运行中,它会每隔1分钟察看一次/etc/crontab文件,因此你修改了crontab文件之后不需要重新启动 crond程序,只要简单地等待就可以发现crond会刷新它的列表。如果发生了什么不寻常的事情,或者crond程序没有完成你设定的作业,你可以察看 /var/log/cron文件查阅问题的原因。     上面解释的是系统的cron作业设置,每个用户还可以设置自己的cron作业表。比如, 我是某个用户,我想每隔5分钟在虚拟控制台1上显示一下当前时间,那么我可以建立这样的一个文件:      */5 * * * * date > /dev/tty1      同样,回车符是不可缺少的。假设文件名字为testcron,然后用crontab命令设置作业表:      crontab testcron      这样就可以了。      同样,任何一个用户都可以建立自己的cron文件。

要察看某个用户自己设置的作业,使用crontab命令的-l-u 开关:      # crontab -l

要清除自己的作业列表,使用crontab -r命令。

crontab执行相关的权限文件有两个,分别是/etc/cron.allow和/etc/cron.deny。如果cron.allow文件存 在,系统试图从中读出可以执行crontab命令的用户名字,其他的用户(除了root)都无法使用这个命令;否则,如果cron.allow文件不存 在,系统将寻找/etc/cron.deny文件,如果存在的话,那么系统认为所有人都可以执行crontab命令,除了列在/etc /cron.deny中的用户;最后,如果这两个文件都不存在,除了root以外的其他用户将无法使用crontab命令.

at守护进程

at程序是另外一种管理作业的工具,与crond程序不同,at调度程序是设置程序在设定好的某个时刻执行,但是只执行一次。 要使用at调度程序,必须首先启动atd守护进程,语法很简单:      #/usr/sbin/atd      然后就可以用at命令调度作业了,例如,对我们想在三个小时之后, 也就是1:00开始这个进程(假设进程的名字是cpu_killer),那么,可以这样使用at命令:      $ at now + 3 hours      这里设置程序将在三个小时之后执行,也可以使用明确的时间:      $ at 1:00 kill_cpu     无论哪一种情况,都会出现at命令的提示符:      at>      可以输入命令:      at> kill_cpu      at>      在这个提示符下可以输入多个命令,直到你按下^D组合键:      at>       warning: commands will be executed using /bin/sh      job 2 at 2000-12-31 04:00       at命令的一般语法是      at [时间] [命令]      时间参数是启动命令的时间。at命令认识类似下面形式的命令:      1930 December 5   表示12月5日晚上19点30分      19:30 December 5 跟刚才的形式等效      11:00 pm    表示夜间23:00      11:00 P   同上      now + 1 week   从现在开始一周以后      4:30 Tuesday next week 下星期二4:30      5:15 12/05/2000         2000年12月5日早晨5:15        不是每个用户都可以使用at调度作业。

与at执行相关的权限文件有两个,分别是/etc/at.allow和/etc/at.deny。如果at.allow文件存在,系统试图从中读出 可以执行at命令的用户名字,其他的用户(除了root)都无法使用这个命令;否则,如果at.allow文件不存在,系统将寻找/etc /at.deny文件,如果存在的话,那么系统认为所有人都可以执 行at命令,除了列在/etc/at.deny中的用户;最后,如果这两个文件都不存在,除了root以外的其他用户将无法使用at命令。

 

摘自: http://hi.baidu.com/ezrax/blog/item/51caca06c7cc857f03088145.html

 

更多参考: http://zh.wikipedia.org/wiki/CRON

测试例子:

该cron是 2012年7月30号21点08分设置的,当日星期一,执行文件内容如下:

Mon Jul 30 21:09:01 CST 2012
Mon Jul 30 21:10:01 CST 2012
Mon Jul 30 21:11:01 CST 2012

 

看来,月份、日期和周之间确实是 “或” 的关系

 

关于共享库的学习笔记

关于共享库的学习可以参看: 《程序员的自我修养》

1. 为什么需要SONAME?

Linux中提供了一个工具叫做“ldconfig”,当系统中安装或更新一个共享库时,就需要运行这个工具,它会遍历所有的默认共享目录,比如/lib、/usr/lib等,然后更新所有的软连接,是他们指向最新版的共享库; 如果安装了新的共享库,那么ldconfig会为其创建相应的软连接。如果新版本的共享库文件被意外删除了,则软连接将自动更新到较低版本的共享库文件。

但是,如果你的共享库没有指定SONAME ,则ldconfig将无法自动更新软连接。

2. 如何查看共享库的SONAME

如图:

3. 不是所有的共享库都(必须)有SONAME,如何指定SONAME呢?

注意:使用 -Wl,-soname,your_soname 指定 你的SONAME

4. 使用了ldconfig后,编译新的程序还是找不到共享库(-lphpor),为什么?

ldconfig 只是为我们创建了满足程序运行的软连接,没有创建供程序编译使用的软连接;需要手动创建软连接:

程序编译之后,就和该软连接没有关系了,程序将只依赖指定的SONAME了

5. 相关命令的演示

6. 可以使用静态库生成共享库,不能使用共享库来编译出静态链接文件

gcc的 -static 的使用:(下面有些乱七八糟了,还没明白怎么回事儿)

7. 如何生成一个静态链接的共享库?

8.如何使用共享库生成一个静态链接文件?

 

关于PHP5.4的closure

参考: http://us.php.net/manual/en/closure.bind.php

有如下测试:

上述代码说明: 通过Closure的bind方法是可以访问一个对象的private属性的;这个是不是有悖于程序设计原则?