1. 显示当前的时间戳
date +%s
2. 修改系统时间
date -s 2008-08-08 08:08:08
3. 转化时间字符串为时间戳
date +%s -d "2008-08-08 08:08:08"
注意: 不要无意将 -d 写成-s ,那样你就无意修改了系统时间了
4. 按照指定格式输出时间
date +%F // 输出: 2009-09-22
date +%F –date=’1 days ago’ // 输出: 2009-09-21
DevOps
1. 显示当前的时间戳
date +%s
2. 修改系统时间
date -s 2008-08-08 08:08:08
3. 转化时间字符串为时间戳
date +%s -d "2008-08-08 08:08:08"
注意: 不要无意将 -d 写成-s ,那样你就无意修改了系统时间了
4. 按照指定格式输出时间
date +%F // 输出: 2009-09-22
date +%F –date=’1 days ago’ // 输出: 2009-09-21
对于一些非长连接的应用,可以通过计算连接的持续时间来知道处理时间的长短,首先通过tcpdump抓包,通过tcptrace可以知道连接的开始和结束时间,再用awk就可以统计了,基本命令如下:
tcpdump -i eth1 -w -| tcptrace -xrealtime stdin | awk ‘{ link = $2 "-" $3;if($4=="new")sum[link] = $1; else if($4 =="connection" && sum[link] > 0){ print link "\t" ($1-sum[link]) "\t" $6 " " $7 " " $8; delete sum[link];}}’
好像tcptrace本身是可以计算连接时间的长短的,应该是我还没有发现。
找见了:
tcptrace -l a.tcpdump | grep "elapsed time"
一、建立连接
在发送SYN报文段后,如果在75秒没有收到相应相应,连接建立将中止。这个时间也就是阻塞connect系统调用的超时时间。
二、保活
SO_KEEPALIVE选项保持连接检测对方主机是否崩溃,避免(服务器)永远阻塞于TCP连接的输入。设置该选项后,如果2小时内在此套接口的任一方向都没有数据交换,TCP就自动给对方 发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况:对方接收一切正常:以期望的ACK响应。2小时后,TCP将发出另一个探测分节。对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接口本身则被关闭。对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到一个响应。在发出第一个探测分节11分钟 15秒后若仍无响应就放弃。套接口的待处理错误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。
注意这里面有三个数字:
1.开始首次KeepAlive探测前的TCP空闭时间,2小时
2.两次KeepAlive探测间的时间间隔,75秒
3.判定断开前的KeepAlive探测次数,10次
也就是说,总共需要2小时+75秒*10次 = 7950秒
三、重传
重传定时器在发送数据时设定,超时值是计算出来的,取决于RTT和报文已被重传次数(并没有包括在以下公式内,但是BSD的实现确实用到了这个数据)。
RTT估计其,R是RTT,M是测量到的RTT,a推荐值为0.9
R = a * R + (1-a) * M
重传超时时间RTO, b推荐值为2
RTO = R * b
例外:快速重传,收到3个重复的ACK会立即重传
四、延时确认,捎带确认
TCP协议栈收到数据后并不立即发送ACK,而是等待200ms(推荐值,但是这个值不能高于500ms),如果在这段时间有用户数据需要发送则一同随着这个ACK发送。
五、FIN_WAIT_2定时器
某个连接准备关闭连接时,调用close函数,发送FIN报文,状态从SYN_RCVD迁移到FIN_WAIT_1,收到这个FIN的ACK后,迁移到FIN_WAIT_2状态。
为了防止对端一直不发送FIN,在等待10分钟后再等待75秒(定时器确实被设置了两次,所以分开说),超时,连接关闭。
六、2MSL定时器
MSL是最大报文段生存时间,RFC1122建议是2分钟,但BSD传统实现采用了30秒。当连接转移到TIME_WAIT状态时,即连接主动关闭时,定时器启动,为两倍的MSL。定时器超时,这时才能重新使用之前连接使用的端口号。这也是为了避免一些意想不到的边界情况,TCPIP详解第一卷的18.6.1给出了一个极端的例子。
七、平静时间
对于来自某个连接的较早替身的迟到报文段, 2 M S L等待可防止将它解释成使用相同插口对的新连接的一部分。但这只有在处于2 M S L等待连接中的主机处于正常工作状态时才有效。
如果使用处于2 M S L等待端口的主机出现故障,它会在M S L秒内重新启动,并立即使用故障前仍处于2 M S L的插口对来建立一个新的连接吗?如果是这样,在故障前从这个连接发出而迟到的报文段会被错误地当作属于重启后新连接的报文段。无论如何选择重启后新连接的初始序号,都会发生这种情况。
为了防止这种情况,RFC 793指出TCP在重启动后的MSL秒内不能建立任何连接。这就称为平静时间(quiet time)。
八、SO_LINGER的时间
这个选项会影响close的行为。如果linger结构中的l_onoff域设为非零,并设置了零超时间隔,则close不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式会发送RST报文段,且丢失了未发送的数据。在远端的读调用将以ECONNRESET出错。
若设置了SO_LINGER并确定了非零的超时间隔,则closes调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。如果套接口置为非阻塞且SO_LINGER设为非零超时,则close调用将以EWOULDBLOCK错误返回。
若在一个流类套接口上设置了SO_DONTLINGER(等效于SO_LINGER中将linger结构的l_onoff域设为零),则close调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。
下面是一个常见的获取用户ip的函数:
<?php
function getip()
{
if(getenv("HTTP_CLIENT_IP") && getenv("HTTP_CLIENT_IP")!="unknown")
$ip = getenv("HTTP_CLIENT_IP");
elseif(getenv("HTTP_X_FORWARDED_FOR") && getenv("HTTP_X_FORWARDED_FOR")!="unknown")
$ip = getenv("HTTP_X_FORWARDED_FOR");
elseif(getenv("REMOTE_ADDR") && getenv("REMOTE_ADDR")!="unknown")
$ip = getenv("REMOTE_ADDR");
else
$ip = "none";
return $ip;
}
?>
下面给出一个测试脚本:
<?php
$ch = curl_init();
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
curl_setopt($ch,CURLOPT_HTTPHEADER,array(‘X_FORWARDED_FOR: 158.10.10.10’));
curl_setopt($ch,CURLOPT_HTTPHEADER,array(‘CLIENT_IP: 159.10.10.10’));
curl_setopt($ch, CURLOPT_URL,"http://10.10.10.21/test.php");
echo curl_exec($ch);
curl_close($ch);
exit;
?>
http1.0: RFC 1945.
http1.1: RFC 2068
The Warning header
HTTP status codes indicate the success or failure of a request. For a successful response, the status code cannot provide additional advisory information, in part because the placement of the status code in the Status-Line, instead of in a header field, prevents the use of multiple status codes.
HTTP/1.1 introduces a Warning header, which may carry any number of subsidiary status indications. The intent is to allow a sender to advise the recipient that something may be unsatisfactory about an ostensibly successful response.
HTTP/1.1 defines an initial set of Warning codes, mostly related to the actions of caches along the response path. For example, a Warning can mark a response as having been returned by a cache during disconnected operation, when it is not possible to validate the cache entry with the origin server.
The Warning codes are divided into two classes, based on the first digit of the 3-digit code. One class of warnings must be deleted after a successful revalidation of a cache entry; the other class must be retained with a revalidated cache entry. Because this distinction is made based on the first digit of the code, rather than through an exhaustive listing of the codes, it is extensible to Warning codes defined in the future.
Other new status codes
There are 24 new status codes in HTTP/1.1; we have discussed 100 (Continue), 206 (Partial Content), and 300 (Multiple Choices) elsewhere in this paper. A few of the more notable additions include
* 409 (Conflict), returned when a request would conflict with the current state of the resource. For example, a PUT request might violate a versioning policy.
* 410 (Gone), used when a resource has been removed permanently from a server, and to aid in the deletion of any links to the resource.
Most of the other new status codes are minor extensions.
HTTP1.0
HTTP1.1
HTTP/1.0 does not define any 1xx status
codes and they are not a valid response to a HTTP/1.0 request.
100 Continue
101 Switching Protocols
Undifined
203 Non-Authoritative Information
Undifined
205 Reset Content
Undifined
206 Partial Content
Undifined
303 See Other
Undifined
305 Use Proxy
Undifined
402 Payment Required
Undifined
405 Method Not Allowed
Undifined
406 Not Acceptable
Undifined
407 Proxy Authentication Required
Undifined
408 Request Timeout
Undifined
409 Conflict
Undifined
410 Gone
Undifined
411 Length Required
Undifined
412 Precondition Failed
Undifined
413 Request Entity Too Large
Undifined
414 Request-URI Too Long
Undifined
415 Unsupported Media Type
Undifined
504 Gateway Timeout
Undifined
505 HTTP Version Not Supported
Changes to Simplify Multi-homed Web Servers and Conserve IP
Addresses
The requirements that clients and servers support the Host request-
header, report an error if the Host request-header (section 14.23) is
missing from an HTTP/1.1 request, and accept absolute URIs (section
5.1.2) are among the most important changes defined by this
specification.
Older HTTP/1.0 clients assumed a one-to-one relationship of IP
addresses and servers; there was no other established mechanism for
distinguishing the intended server of a request than the IP address
to which that request was directed. The changes outlined above will
allow the Internet, once older HTTP clients are no longer common, to
support multiple Web sites from a single IP address, greatly
simplifying large operational Web servers, where allocation of many
IP addresses to a single host has created serious problems. The
Internet will also be able to recover the IP addresses that have been
allocated for the sole purpose of allowing special-purpose domain
names to be used in root-level HTTP URLs. Given the rate of growth of
the Web, and the number of servers already deployed, it is extremely
important that all implementations of HTTP (including updates to
existing HTTP/1.0 applications) correctly implement these
requirements:
o Both clients and servers MUST support the Host request-header.
o Host request-headers are required in HTTP/1.1 requests.
o Servers MUST report a 400 (Bad Request) error if an HTTP/1.1
request does not include a Host request-header.
o Servers MUST accept absolute URIs.
HTTP/1.0
experimental implementations of persistent connections are faulty,
and the new facilities in HTTP/1.1 are designed to rectify these
problems. The problem was that some existing 1.0 clients may be
sending Keep-Alive to a proxy server that doesn’t understand
Connection, which would then erroneously forward it to the next
inbound server, which would establish the Keep-Alive connection and
result in a hung HTTP/1.0 proxy waiting for the close on the
response. The result is that HTTP/1.0 clients must be prevented from
using Keep-Alive when talking to proxies.
original HTTP/1.0 form of persistent
connections.
When it connects to an origin server, an HTTP client MAY send the
Keep-Alive connection-token in addition to the Persist connection-
token:
Connection: Keep-Alive
An HTTP/1.0 server would then respond with the Keep-Alive connection
token and the client may proceed with an HTTP/1.0 (or Keep-Alive)
persistent connection.
An HTTP/1.1 server may also establish persistent connections with
HTTP/1.0 clients upon receipt of a Keep-Alive connection token.
However, a persistent connection with an HTTP/1.0 client cannot make
use of the chunked transfer-coding, and therefore MUST use a
Content-Length for marking the ending boundary of each message.
A client MUST NOT send the Keep-Alive connection token to a proxy
server as HTTP/1.0 proxy servers do not obey the rules of HTTP/1.1
for parsing the Connection header field.
In HTTP/1.0, most implementations used a new connection for each
request/response exchange. In HTTP/1.1, a connection may be used for
one or more request/response exchanges, although connections may be
closed for a variety of reasons .
Web users speak many languages and use many character sets. Some Web resources are available in several variants to satisfy this multiplicity. HTTP/1.0 included the notion of content negotiation, a mechanism by which a client can inform the server which language(s) and/or character set(s) are acceptable to the user.
Content negotiation has proved to be a contentious and confusing area. Some aspects that appeared simple at first turned out to be quite difficult to resolve. For example, although current IETF practice is to insist on explicit character set labeling in all relevant contexts, the existing HTTP practice has been to use a default character set in most contexts, but not all implementations chose the same default. The use of unlabeled defaults greatly complicates the problem of internationalizing the Web.
HTTP/1.0 provided a few features to support content negotiation, but RFC1945 never uses that term and devotes less than a page to the relevant protocol features. The HTTP/1.1 specification specifies these features with far greater care, and introduces a number of new concepts.
The goal of the content negotiation mechanism is to choose the best available representation of a resource. HTTP/1.1 provides two orthogonal forms of content negotiation, differing in where the choice is made:
1.
In server-driven negotiation, the more mature form, the client sends hints about the user’s preferences to the server, using headers such as Accept-Language, Accept-Charset, etc. The server then chooses the representation that best matches the preferences expressed in these headers.
2.
In agent-driven negotiation, when the client requests a varying resource, the server replies with a 300 (Multiple Choices) response that contains a list of the available representations and a description of each representation’s properties (such as its language and character set). The client (agent) then chooses one representation, either automatically or with user intervention, and resubmits the request, specifying the chosen variant.
Although the HTTP/1.1 specification reserves the Alternates header name for use in agent-driven negotiation, the HTTP working group never completed a specification of this header, and server-driven negotiation remains the only usable form.
Some users may speak multiple languages, but with varying degrees of fluency. Similarly, a Web resource might be available in its original language, and in several translations of varying faithfulness. HTTP introduces the use of quality values to express the importance or degree of acceptability of various negotiable parameters. A quality value (or qvalue) is a fixed-point number between 0.0 and 1.0. For example, a native speaker of English with some fluency in French, and who can impose on a Danish-speaking office-mate, might configure a browser to generate requests including
Accept-Language: en, fr;q=0.5, da;q=0.1
Because the content-negotiation mechanism allows qvalues and wildcards, and expresses variation across many dimensions (language, character-set, content-type, and content-encoding) the automated choice of the best available” variant can be complex and might generate unexpected outcomes. These choices can interact with caching in subtle ways.
Content negotiation promises to be a fertile area for additional protocol evolution. For example, the HTTP working group recognized the utility of automatic negotiation regarding client implementation features, such as screen size, resolution, and color depth. The IETF has created the Content Negotiation working group to carry forward with work in the area.
A server MUST NOT send
transfer-codings to an HTTP/1.0 client.
19 附录
19.1 互联网媒体类型message/http和application/http
这篇文档除了定义HTTP/1.1协议外,还用作互联网媒介类型"message/http"和"application/http"的规范。此类型用于封装一个HTTP请求消息或响应消息,这假设此类型遵循MIME对 所有“消息”类型关于行长度和编的限制。application/http类型可以用来封装一个或者更多HTTP请求或响应信息(非混合的)的传输路径(pipeline)。下列是在IANA[17]注册的。
媒介类型名称: message
媒介次类型名称: http
必须参数: 无
可选参数: 版本,信息类型
版本:封装信息的HTTP版本号(例如,"1.1")。如果不存在,版本可以从消息的第一行确定。
信息类型:信息类型–"请求"或者"响应"。如果不存在,类型可以从报文的第一行确定。
编码考虑:只有"7bit","8bit",或者"二进制"是允许的。
安全考虑:无
媒介类型名称: application
媒介次类型名称: http
必须参数: 无
可选参数: 版本,信息类型
版本:封装信息的HTTP版本号(例如,"1.1")。如果不存在,版本可以从报文的第一行确定。
信息类型:信息类型–"request"或者"response"。如果不存在,类型可以从报文的第一行确定。
编码考虑:用这种类型封装的HTTP信息是"二进制"的格式;当通过E-mail传递的时候一种合适的内容传输编码是必须的。
安全考虑:无
19.2 互联网媒体类型multipart/byteranges
当一个HTTP206(部分内容)响应信息包含多个范围的内容(请求响应的内容有多个非重叠的范围),这些是作为一个多部分消息主体来被传送的。这种用途的媒体类型被称作"multipart/byteranges"。
multipart/byteranges媒体类型包括两个或者更多的部分,每一个都有自己Content-type和Content-Range头域。必需的分界参数(boundary parameter)指定分界字符串,此分界字符串用来隔离每一部分。
媒介类型名称: multipart
媒介次类型名称: byteranges
必须参数: boundary
可选参数: 无
编码考虑:只有"7bit","8bit",或者"二进制"是允许的。
安全考虑:无
例如:
HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-type:multipart/byteranges;boundary=THIS_STRING_SEPARATES
–THIS_STRING_SEPARATES
Content-type: application/pdf
Content-range: bytes 500-999/8000
…第一部分…
–THIS_STRING_SEPARATES
Content-type: application/pdf
Content-range: bytes 7000-7999/8000
…第二部分
–THIS_STRING_SEPARATES–
注意:
在实体(entity)中,在第一个分界字符串之前可以有多余的CRLFs。
虽然RFC 2046 [40]允许分界字符串加引号,但是一些现有的实现会不正确的处理分界字符串
许多浏览器和服务器是按照字节范围标准的早期草案关于使用multipart/x-byteranges媒体类型来进行编码的的,这个草案不总是完全和HTTP/1.1中描述的版本兼容。
19.3 宽松的应用程序 (Tolerent Applications)
虽然这篇文档列出了HTTP/1.1消息所必须的元素,但是并不是所有的程序在实现的时候都是正确的。因此我们建议当偏差可以明确解释的时候,运算程序对这种偏差应该是宽容的。
客户端应该宽松的解析Status-Line(状态行);服务器也应该宽松的解析Request-Line(请求行)。特别的,他们应该可以接受头域之间任何数量的SP或HT字符,即使协议规定只有一个SP。
消息头域的行终结符是CRLF。然而,当解析这样的头域时,我们建议应用程序能识别单一LF作为行终结符并能忽略CR。
实体主体(entity-body)的字符集应该被标记为应用于实体主体字符编码的最小公分母,并且期望不对实体进行标记要优于对实体标记为US-ASCII或ISO-8859-1。见3.7.1和3.4.1。
对关于日期分析和编码的要求的额外规则以及其它对日期编码的潜在问题包含:
Ø HTTP/1.1客户端和缓存应该假定一个似乎是50多年以后的RFC-850日期实际上是过去的(这有助于解决"2000年"问题)。
Ø 一个HTTP/1.1的实现可以内部地表示一个比正确日期值更早的已解析后的Expires日期,但是一定不要(MUST NOT)内部地表示一个比正确日期值更迟的已解析过的Expires日期。
Ø 所有过期日期相关的计算必须用GMT时间。本地时区一定不能(MUST NOT)影响年龄或过期时间的计算。
Ø 如果一个HTTP头域不正确的携带了一个非GMT时间区的日期值,那么必须利用最保守的可能转换把此日期值转换成GMT时间值。
19.4 HTTP实体和RFC 2045实体之间的区别
HTTP/1.1使用了许多Internet Mail(RFC 822 [9])和Multipurpose Internet Mail Extensions(MIME [7])里定义的结构,去允许实体以多种表现形式和扩展机制去传输。然而,RFC2045讨论邮件,并且HTTP有许多不同于RFC2045里描述的特征。这些不同被小心地挑选出来优化二进制连接的性能,为了允许使用新的媒体类型有更大的灵活性,为了使时间比较变得容易,和为了承认一些早期HTTP服务器和客户端的实效。
本附录描述了HTTP协议不同于RFC 2045的特殊区域。在严格的MIME环境中的代理和网关应该意识到这些不同并且在必要的时候要提供合适地转换。从MIME环境到HTTP的代理服务器和网关也需要意识到这些不同因为一些转换可能是需要的。
19.4.1 MIME版本(MIME-Version)
HTTP不是一个遵守MIME的协议。然而HTTP/1.1消息可以(MAY)包含一个单独的MIME-Version常用头域用来指出什么样的MIME协议版本被用于去构造消息。利用MIME-Version头域指明完全遵循MIME协议的消息(在RFC2045[7])。代理/网关要保证完全遵守MIME协议当把HTTP消息输出到严格MIME环境的时候。
MIME-Version = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
在HTTP/1.1用的缺省值是MIME1.0版本。然而,HTTP/1.1消息的解析和语义是由本文档而不是MIME规范定义的。
19.4.2转换到规范化形式 (Conversion to Canoical Form)
RFC 2045 [7]需要一个Internet mail实体在被传输之前要被转换成一个规范化的形式,这在RFC2049[48]里第四章里描述的。这篇文档的3.7.1节描述了当用HTTP协议传输时允许使用的”text”子媒体类型的形式。RFC2046要求以类型为“text”的内容要用CRLF表示为换行符,以及在换行符外禁止使用CR或LF。
RFC 2046需要像在"text"类型的内容里一样,用CRLF表示行间隔符并禁止在行间隔符序列以外使用CR或者LF。HTTP允许CRLF,单个CR,和单个LF来表示一个换行符在一个文本内容消息中。
在可能的地方,从HTTP到严格MIME环境的代理或网关应该(SHOULD)把RFC2049里描述的text媒体类型里所有换行符转换成RFC2049里CRLF的规范形式。然而,注意这可能在Content-Encoding出现的时候,以及HTTP允许利用一些没有利用13和10代表CR和LF的字符集时候都会变得复杂。
实现者应该注意转换将会破坏任何应用于源内容(original content)的密码校验和,除非源内容已经是规范化形式。因此,对任何在HTTP中使用校验和的内容被建议要表示为规范化形式。
19.4.3日期格式的转换 (Conversion of Date Formate)
为了简化日期比较的过程,HTTP/1.1使用了一个限制的日期格式(3.3.1节)。其它协议的代理和网关应该保证任何消息里出现的Date头域应该遵循HTTP/1.1规定的格式,如果有必要需要重写此日期。
19.4.4 Content-Encoding头域介绍 (Introduction of Content-Encoding)
RFC 2045不包含任何等价于HTTP/1.1里Content-Encoding头域的概念。因为这个头域作为媒体类型(media type)的修饰,从HTTP协议到MIME遵守的协议的代理和网关在转发消息之前必须既能改变Content-Type头域的值,也能解码实体主体(entity-body).。(一些为Internet mail类型的Content-Type的实验性的应用已经使用了一个媒体类型参数“; conversions=<content-coding>”去执行等价于Content-Encoding的功能。然而,此参数并不是RFC2045的部分)
19.4.5没有Content-Transfer-Encoding头域
HTTP不使用RFC 2045里的Content-Transfer-Encoding(CTE)头域。从使用MIME协议到HTTP的代理和网关在把响应消息发送给HTTP客户端之前必须删除任何非等价(non-identity,译注:identity编码,表示没有进行任何编码)CTE("quoted-printable"或"base64")编码。
从HTTP到MIME协议遵循的代理和网关要确保消息在那个协议安全传输上是用正确的格式和正确的编码,“安全传输”是通过使用的协议的限制而被定义的。这样一个代理或网关应该用合适的Content-Transfer-Encoding头域来标记数据如果这样做将提高安全传输的可能性。
19.4.6 Transfer-Encoding头域的介绍
HTTP/1.1介绍了Transfer-Encoding头域(14.41节)。代理/网关在转发经由MIME协议的消息之前必须移除任何传输编码。
一个解码"chunked"传输代码(3.6节)的程序可以用代码表示如下:
length := 0
read chunk-size, chunk-extension (if any) and CRLF
while (chunk-size > 0) {
read chunk-data and CRLF
append chunk-data to entity-body
length := length + chunk-size
read chunk-size and CRLF
}
read entity-header
while (entity-header not empty) {
append entity-header to existing header fields
read entity-header
}
Content-Length := length
Remove "chunked" from Transfer-Encoding
19.4.7 MHTML和行长度限制
和MHTML实现共享代码的HTTP实现需要了解MIME行长度限制。因为HTTP没有这个限制,HTTP并不折叠长行。用HTTP传输的MHTML消息遵守所有MHTML的规定,包括行长度的限制和折叠,规范化等,因为HTTP传输所有消息主体(见3.7.2)并且不解析消息的内容和消息中包含任何MIME头域。
19.5 其它特征
RFC 1945和RFC 2068里一些协议元素被一些已经存在的HTTP实现使用,但是这些协议元素对于大多数HTTP/1.1应用程序既不兼容也不正确。实现者被建议去了解这些特征,但是不能依赖于它们的出现或不依赖于与其它HTTP/1.1应用程序的互操作性。这些特征中的一些特征描述了实验性的特征,以及还有一些特征描述了没有在基本HTTP/1.1规范里被描述的实验性部署特征。
一些其它头域,如Content-Dispositon和Title头域,他们来自于SMTP和MIME协议,他们同样经常被实现(见2076[37]).
19.5.1 Content-Disposition
Content-Disposition响应头域被建议作为一个这样的用途,那就是如果用户请求要使内容被保存为一个文件,那么此头域被源服务器使用去建议的一个缺省的文件名。此用途来自于RFC1806[35]关于对Content-Disposition的定义。
content-disposition = "Content-Disposition" ":"
disposition-type *( ";" disposition-parm )
disposition-type = "attachment" | disp-extension-token
disposition-parm = filename-parm | disp-extension-parm
filename-parm = "filename" "=" quoted-string
disp-extension-token = token
disp-extension-parm = token "=" ( token | quoted-string )
一个例子是:
Content-Disposition: attachment; filename="fname.ext"
接收用户的代理不应该(SHOULD NOT)关注任何在filename-parm参数中出现的文件路径信息,这个参数被认为在这次仅仅是应用于HTTP实现。文件名应该(SHOULD)只被当作一个终端组件。
如果此头域用于一个Content-Type为application/octet-stream响应里,那么含义就是用户代理不应该展现响应,但是它应该直接进入一个‘保存响应为…’对话框。
见15.5节关于Content-Disposition的的安全问题。
19.6 和以前版本的兼容
要求和以前的版本的兼容超出了协议规范的范围。然而HTTP/1.1有意设计成很容易支持以前的版本。必须值得注意的是,在写这份规范的时候,我们希望商业的HTTP/1.1服务器去:
–接受HTTP/0.9,1.0和1.1请求的请求行(Request-Line)格式;
–理解HTTP/0.9,1.0或1.1格式中的任何有效请求;
–恰当地用客户端使用的主要版本来响应。
并且我们希望HTTP/1.1的客户端:
–接受HTTP/1.0和1.1响应的状态行(Status-Line)格式;
–懂得HTTP/0.9,1.0或1.1的格式的任何有效的响应。
对大多数HTTP/1.0的实现,每一个连接要在请求之前被客户端建立,并且在发送响应之后要被服务器关闭。一些实现了在RFC 2068 [33]的19.7.1节描述的持久连接的Keep-Alive版本。
19.6.1对HTTP/1.0的改变
这一部分总结HTTP/1.0和HTTP/1.1之间主要的区别。
19.6.1.1 对多主机web服务器和保留IP地址简化的改变
客户端和服务器必须支持Host请求头域,并且如果Host请求头域在HTTP/1.1请求里缺少,那么服务器应该报告一个错误,并且服务器能接受一个绝对URIs(5.1.2节),对于这个要求是在此规范里最重要的改变。上面的改变将允许互联网,一旦旧的客户端不再常用时,去支持一个IP地址的多个web站点,这大大简化了大型运算的web服务器,在那里分配多个IP地址给一个主机(host)会产生很严重的问题。此互联网照样能恢复这样一个IP地址,此IP地址作为特殊目的被分配给被用于根级HTTPURLs的域名。给定web的增长速度,服务器的部署数量部,那么所有HTTP实现(包括对已存HTTP/1.0应用程序)应该正确地满足下面这些需求:
–客户端和服务器都必须(MUST)支持Host请求头域。
–发送HTTP/1.1请求的客户端必须(MUST)发送Host头域。
–如果HTTP/1.1请求不包括Host请求头域,服务器就必须(MUST)报告错误400(Bad Request)。
–服务器必须(MUST)接受绝对URIs(absolute URIs)。
19.6.2和HTTP/1.0持续连接的兼容
一些客户端和服务器可能希望和一些对以前持续连接实现的HTTP/1.0客户端和服务器兼容。HTTP/1.0持久连接需要显示地协商,因为它们不是缺省的行为。持久连接的HTTP/1.0实验性的实现有错误,并且HTTP/1.1里的新的功能被设计成去矫正这些问题。此问题是一些已经存在的1.0客户端可能会发送Keep-Alive头域给不理解连接的代理服务器,然后代理服务器会把此Keep-Alive转发给下一个入流(inbound)服务器。所以HTTP/1.0客户端必须禁止利用Keep-Alive当和代理会话的时候。
然而,和代理进行会话最重要是利用持久连接,所以那个禁止很显然不能被接受。因此,我们需要一些其它的机制去指明需要一个持久连接,并且它必须能安全的使用甚至当和忽略连接的老代理。持久连接缺省是为HTTP/1.1消息的;为了声明非持久连接(见14.10节),我们介绍一个新的关键字(Connection:close)。
持久连接的源HTTP/1.0的形式(the Connection: Keep-Alive and Keep-Alive 头域)在RFC2068里说明
19.6.3对RFC 2068的改变
这篇规范已经被仔细的审查来纠正关键字的用法和消除它们的歧义;RFC 2068在遵守RFC 2119 [34] 制定的协定方面有很多问题。
澄清哪个错误代码将会使入流服务器失灵(例如DNS失灵)。(10.5.5节)
Create有一个特点当一个资源第一次被创建的时候必须需要一个Etag。(10.2.2节)
Content-Base头域从此规范里删除了:它无法广泛的实现,并且在没有健壮的扩展机制的情况下,没有简单的,安全的方式去介绍它。并且,它以一种相似的而不是相同的方式在MHTML[45]里被使用。
出色的软件工程师善用设计模式,勤于代码重构,编写单元测试,并对简单有宗教般的追求。除了这些,优秀的软件工程师还要通晓10个概念,这10个概念超越了编程语言与设计模式,软件工程师应当从更广的范围内明白这些道理。
10. 关系数据库 (Relational Databases)
关系数据库因为在大规模 Web 服务上缺乏可扩充性而颇受微词,然而,关系数据库仍然是近20年来计算机技术中最伟大的成就。关系数据库对处理订单,公司数据方面有着出色的表现。
关系数据库的核心是以记录表示数据,记录存放在数据库表,数据库使用查询语言(SQL)对数据进行搜索与查询,同时,数据库对各个数据表进行关联。
数据库的标准化技术(normalization)讲的是使用正确的方式对数据进行分存以降低冗余,并加快存取速度。
9. 安全 (Security)
随着黑客的崛起与数据敏感性的上升,安全变得非常重要。安全是个广义的概念,涉及验证,授权与信息传输。
验证是对用户的身份进行检查,如要求用户输入密码。验证通常需要结合 SSL (secure socket layer)进行;授权在公司业务系统中非常重要,尤其是一些工作流系统。最近开发的 OAuth 协议可以帮助 Web 服务将相应信息向相应用户开放。Flickr 便使用这种方式管理私人照片和数据的访问权限。
另外一个安全领域是网络设防,这关系到操作系统,配置与监控。不仅网络危险重重,任何软件都是。Firefox 被称为最安全的浏览器,仍然需要频频发布安全补丁。要为你的系统编写安全代码就需要明白各种潜在的问题。
8. 云计算 (Cloud Computing)
RWW 最近的关于云计算的文章 Reaching For The Sky Through Compute Clouds 讲到了云计算如何改变大规模 Web 应用的发布。大规模的并行,低成本,与快速投入市场。
并行算法发明以来,首先迎来的是网格计算,网格计算是借助空闲的桌面计算机资源进行并行计算。最著名的例子是 Berkley 大学的 SETI@home 计划,该计划使用空闲的 CPU 资源分析太空数据。金融机构也大规模实施网格计算进行风险分析。空闲的资源,加上 J2EE 平台的崛起,迎来了云计算的概念:应用服务虚拟化。就是应用按需运行,并可以随着时间和用户规模而实时改变。
云计算最生动的例子是 Amazon 的 Web 服务,一组可以通过 API 进行调用的应用,如云服务(EC2),一个用来存储大型媒体文件的数据库(S3),索引服务(SimpleDB),序列服务(SQS)。
7. 并发 (Concurrency)
并发是软件工程师最容易犯错的地方,这可以理解,因为我们一直遵从线形思维,然而并发在现代系统中非常重要。
并发是程序中的并行处理,多数现代编程语言包含内置的并发能力,在 Java,指的是线程。关于并发,最经典的例子是“生产/消费”模式,生产方生产数据和任务,并放入工作线程消费或执行。并发的复杂性在于,线程需要经常访问共同数据,每个线程都有自己的执行顺序,但需要访问共同数据。Doug Lea 曾写过一个最复杂的并发类,现在是 core Java 的一部分。
6. 缓存(Caching)
缓存对现代 Web 程序不可或缺,缓存是从数据库取回,并存放在内存中的数据。因为数据库直接存取的代价非常高,将数据从数据库取回并放在缓存中访问就变得十分必要。比如,你有一个网站,要显示上周的畅销书,你可以从数据将畅销书榜一次性取回放在缓存中,而不必在每次访问时都去数据库读数据。
缓存需要代价,只有最常用的内容才可以放入缓存。很多现代程序,包括 Facebook,依靠一种叫做 Memcached 的分布式缓存系统,该系统是 Brad Firzpatrick 在工作于 LiveJournal 项目时开发的,Memcached 使用网络中空闲的内存资源建立缓存机制,Memcached 类库在很多流行编程语言,包括 Java 和 PHP 中都有。
5. 散列法(Hashing)
Hashing 的目的是加速访问速度。如果数据是序列存储的,从中查询一个项的时间取决于数据列的大小。而散列法对每一个项计算一个数字作为索引,在一个好的 Hashing 算法下,数据查找的速度是一样的。
除了存储数据,散列法对分布式系统也很重要。统一散列法(uniform hash )用来在云数据库环境下,在不同计算机之间分存数据。Google 的索引服务就是这种方法的体现,每一个 URL 都被散列分布到特定计算机。
散列函数非常复杂,但现代类库中都有现成的类,重要的是,如何对散列法进行细调以获得最好的性能。
4. 算法的复杂性 (Algorithmic Complexity)
关于算法的复杂性,软件工程师需要理解这样几件事。第一,大O标记法(big O notation);第二,你永远都不应该使用嵌套式循环(循环里面套循环),你应该使用 Hash 表,数组或单一循环;第三,如今优秀类库比比皆是,我们不必过分纠缠于这些库的效能的差别,我们以后还有机会进行细调;最后,不要忽视算法的优雅及性能,编写紧凑的,可读的代码可以让你的算法更简单,更干净。
3. 分层 (Layering)
用分层来讨论软件架构是最容易的。John Lakos 曾出版过一本关于大型 C++ 系统的书。Lakos 认为软件包含了层,书中介绍了层的概念,方法是,对每个软件组件,数一下它所依赖的组件数目就可以知道它的复杂程度。
Lakos 认为,一个好的软件拥有金字塔结构,就是说,软件组件拥有层层积累的复杂度,但每个组件本身必须简单,一个优秀的软件包含很多小的,可重复使用的模块,每个模块有自己的职责。一个好的系统中,组件之间的依赖性不可交叉,整个系统是各种各样的组件堆积起来,形成一个金字塔。
Lakos 在软件工程的很多方面都是先驱,最著名的是 Refactoring (代码重构)。代码重构指的是,在编程过程中需要不断地对代码进行改造以保证其结构的健壮与灵活。
2. 惯例与模板 (Conventions and Templates)
命名惯例和基础模板在编程模式中常被忽视,然而它可能是最强大的方法。命名惯例使软件自动化成为可能,如,Java Beans 框架在 getter 和 setter 方法中,使用简单的命名惯例。del.icio.us 网站的 URL 命名也使用统一的格式,如 http://del.icio.us/tag/software 会将用户带到所有标签为 software 的页。
很多社会网络均使用简单命名,如,你的名字是 johnsmith ,那你的头像可能命名为 johnsmith.jpg,而你的 rss 聚合文件的命名很可能是 johnsmith.xml 。
命名惯例还用于单元测试,如,JUnit 单元测试工具会辨认所有以 test 开头的类。
我们这里说的模板(templates )指的并不是 C++ 或 Java 语言中的 constructs,我们说的是一些包含变量的模板文件,用户可以替换变量并输出最终结果。
Cold Fusion 是最先使用模板的程序之一,后来,Java 使用 JSP 实现模板功能。Apache 近来为 Java 开发了非常好用的通用模板, Velocity。PHP 本身就是基于模板的,因为它支持 eval 函数。
1. 接口(Interfaces)
软件工程中最重要的概念是接口。任何软件都是一个真实系统的模型。如何使用简单的用户接口进行模型化至关重要。很多软件系统走这样的极端,缺乏抽象的冗长代码,或者过分设计而导致无谓的复杂。
在众多软件工程书籍中,Robert Martin 写的《敏捷编程》值得一读。
关于模型化,以下方法对你会有帮助。首先,去掉那些只有在将来才可能用得着的方法,代码越精练越好。第二,不要总认为以前的东西是对的,要善于改变。第三,要有耐心并享受过程。
1.
现象: 200 个并发,请求一个非常简单的html,httpd子进程只有20个,使用netstat 查看,发现很多已建立的连接被阻塞
分析:
因为html太简单,处理速度飞快
如果限制了每个子进程允许处理的请求数,则可能进程死的很快(比创建的快),这样进程数就
总是上不去,可以加大每个子进程允许处理的请求数,最大为0
如果该httpd服务器监听的不是一个sock,则多进程之间需要互斥,都要先给一个信号量加锁,这样进程的
很多时间都用到了争夺互斥量了,至少表现为清闲,所以,apache不会再派生更多的子进程。解决办法是:
如果监听的是同一个端口,可以使用listen *:port ,而不是每个ip都写一个listen
如果监听的不是一个端口,可以考虑不同的端口使用不同的server
2.
现象:我的httpd只监听了一个端口,200个并发,httpd子进程数才70个
分析:可能70子进程已经足以处理你的200个并发了,使用netstat看看,没有阻塞的连接就行了
有时候,处于测试的需要,我们想有一个很大的文件,但是手头又没有大文件,怎么办呢?
1. 如果你在Linux上,那么,试试这个:
dd if=/dev/zero of=/path/to/bigfile bs=1024000 count=1000
这样就生成了1024000 × 1000 (即:1G) 的文件了
2. 如果你安装了PHP环境的话
php -r ‘$fp = fopen("/path/to/biggile","w");echo ftruncate ($fp,1024*1000*1000);’
这样也生成了一个1G的文件
记得Solaris里有mkfile这个系统调用的,可以生成指定大小的文件,但是Linux下好像没有;总以为ftruncate 只能将文件截短,其实还能将文件加长;
预生成指定大小的文件对于多进程下载时是比较有用的,我们知道的文件的长度之后,直接创建指定大小的文件,然后就可以多线程下载了。