CCNP 筆記本

2011 年 02 月 08 日

FTP 運作原理

Filed under: 網路基本服務原理 — nkongkimo @ 11:25:11

基本觀念

使用 FTP 傳輸時,至少會使用到兩個 Port 來建立連線通道:

  • 一個為指令通道(Command Channel),預設使用 Port 21 建立連線,用來傳輸 FTP 指令,例如:列出檔案清單(LIST)、變更目錄(CWD)、取得目前的目錄(PWD)、……等。
  • 另一個為資料通道(DATA Channel),預設使用 Port 20,但是會因 FTP Client 選擇使用的「連線模式」不同而有所不同。

一般來說,指令通道的連線與下指令都沒有什麼問題,有問題的通常是在資料通道的建立,而資料通道的建立方式是由 FTP Client 所下的指令決定的,以 FileZilla 設定為例(如下圖):

clip_image002

FTP Client (e.g. FileZilla) 每次建立連線時都會下 PORT 或 PASV 指令,如下範例:

    指令: PASV

    回應: 227 Entering Passive Mode (59,37,124,43,158,251)

而每次下指令傳輸資料時,都會建立一次 data connection,包括取得遠端的檔案清單(LIST)時回傳的檔案列表、下載檔案、或上傳檔案。

 

連線模式

FTP 的連線模式分兩種:主動模式 ( Active mode ) 與 被動模式 ( Passive mode )

主動模式 ( Active mode )

FTP Client 跟 FTP Server 連線後,會主動利用 PORT 指令提出 DATA Channel 連線的要求,如下:

    指令: PORT 10,18,53,171,17,114

    回應: 200 Port command successful.

這裡的 PORT 指令是由 FTP Client 送出的,當需要建立 DATA Channel 時,FTP Server 會主動利用 Server 主機的 Port 20 發出連線到 FTP Client 的主機,而 PORT 指令後的參數說明如下:

  • 前四個數字是 FTP Client 的 IP 位址:10.18.53.171
  • 後兩個數字是 FTP Client 接受連線的 Port 埠號,埠號的計算方式是 (第五個數字 * 256 + 第六個數字),以此範例來說,FTP Client 接受的連線埠號是 17 * 256 + 114 = 4,466

由此可知,如果 FTP Client 處於 NAT 的環境下的話,FTP Server 幾乎無法正常的連線到 FTP Client 的主機,所以現在大部分的連線模式幾乎都建議使用者使用被動模式(Passive mode)。

範例:

image

 

被動模式 ( Passive mode )

FTP Client 跟 FTP Server 連線後,會主動利用 PASV 指令提出 DATA Channel 連線的要求,如下:

    指令: PASV

    回應: 227  Entering Passive Mode  (59,37,124,43,158,251)

你可以看到由 FTP Client 送出的 PASV 指令並沒有送出其他的參數,而是在 FTP Server 回應的時候出現了 (59,37,124,43,158,251) 字串,當需要建立 DATA Channel 時,這時就會由 FTP Client 主動連接至 FTP Server 動態開放的 Port 供 FTP Client 連接,其中 (59,37,124,43,158,251) 的說明如下:

  • 前四個數字是 FTP Server 的 IP 位址:59.37.124.43
  • 後兩個數字是 FTP Server 接受連線的 Port 埠號,埠號的計算方式是 (第五個數字 * 256 + 第六個數字),以此範例來說,FTP Server 可接受的連線埠號是 158 * 256 + 251 = 40,699

由此可知,使用被動模式(Passive mode)對 FTP Server 的系統管理員來說,可掌控的部分是比較多的,因為 FTP Server 無法決定使用者是否可使用主動模式連線,但若改使用被動模式連線的話,就幾乎能讓所有人正常的使用 FTP 服務。

範例:

image

其他資訊

  • 在 IIS 的 FTP 服務中,當使用 Passive mode 時,IIS FTP 會自動開啟短暫的 Port 用以建立 DATA Channel 供 FTP Client 連接,IIS 預設會動態使用 Port 1024 ~ 65535 進行 DATA Channel 的連線,若要修改預設的 Port Range 可以參考我昨天的文章:如何調整 IIS FTP 在 Passive mode 使用的 Port Range
  • 在 Linux kernel 中,若有設定 MASQ 的話,Kernel 已經支援「動態開啟 FTP DATA PORT」功能,也就是說在 FTP Client 端在 NAT 內部也能以 Active mode 使用 FTP,這就是為什麼有些人在公司內部使用虛擬 IP 也能夠使用主動模式(Active mode)傳輸檔案的情形。
廣告

2010 年 04 月 30 日

Wins Server 筆記

Filed under: 網路基本服務原理 — nkongkimo @ 02:56:09

Windows TCP/IP Protocol

Windows OS有2種TCP/IP的Protocol,Win Sockets 和 NetBIOS。
1.Windows Sockets Application:
特性:
(1)IP為主,名稱為輔
(2)一定需要IP才可以工作。
(3)目前大部分的程式都使用WIN Sockets的Protocol
應用程式:
MSN、Outlook、Browser…
2.NetBIOS Applications:
特性:
(1)以名稱為主,IP為輔
(2)總共有16個byte,前15個byte用來區分電腦名稱,
(3)NetBIOS的名稱再網路上不可重覆,如遇到重覆的狀況,後來的會無法上網。
應用程式:
File Sharing、Print Sharing、Windows管理程式…

 

NetBIOS Name Resolution

當PC要查詢一台主機的時候會做這些事:
1.先查詢自己的NetBIOS Cache有沒有資料。
2.若自己的cache 沒有資料會向Wins Server詢問。
3.若都沒有資料會自己Brocast來查詢。
目前的OS都是以這樣的模式在查詢主機。
但是在95/98的OS會直接brocast去查詢。
1.B-node:
只使用Brocast的方式查詢。
2.P-node:
使用Wins Server去查詢主機
3.M-node:
先使用Brocast的方式再使用WINs Server的方式
4.H-node:
先使用WINs Server的方式再使用Brocast的方式
5.若PC是使用DHCP 自動取得IP的方式,可以直接把WINs Server加進來即可。

 

NetBIOS的主要功能

1.減少Brocast的封包。
2.若沒有WINs Server可以再PC設定LMhost
但是LMhost需要每一台PC去設定,故建議還是使用WINs Server比較方便。

 

PC 與WINs Server的行為

1.PC會把IP跟PC名稱來WINS Server註冊。
WINs Server會回PC 註冊成功及TTL值
2.PC會定期向WINs Server 告知目前的狀況。
3.PC會向WINs Server查詢
4.PC再關機時會自動向WINs Server刪除自己的資料。
5.以上的行為再2個封包即可完成。

 

PC查詢WINs 的步驟

1.PC會查詢自己WINs 列表的WINs Server,會先由第一筆WINs Server開始詢問。
2.當詢問3次沒有反應,PC會使用第2台WINS Server詢問。

 

WINs有跨WAN的時候

1.這個動作叫做WINS Replication(等同sync的意思)
2台SYNC運作的方法為看更新的版本,與DNS 交換一樣,若版本有更新才交換資料。

 

Replication的模式

1.Push的模式

運作的步驟:
(1)WINS-A設定一個門檻值
(2)當WINS-A達到門檻值時,會主動告知WINS-B,請WINS-B來向WINS-A更新資料
(3)WINS-B來更新資料
(4)WINS-A把新的資料傳送給WINS-B。

2.Pull的模式

 

運作的步驟:
(1)WINS-A設定多久與WINS-B同步資料
(2)雙邊都會做一樣的動作

2010 年 04 月 28 日

DNS 筆記

Filed under: 網路基本服務原理 — nkongkimo @ 02:24:39

Domain Namespace

1.Root Domain:由美國(ICANN)掌管。

2.FQDN(Full Quailified Domain Name):完全合格的Domain名稱

3.台灣的.com.tw都必須先到root Domain註冊,才可以使用

4.DNS Server的作用就是解析FQDN的到正確的IP Address

 

 

DNS的查詢種類

Query的種類:
1.Interative Query:
DNS Server只會在自己的DB裡面找到一個最接近的答案告知來詢問的Client.2.Recursive Query:
DNS Server會現在自己的DB尋找,若沒有找到會上internet的各個DNS Server詢問正確的答案,在把正確的答案告知來詢問的Client
Lookup的整類:
1.Forwarding Lookup(正向查詢):
由FQDN解析IP Address2.Reverse Lookup(反向查詢):
由IP解析FQDN

 

Recursive Query解釋

1.DNS Server可能自己有記錄這一筆資料 所以直接告知PC,若DNS Server沒有這一筆資料,會由DNS Server向外查詢到正確的資料在回傳給PC.
2.最常發生Recursive Query的封包發生在PC向DNS Server詢問FQDN的時候.


 

Interative Query解釋

1.Interative Query 會由範圍最大的開始詢問,一直問到最準確的資訊,在把最準確的資訊告知PC。
2.最常發生DNS Server與DNS Server查詢時。

 

Root Hint的解釋

1.Root Hint就是Root Domain 下的的13台主要DNS Server
2.Root Hint 基本上都會被寫入DNS Server裡面,當在查詢時就可以直接到Root DNS查詢,建議把ISP的DNS加進來,以利加速查詢。

 

Forwarder的功能

1.把Local DNS Server Query的方式由Interative Query轉變成Recuresive Query的方式,換句話說就是由上層的DNS Server幫Local的DNS Server去查詢正確的FQDN資料。
2.通常Forwarder的DNS Server是ISP提供的DNS Server
3.可以減少Local DNS Server resource的消耗,也可以減少頻寬的消耗

 

DNS Zone

1.DNS Zone:
DNS 以Zone為單位,管理也是以Zone一個單位,名稱有連續的才算是一個Zone
ex:
Training.north.nwtraders—>算是一個Zone
單獨的North與West不算是一個zone,因為他們沒有與Nwtraders相關連

 

DNS Zone Typer

1.Primary Zone DNS:
有修改及增加的權限。
2.Secondry Zone DNS:
只有讀的權限。
沒有限制多少台Secondry DNS server。
3.Stub Zone DNS:
只記錄Primary DNS的IP資訊。
行為就是發Recursive Query去給Primary DNS詢問正確的DNS資訊。

 

Zone Transfer(Zone 資料的copy)

1.行為的模式:
當Primary DNS的資料有修改時,會自動Update Secondry DNS。
2.當Primary DNS 掛掉了,Secondry DNS會自動接手,但是無法增加或修改裡面的資料。
3.Secondary 會自動去找Primary DNS copy 資料。也可以找另一台Secondary copy資料。

 

Resource Records

A:
Address Record 主要記錄設備的名稱與設備IP的位址。
PTR:
Point Record 主要用在反向查詢使用,用在那一個IP對應到那一個設備名稱。
SOA:
授權記錄,每一個Zone的第一筆記錄,記錄了Zone的名稱與聯絡資訊。
SRV:
Service記錄,記錄哪一台Server提供哪一種服務。
在Internet沒有人使用,但是常被用在LAN裡面。
NS:
NS Record表示DNS Server的IP,但是無法得知是Primary或是Secondary DNS Server。
MX:
Mail Exchange的紀錄,表示Mail Server是那一台。
CNAME:
別名的紀錄,當多個服務都在同一台Server上時,可以使用CNAME的紀錄來表示多種服務。

 

DNS Server 角色

Cache-only server:
只要開啟DNS的功能就自動啟用此功能。
Non-Recuresive Server:
只提供Internet來查詢的功能(Interative Query),不接受Recursive Query的封包。
Forward-only Server:
把PC來的Recursive Query的在轉到ISP的DNS Server去做Recursive Query 動作。
Conditional Forwarder:
針對有設定的轉送資料

 

Time-to-Live

1.PC發Recursive Query向DNS詢問,DNS會回正確的資訊給PC,並在自己的DB保留一份,這時外部的DNS主機會告知TTL的值,都以秒為單位。
2.TTL表示DNS記錄存活的時間。

 

DNS Server的規劃

第1種:
內網跟外網都相同Domain Name,且2台DNS都是Primary DNS Server,維護上比較花時間,且較不安全。
第2種:
內網使用AD整合的DNS Server。
第3種:
內網跟外網使用不同的Domain Name,較建議使用使方法。內網的安全性比較高。

 

DNS Server的架設

外網的DNS Server放在DMZ區,內網的DNS Server使用forwarder的模式,把DNS的Query都只到外網的DNS Server,這樣就部會暴露內部DNS的資訊。
在DMZ區放置Secondary的DNS,內網放置一台Primary的DNS Server。
當Secondary DNS被攻擊時也部會影響到Primary DNS Server。
較建議此架構,但需要2台對外服務的DNS Server。

Http Header入門

Filed under: 網路基本服務原理 — nkongkimo @ 00:27:17

HTTP Headers 入門

本文系統的對HTTP Headers進行了簡明易懂的闡述,我僅稍作筆記。

什麼是HTTP Headers

HTTP是“Hypertext Transfer Protocol”的所寫,整個www都在使用這種協定,幾乎你在流覽器裏看到的大部分內容都是通過http協定來傳輸的,比如這篇文章。

HTTP Headers是HTTP請求和相應的核心,它承載了關於用戶端流覽器,請求頁面,伺服器等相關的資訊。


示例

當你在流覽器位址欄裏鍵入一個url,你的流覽器會將類似如下的http請求:
GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1 (Request line)
Host: net.tutsplus.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120
Pragma: no-cache
Cache-Control: no-cache
第一行被稱為“Request Line” 它描述的是這個請求的基本資訊,剩下的就是HTTP headers了。

請求完成之後,你的流覽器可能會收到如下的HTTP回應:

HTTP/1.x 200 OK (state line)
Transfer-Encoding: chunked
Date: Sat, 28 Nov 2009 04:36:25 GMT
Server: LiteSpeed
Connection: close
X-Powered-By: W3 Total Cache/0.8
Pragma: public
Expires: Sat, 28 Nov 2009 05:36:25 GMT
Etag: “pub1259380237;gz"
Cache-Control: max-age=3600, public
Content-Type: text/html; charset=UTF-8
Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT
X-Pingback: http://net.tutsplus.com/xmlrpc.php
Content-Encoding: gzip
Vary: Accept-Encoding, Cookie, User-Agent
<!– … rest of the html … –>

第一行被稱為“Status Line”,它之後就是http headers,空行完了就開始輸出內容了(在這個案例中是一些html輸出)。

但你查看頁面源代碼卻不能看到HTTP headers,雖然它們連同你能看到的東西一起被傳送至流覽器。

這個HTTP請求也發出了一些其他資源的接收請求,例如圖片,css檔,js文件等等。

下面我們來看看細節。


怎樣才能看到HTTP Headers

下面這些FireFox擴展能夠幫助你分析HTTP headers:

1. firebug

2.Live HTTP Headers

3. 在PHP中:

文章下面將會看到一些使用php示範的例子。


HTTP Request 的結構

被稱作“first line”的第一行包含三個部分:

  • “method” 表明這是何種類型的請求. 最常見的請求類型有 GET, POST 和 HEAD.
  • “path” 體現的是主機之後的路徑. 例如,當你請求 “http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/”時 , path 就會是 “/tutorials/other/top-20-mysql-best-practices/”.
  • “protocol” 包含有 “HTTP” 和版本號, 目前流覽器都會使用1.1.

剩下的部分每行都是一個“Name:Value”對。它們包含了各式各樣關於請求和你流覽器的資訊。

例如”User-Agent“就表明了你流覽器版本和你所用的作業系統。

”Accept-Encoding“會告訴伺服器你的流覽可以接受類似gzip的壓縮輸出。

這些headers大部分都是可選的。HTTP 請求甚至可以被精簡成這樣子:

GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1
Host: net.tutsplus.com

並且你仍舊可以從伺服器收到有效的回應。


請求類型

三種最常見的請求類型是:GET,POST 和 HEAD ,從html的編寫過程中你可能已經熟悉了前兩種。

GET:獲取一個文檔

大部分被傳輸到流覽器的html,images,js,css, … 都是通過GET方法發出請求的。它是獲取資料的主要方法。

例如,要獲取Nettuts+ 的文章,http request的第一行通常看起來是這樣的:

GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1

一旦html載入完成,流覽器將會發送GET 請求去獲取圖片,就像下面這樣:

GET /wp-content/themes/tuts_theme/images/header_bg_tall.png HTTP/1.1

表單也可以通過GET方法發送,下面是個例子:

<form action="foo.php" method="GET">
First Name: <input name="first_name" type="text" />
Last Name: <input name="last_name" type="text" />
<input name="action" type="submit" value="Submit" />
</form>

當這個表單被提交時,HTTP request 就會像這樣:

GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1

你可以將表單輸入通過附加進查詢字串的方式發送至伺服器。


POST:發送資料至伺服器

儘管你可以通過GET方法將資料附加到url中傳送給伺服器,但在很多情況下使用POST發送資料給伺服器更加合適。通過GET發送大量資料是不現實的,它有一定的局限性。

用POST請求來發送表單數據是普遍的做法。我們來吧上面的例子改造成使用POST方式:

<form action="foo.php" method="POST">
First Name: <input name="first_name" type="text" />
Last Name: <input name="last_name" type="text" />
<input name="action" type="submit" value="Submit" />
</form>

提交這個表單會創建一個如下的HTTP 請求:

POST /foo.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/test.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
first_name=John&last_name=Doe&action=Submit

這裏有三個需要注意的地方:

  • 第一行的路徑已經變為簡單的 /foo.php , 已經沒了查詢字串。
  • 新增了 Content-Type 和 Content-Lenght Header,它提供了發送資訊的相關資訊.
  • 所有資料都在headers之後,以查詢字串的形式被發送.

POST方式的請求也可用在AJAX,應用程式,cURL … 之上。並且所有的檔上傳表單都被要求使用POST方式。


HEAD:接收Header資訊

HEAD和GET很相似,只不過HEAD不接受HTTP回應的內容部分。當你發送了一個HEAD請求,那就意味著你只對HTTPHeader感興趣,而不是文檔本身。

這個方法可以讓流覽器判斷頁面是否被修改過,從而控制緩存。也可判斷所請求的文檔是否存在。

例如,假如你的網站上有很多鏈結,那麼你就可以簡單的給他們分別發送HEAD請求來判斷是否存在死鏈,這比使用GET要快很多。

http回應結構

當流覽器發送了HTTP請求之後,伺服器就會通過一個HTTP response來回應這個請求。如果不關心內容,那麼這個請求看起來會是這樣的:

第一個有價值的資訊就是協定。目前伺服器都會使用 HTTP/1.x 或者 HTTP/1.1。

接下來一個簡短的資訊代表狀態。代碼200意味著我們的請求已經發送成功了,伺服器將會返回給我們所請求的文檔,在Header資訊之後。

我們都見過“404”頁面。當我向伺服器請求一個不存在的路徑時,伺服器就用用404來代替200回應我們。

餘下的回應內容和HTTP請求相似。這些內容是關於伺服器軟體的,頁面/檔何時被修改過,mime type 等等…

同樣,這些Header資訊也是可選的。


HTTP狀態碼

  • 200 用來表示請求成功.
  • 300 來表示重定向.
  • 400 用來表示請求出現問題.
  • 500 用來表示伺服器出現問題.

200 成功 (OK)

前文已經提到,200是用來表示請求成功的。

206 部分內容 (Partial Content)

如果一個應用只請求某範圍之內的檔,那麼就會返回206.

這通常被用來進行下載管理,中斷點續傳或者檔分塊下載。

404 沒有找到 (Not Found)

很容易理解


401 未經授權 (Unauthorized)

受密碼保護的頁面會返回這個狀態。如果你沒有輸入正確的密碼,那麼你就會在流覽器中看到如下的資訊:

注意這只是受密碼保護頁面,請求輸入密碼的彈出框是下面這個樣子的:


403 被禁止(Forbidden)

如果你沒有許可權訪問某個頁面,那麼就會返回403狀態。這種情況通常會發生在你試圖打開一個沒有index頁面的檔夾。如果伺服器設置不允許查看目錄內容,那麼你就會看到403錯誤。

其他一些方式也會發送許可權限制,例如你可以通過IP位址進行阻止,這需要一些htaccess的協助。

order allow,deny
deny from 192.168.44.201
deny from 224.39.163.12
deny from 172.16.7.92
allow from all

302(或307)臨時移動(Moved Temporarily) 和 301 永久移動(Moved Permanently)

這兩個狀態會出現在流覽器重定向時。例如,你使用了類似 bit.ly 的網址縮短服務。這也是它們如何獲知誰點擊了他們鏈結的方法。

302和301對於流覽器來說是非常相似的,但對於搜索引擎爬蟲就有一些差別。打個比方,如果你的網站正在維護,那麼你就會將用戶端流覽器用302重定向到另外一個位址。搜索引擎爬蟲就會在將來重新索引你的頁面。但是如果你使用了301重定向,這就等於你告訴了搜索引擎爬蟲:你的網站已經永久的移動到了新的位址。

500 伺服器錯誤(Internal Server Error)

這個代碼通常會在頁面腳本崩潰時出現。大部分CGI腳本都不會像PHP那樣輸出錯誤資訊給流覽器。如果出現了致命的錯誤,它們只會發送一個500的狀態碼。這時需要查看伺服器錯誤日誌來排錯。


完整的列表

你可以在這裏找到完整的HTTP 狀態碼說明。

HTTP Headers 中的 HTTP請求

現在我們來看一些在HTTP headers中常見的HTTP請求資訊。

所有這些Header資訊都可以在PHP的$_SERVER陣列中找到。你也可以用getallheaders()函數一次性獲取所有的Header資訊。

Host

一個HTTP請求會發送至一個特定的IP位址,但是大部分伺服器都有在同一IP位址下託管多個網站的能力,那麼伺服器必須知道流覽器請求的是哪個功能變數名稱下的資源。

Host: rlog.cn

這只是基本的主機名,包含功能變數名稱和子級功能變數名稱。

在PHP中,可以通過$_SERVER[‘HTTP_HOST’] 或 $_SERVER[‘SERVER_NAME’]來查看。

User-Agent

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)

這個Header可以攜帶如下幾條資訊:

  • 流覽器名和版本號.
  • 作業系統名和版本號.
  • 默認語言.

這就是某些網站用來收集訪客資訊的一般手段。例如,你可以判斷訪客是否在使用手機訪問你的網站,然後決定是否將他們引導至一個在低解析度下表現良好的移動網站。

在PHP中,可以通過 $_SERVER[‘HTTP_USER_AGENT’] 來獲取User-Agent

if ( strstr($_SERVER[‘HTTP_USER_AGENT’],’MSIE 6′) ) {
echo “Please stop using IE6!";
}


Accept-Language

Accept-Language: en-us,en;q=0.5

這個資訊可以說明用戶的默認語言設置。如果網站有不同的語言版本,那麼就可以通過這個資訊來重定向用戶的流覽器。

它可以通過逗號分割來攜帶多國語言。第一個會是首選的語言,其他語言會攜帶一個“q”值,來表示用戶對該語言的喜好程度(0~1)。

在PHP中用 $_SERVER[“HTTP_ACCEPT_LANGUAGE"] 來獲取這一資訊。

if (substr($_SERVER[‘HTTP_ACCEPT_LANGUAGE’], 0, 2) == ‘fr’) {
header(‘Location: http://french.mydomain.com&#8217;);
}

Accept-Encoding

Accept-Encoding: gzip,deflate

大部分的流覽器都支援gzip壓縮,並會把這一資訊報告給伺服器。這時伺服器就會壓縮HTML發送給流覽器。這可以減少近80%的檔案大小,以節省下載時間和頻寬。

在PHP中可以使用 $_SERVER[“HTTP_ACCEPT_ENCODING"] 獲取該資訊。 然後調用ob_gzhandler()方法時會自動檢測該值,所以你無需手動檢測。

// enables output buffering
// and all output is compressed if the browser supports it
ob_start(‘ob_gzhandler’);


If-Modified-Since

如果一個頁面已經在你的流覽器中被cache,那麼你下次流覽時流覽器將會檢測文檔是否被修改過,那麼它就會發送這樣的Header:

If-Modified-Since: Sat, 28 Nov 2009 06:38:19 GMT

如果自從這個時間以來未被修改過,那麼伺服器將會返回“304 Not Modified”,而且不會再返回內容。流覽器將自動去緩存中讀取內容

在PHP中,可以用$_SERVER[‘HTTP_IF_MODIFIED_SINCE’] 來檢測。

// assume $last_modify_time was the last the output was updated
// did the browser send If-Modified-Since header?
if(isset($_SERVER[‘HTTP_IF_MODIFIED_SINCE’])) {
// if the browser cache matches the modify time
if ($last_modify_time == strtotime($_SERVER[‘HTTP_IF_MODIFIED_SINCE’])) {
// send a 304 header, and no content
header(“HTTP/1.1 304 Not Modified");
exit;
}
}

還有一個叫Etag的HTTP頭資訊,它被用來確定緩存的資訊是否正確,稍後我們將會解釋它。

Cookie

顧名思義,他會送出流覽器中存儲的Cookie資訊給伺服器。

Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120; foo=bar

它是用分號分割的一組名值對。Cookie也可以包含session id。

在PHP中,單一的Cookie可以訪問$_COOKIE陣列獲得。你可以直接用$_SESSION array獲取session變數。如果你需要session id,那麼你可以使用session_id()函數代替cookie。

echo $_COOKIE[‘foo’];
// output: bar
echo $_COOKIE[‘PHPSESSID’];
// output: r2t5uvjq435r4q7ib3vtdjq120
session_start();
echo session_id();
// output: r2t5uvjq435r4q7ib3vtdjq120

Referer

顧名思義, Header將會包含referring url信息。

例如,我訪問Nettuts+的主頁並點擊了一個鏈結,這個Header資訊將會發送到流覽器:
Referer: http://net.tutsplus.com/

在PHP中,可以通過 $_SERVER[‘HTTP_REFERER’] 獲取該值。

if (isset($_SERVER[‘HTTP_REFERER’])) {
$url_info = parse_url($_SERVER[‘HTTP_REFERER’]);
// is the surfer coming from Google?
if ($url_info[‘host’] == ‘www.google.com’) {
parse_str($url_info[‘query’], $vars);
echo “You searched on Google for this keyword: “. $vars[‘q’];
}
}
// if the referring url was:
// http://www.google.com/search?source=ig&hl=en&rlz=&=&q=http+headers&aq=f&oq=&aqi=g-p1g9
// the output will be:
// You searched on Google for this keyword: http headers

You may have noticed the word “referrer” is misspelled as “referer”. Unfortunately it made into the official HTTP specifications like that and got stuck.

Authorization

當一個頁面需要授權,流覽器就會彈出一個登入視窗,輸入正確的帳號後,流覽器會發送一個HTTP請求,但此時會包含這樣一個Header:

Authorization: Basic bXl1c2VyOm15cGFzcw==

包含在Header的這部分資訊是base64 encoded。例如,base64_decode(‘bXl1c2VyOm15cGFzcw==’) 會被轉化為 ‘myuser:mypass’ 。

在PHP中,這個值可以用$_SERVER[‘PHP_AUTH_USER’] 和 $_SERVER[‘PHP_AUTH_PW’] 獲得。

更多細節我們會在WWW-Authenticate部分講解。


HTTP Headers 中的 HTTP回應

現在讓我瞭解一些常見的HTTP Headers中的HTTP回應資訊。

在PHP中,你可以通過 header() 來設置Header回應資訊。PHP已經自動發送了一些必要的Header資訊,如 載入的內容,設置 cookies 等等… 你可以通過 headers_list() 函數看到已發送和將要發送的Header資訊。你也可以使用headers_sent()函數來檢查Header資訊是否已經被發送。

Cache-Control

w3.org 的定義是:“The Cache-Control general-header field is used to specify directives which MUST be obeyed by all caching mechanisms along the request/response chain.” 其中“caching mechanisms” 包含一些你ISP可能會用到的 閘道和代理資訊。

例如:

Cache-Control: max-age=3600, public

“public”意味著這個回應可以被任何人cache,“max-age” 則表明了該cache有效的秒數。允許你的網站被cache降大大減少下載時間和帶寬,同時也提高的流覽器的載入速度。

也可以通過設置 “no-cache”  指令來禁止緩存:

Cache-Control: no-cache

更多詳情請參見w3.org

Content-Type

這個Header包含了文檔的”mime-type”。流覽器將會依據該參數決定如何對文檔進行解析。例如,一個html頁面(或者有html輸出的php頁面)將會返回這樣的東西:

Content-Type: text/html; charset=UTF-8

‘text’ 是文檔類型,‘html’則是文檔子類型。 這個Header還包括了更多資訊,例如 charset。

如果是一個圖片,將會發送這樣的回應:

Content-Type: image/gif

流覽器可以通過mime-type來決定使用外部程式還是自身擴展來打開該文檔。如下的例子降調用Adobe Reader:

Content-Type: application/pdf

直接載入,Apache通常會自動判斷文檔的mime-type並且添加合適的資訊到Header去。並且大部分流覽器都有一定程度的容錯,在Header未提供或者錯誤提供該資訊的情況下它會去自動檢測mime-type。

你可以在這裏找到一個常用mime-type列表。

在PHP中你可以通過 finfo_file()來檢測檔的ime-type。

Content-Disposition

這個Header資訊將告訴流覽器打開一個檔下載視窗,而不是試圖解析該回應的內容。例如:

Content-Disposition: attachment; filename="download.zip"

他會導致流覽器出現這樣的對話方塊:

注意,適合它的Content-Type頭資訊同時也會被發送

Content-Type: application/zip
Content-Disposition: attachment; filename="download.zip"

Content-Length

當內容將要被傳輸到流覽器時,伺服器可以通過該Header告知流覽器將要傳送檔的大小(bytes)。

Content-Length: 89123

對於檔下載來說這個資訊相當的有用。這就是為什麼流覽器知道下載進度的原因。

例如,這裏我寫了一段虛擬腳本,來模擬一個慢速下載。

// it’s a zip file
header(‘Content-Type: application/zip’);
// 1 million bytes (about 1megabyte)
header(‘Content-Length: 1000000’);
// load a download dialogue, and save it as download.zip
header(‘Content-Disposition: attachment; filename="download.zip"‘);
// 1000 times 1000 bytes of data
for ($i = 0; $i < 1000; $i++) {
echo str_repeat(“.",1000);
// sleep to slow down the download
usleep(50000);
}

結果將會是這樣的:

現在,我將Content-LengthHeader注釋掉:

// it’s a zip file
header(‘Content-Type: application/zip’);
// the browser won’t know the size
// header(‘Content-Length: 1000000’);
// load a download dialogue, and save it as download.zip
header(‘Content-Disposition: attachment; filename="download.zip"‘);
// 1000 times 1000 bytes of data
for ($i = 0; $i < 1000; $i++) {
echo str_repeat(“.",1000);
// sleep to slow down the download
usleep(50000);
}

結果就變成了這樣:

這個流覽器只會告訴你已下載了多少,但不會告訴你總共需要下載多少。而且進度條也不會顯示進度。

Etag

這是另一個為緩存而產生的Header資訊。它看起來會是這樣:

Etag: “pub1259380237;gz"

伺服器可能會將該資訊和每個被發送檔一起回應給流覽器。該值可以包含文檔的最後修改日期,檔大小或者檔校驗和。流覽會把它和所接收到的文檔一起緩存。下一次當流覽器再次請求同一檔時將會發送如下的HTTP請求:

If-None-Match: “pub1259380237;gz"

如果所請求的文檔Etag值和它一致,伺服器將會發送304狀態碼,而不是200。並且不返回內容。流覽器此時就會從緩存載入該檔。


Last-Modified

顧名思義,這個Header資訊用GMT格式表明了文檔的最後修改時間:

Last-Modified: Sat, 28 Nov 2009 03:50:37 GMT

$modify_time = filemtime($file);
header(“Last-Modified: " . gmdate(“D, d M Y H:i:s", $modify_time) . " GMT");

它提供了另一種緩存機制。流覽器可能會發送這樣的請求:

If-Modified-Since: Sat, 28 Nov 2009 06:38:19 GMT

在If-Modified-Since一節我們已經討論過了。

Location

這個Header是用來重定向的。如果回應代碼為 301 或者 302 ,伺服器就必須發送該Header。例如,當你訪問 http://www.nettuts.com 時流覽器就會收到如下的回應:

HTTP/1.x 301 Moved Permanently

Location: http://net.tutsplus.com/

在PHP中你可以通過這種方式對訪客重定向:
header(‘Location: http://net.tutsplus.com/&#8217;);

默認會發送302狀態碼,如果你想發送301,就這樣寫:

header(‘Location: http://net.tutsplus.com/&#8217;, true, 301);

Set-Cookie

當一個網站需要設置或者更新你流覽的cookie資訊時,它就會使用這樣的Header:

Set-Cookie: skin=noskin; path=/; domain=.amazon.com; expires=Sun, 29-Nov-2009 21:42:28 GMT
Set-Cookie: session-id=120-7333518-8165026; path=/; domain=.amazon.com; expires=Sat Feb 27 08:00:00 2010 GMT

每個cookie會作為單獨的一條Header資訊。注意,通過js設置cookie將不會出現在HTTP頭中。

在PHP中,你可以通過setcookie()函數來設置cookie,PHP會發送合適的HTTP 頭。

setcookie(“TestCookie", “foobar");

它會發送這樣的頭資訊:

Set-Cookie: TestCookie=foobar

如果未指定到期時間,cookie就會在流覽器關閉後被刪除。

WWW-Authenticate

一個網站可能會通過HTTP發送這個Header資訊來驗證用戶。當流覽器看到Header有這個回應時就會打開一個彈出窗。

WWW-Authenticate: Basic realm="Restricted Area"

它會看起來像這樣:

PHP手冊的一章中就有一段簡單的代碼演示了如果用PHP做這樣的事情:

if (!isset($_SERVER[‘PHP_AUTH_USER’])) {
header(‘WWW-Authenticate: Basic realm="My Realm"‘);
header(‘HTTP/1.0 401 Unauthorized’);
echo ‘Text to send if user hits Cancel button’;
exit;
} else {
echo “<p>Hello {$_SERVER[‘PHP_AUTH_USER’]}.</p>";
echo “<p>You entered {$_SERVER[‘PHP_AUTH_PW’]} as your password.</p>";
}

Content-Encoding

這個Header通常會在返回內容被壓縮時設置。

2010 年 04 月 18 日

Http 運作的流程

Filed under: 網路基本服務原理 — nkongkimo @ 01:05:42

為一個軟體發展者,你一定會對網路應用如何工作有一個完整的層次化的認知,同樣這裏也包括這些應用所用到的技術:像本文將更深入的研究當你輸入一個網址的時候,後臺到底發生了一件件什麼樣的事~

1. 首先,你得在流覽器裏輸入網址:

2. 流覽器查找Domain nameIP位址

導航的第一步是通過訪問的Domain name找出其IP位址。DNS查找過程如下:

l 流覽器cache – 流覽器會cache DNS記錄一段時間。 有趣的是作業系統沒有告訴流覽器儲存DNS記錄的時間,這樣不同流覽器會儲存一個固定的時間(2分鐘到30分鐘不等)。

l 系統cache – 如果在流覽器cache裏沒有找到需要的記錄,流覽器會做一個系統調用(windows裏是gethostbyname)。這樣便可獲得系統cache中的記錄。

l 路由器cache– 接著,前面的查詢request發向router,router一般會有自己的DNScache。

l ISP DNS cache– 接下來要check的就是ISP DNS cache server。在這一般都能找到相應的cache記錄。

l 遞迴搜索– ISP的DNS server從root功能變數Name server開始進行遞迴搜索,從.com頂級Domain nameserver到Facebook的Domain nameserver。一般DNSserver的cache中會有.comDomain nameserver中的Domain name,所以到頂級server的匹配過程不是那麼必要了。

DNS遞迴查找如下圖所示:

DNS有一點令人擔憂,這就是像wikipedia.org 或者 facebook.com這樣的整個Domain name看上去只是對應一個單獨的IP位址。還好,有幾種方法可以消除這個issue:

  • 迴圈 DNS 是DNS查找時返回多個IP時的解決方案。舉例來說,Facebook.com實際上就對應了四個IP位址。
  • 負載平衡器 是以一個特定IP位址進行偵聽並將網路request轉發到一群server上。 一些大型的站點一般都會使用這種昂貴的高性能負載平衡器。
  • 地理 DNS 根據client所處的地理位置,通過Domain name映射到多個不同的IP位址提高可擴展性。這樣不同的server不能夠更新同步狀態,但mirror靜態內容的話就非常好。
  • Anycast 是一個IP位址映射多個物理主機的路由技術。 美中不足,Anycast與TCP協議適應的不是很好,所以很少應用在那些方案中。

大多數DNSserver使用Anycast來獲得高效低延遲的DNS查找。

3. 流覽器給web server發送一個HTTP request

因為像Facebook主頁這樣的動態頁面,打開後在流覽器cache中很快甚至馬上就會過期,毫無疑問他們不能從中讀取。

所以,流覽器將把一下請求發送到Facebook所在的server:

GET http://facebook.com/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, […]
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; […]
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: facebook.com
Cookie: datr=1265876274-[…]; locale=en_US; lsd=WW[…]; c_user=2101[…]

GET 這個請求定義了要讀取的URL: “http://facebook.com/”。

流覽器自身定義 (User-Agent 頭), 和它希望接受什麼類型的回應 (Accept and Accept-Encoding頭).

Connection頭要求server為了後邊的請求不要關閉TCP連接。

請求中也包含流覽器存儲的Domain name的cookies。可能你已經知道,在不同頁面請求當中,cookies是與跟蹤一個網站狀態相匹配的鍵值。這樣cookies會存儲登錄用戶名,server分配的密碼和一些用戶設置等。Cookies會以文本文檔形式存儲在客戶機裏,每次請求時發送給server。

用來看原始HTTP請求及相觀的工具很多。作者比較喜歡使用fiddler,當然也有像FireBug這樣其他的工具。這些軟體在網站優化時會幫上很大忙。

除了獲取請求,還有一種是發送請求,它常在提交表單用到。發送請求通過URL傳遞其參數(e.g.: http://robozzle.com/puzzle.aspx?id=85)。發送請求在請求正文頭之後發送其參數。
像“http://facebook.com/”中的’/’是至關重要的。這種情況下,流覽器能安全的添加斜杠。而像“http://example.com/folderOrFile”這樣的位址,因為流覽器不清楚folderOrFile到底是檔夾還是檔,所以不能自動添加’/’。這時,流覽器就不加’/’直接訪問位址,server會回應一個重定向,結果造成一次不必要的握手。

4. facebook服務的永久重定向回應

圖中所示為Facebookserver發回給流覽器的回應:

HTTP/1.1 301 Moved Permanently
Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,
pre-check=0
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Location: http://www.facebook.com/
P3P: CP="DSP LAW"
Pragma: no-cache
Set-Cookie: made_write_conn=deleted; expires=Thu, 12-Feb-2009 05:09:50 GMT;
path=/; domain=.facebook.com; httponly
Content-Type: text/html; charset=utf-8
X-Cnection: close
Date: Fri, 12 Feb 2010 05:09:51 GMT
Content-Length: 0

server給流覽器響應一個301永久重定向回應,這樣流覽器就會訪問“http://www.facebook.com/” 而非“http://facebook.com/”。

為什麼server一定要重定向而不是直接發會用戶想看的網頁內容呢?這個問題有好多有意思的答案。

其中一個原因跟搜索引擎排名有關。你看,如果一個頁面有兩個位址,就像http://www.litfresh.com/ http://litfresh.com/,搜索引擎會認為它們是兩個網站,結果造成每一個的搜索鏈結都減少從而降低排名。而搜索引擎知道301永久重定向是什麼意思,這樣就會把訪問帶www的和不帶www的位址歸到同一個網站排名下。

還有一個是用不同的位址會造成cache友好性變差。當一個頁面有好幾個名字時,它可能會在cache裏出現好幾次。


5. 流覽器跟蹤重定向地址

現在,流覽器知道了“http://www.facebook.com/”才是要訪問的正確位址,所以它會發送另一個獲取請求:

GET http://www.facebook.com/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, […]
Accept-Language: en-US
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; […]
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Cookie: lsd=XW[…]; c_user=21[…]; x-referer=[…]
Host: http://www.facebook.com

頭資訊以之前請求中的意義相同。

6. server“處理請求

server接收到獲取請求,然後處理並返回一個response。

這表面上看起來是一個順向的任務,但其實這中間發生了很多有意思的東西,就像作者博客這樣簡單的網站,何況像facebook那樣訪問量大的網站呢!

  • Web server軟體
    webserver軟體(像IIS和aprch)接收到HTTP請求,然後確定執行什麼請求處理來處理它。請求處理就是一個能夠讀懂請求並且能生成HTML來進行回應的程式(像ASP.NET,PHP,RUBY…)。

舉個最簡單的例子,需求處理可以以映射網站位址結構的檔層次存儲。像http://example.com/folder1/page1.aspx這個位址會映射/httpdocs/folder1/page1.aspx這個檔。webserver軟體可以設置成為位址人工的對應請求處理,這樣page1.aspx的發佈位址就可以是http://example.com/folder1/page1。

  • 請求處理
    請求處理閱讀請求及它的參數和cookies。它會讀取也可能更新一些資料,並把資料存儲在server上。然後,需求處理會生成一個HTML回應。

所有動態網站都面臨一個有意思的難點 – 如何存儲資料。小網站一半都會有一個SQL資料庫來存儲資料,存儲大量資料和/或訪問量大的網站不得不找一些辦法把資料庫分配到多台機器上。解決方案有:sharding (基於主鍵值將資料表分散到多個資料庫中),複製,利用弱語義一致性的簡化資料庫。

委託工作給批次處理是一個廉價保持資料更新的技術。舉例來講,Fackbook得及時更新新聞feed,但資料支援下的“你可能認識的人”功能只需要每晚更新(作者猜測是這樣的,改功能如何完善不得而知)。批次處理作業更新會導致一些不太重要的資料陳舊,但能使資料更新工作更快更簡潔。

7. server發回一個HTML響應

圖中為server生成並返回的回應:

HTTP/1.1 200 OK
Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,
pre-check=0
Expires: Sat, 01 Jan 2000 00:00:00 GMT
P3P: CP="DSP LAW"
Pragma: no-cache
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
X-Cnection: close
Transfer-Encoding: chunked
Date: Fri, 12 Feb 2010 09:05:55 GMT
2b3��������T�n�@����[…]

整個回應大小為35kB,其中大部分在整理後以blob類型傳輸。

內容編碼頭告訴流覽器整個回應體用gzip演算法進行壓縮。解壓blob塊後,你可以看到如下期望的HTML:

http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
lang="en" id="facebook" class=" no_js">

關於壓縮,頭資訊說明了是否cache這個頁面,如果cache的話如何去做,有什麼cookies要去設置(前面這個回應裏沒有這點)和隱私資訊等等。

請注意表頭中把Content-type設置為“text/html”。表頭讓流覽器將回應內容以HTML形式呈現,而不是以檔形式下載它。流覽器會根據表頭資訊決定如何解釋該回應,不過同時也會考慮像URL擴展內容等其他因素。


8. 流覽器開始顯示HTML

在流覽器沒有完整接受全部的HTML文檔時,它就已經開始顯示這個頁面了:

9. 流覽器發送獲取嵌入在HTML中的物件

在流覽器顯示HTML時,它會注意到需要獲取其他位址內容的標籤。這時,流覽器會發送一個獲取請求來重新獲得這些檔。

下面是幾個我們訪問facebook.com時需要重獲取的幾個URL:

· 圖片
http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif

· CSS 式樣表
http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css
http://static.ak.fbcdn.net/rsrc.php/zANE1/hash/cvtutcee.css

· JavaScript 文件
http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js
http://static.ak.fbcdn.net/rsrc.php/z6R9L/hash/cq2lgbs8.js

這些位址都要經歷一個和HTML讀取類似的過程。所以流覽器會在DNS中查找這些Domain name,發送請求,重定向等等…

但不像動態頁面那樣,靜態檔會允許流覽器對其進行cache。有的檔可能會不需要與server通訊,而從cache中直接讀取。server的回應中包含了靜態檔保存的期限資訊,所以流覽器知道要把它們cache多長時間。還有,每個回應都可能包含像版本號一樣工作的ETag頭(被請求變數的實體值),如果流覽器觀察到檔的版本ETag資訊已經存在,就馬上停止這個檔的傳輸。

試著猜猜看“fbcdn.net”在地址中代表什麼?聰明的答案是"Facebook內容分發網路"。Facebook利用內容分發網路(CDN)分發像圖片,CSS表和JavaScript檔這些靜態檔。所以,這些檔會在全球很多CDN的資料中心中留下備份。

靜態內容往往代表站點的帶寬大小,也能通過CDN輕鬆的複製。通常網站會使用第三方的CDN。例如,Facebook的靜態檔由最大的CDN提供商Akamai來託管。

舉例來講,當你試著ping static.ak.fbcdn.net的時候,可能會從某個akamai.netserver上獲得回應。有意思的是,當你同樣再ping一次的時候,回應的server可能就不一樣,這說明幕後的負載平衡開始起作用了。

10. 流覽器發送非同步(AJAX)請求

在Web 2.0偉大精神的指引下,頁面顯示完成後用戶端仍與server端保持著聯繫。

以Facebook聊天功能為例,它會持續與server保持聯繫來及時更新你那些好友的狀態。為了更新這些亮著的好友狀態,在流覽器中執行的JavaScript代碼會給server發送非同步請求。這個非同步請求發送給特定的位址,它是一個按照程式構造的獲取或發送請求。還是在Facebook這個例子中,用戶端發送給http://www.facebook.com/ajax/chat/buddy_list.php一個發佈請求來獲取你好友裏哪個線上的狀態資訊。

提起這個模式,就必須要講講"AJAX"– “非同步JavaScript 和 XML”,雖然server為什麼用XML格式來進行回應也沒有個一清二白的原因。再舉個例子吧,對於非同步請求,Facebook會返回一些JavaScript的代碼片段。

除了其他,fiddler這個工具能夠讓你看到流覽器發送的非同步請求。事實上,你不僅可以被動的做為這些請求的看客,還能主動出擊修改和重新發送它們。AJAX請求這麼容易被騙,可著實讓那些計分的線上遊戲開發者們鬱悶的了。(當然,可別那樣騙人家~)

Facebook聊天功能提供了關於AJAX一個有意思的問題案例:把資料從server端推送到用戶端。因為HTTP是一個請求-回應協議,所以聊天server不能把新消息發給客戶。取而代之的是用戶端不得不隔幾秒就輪詢下server端看自己有沒有新消息。

這些情況發生時長輪詢是個減輕server負載挺有趣的技術。如果當被輪詢時server沒有新消息,它就不理這個用戶端。而當尚未超時的情況下收到了該客戶的新消息,server就會找到未完成的請求,把新消息做為回應返回給用戶端。

2010 年 03 月 13 日

ARP 協定

Filed under: 網路基本服務原理 — nkongkimo @ 19:52:11

這裡我們要介紹的是 Address Resolution Protocol (ARP)。 ARP 是 TCP/IP 設計者利用乙太網的廣播性質﹐設計出來的位址解釋協定。它的主要特性和優點是它的位址對應關係是動態的﹐它以查詢的方式來獲得 IP 位址和實體位址的對應。它的工作原理非常簡單﹕

1. 首先﹐每一台主機都會在 ARP 快取緩衝區 (ARP Cache)中建立一個 ARP 表格﹐用來記錄 IP 位址和實體位址的對應關係。這個 Table 的每一筆資料會根據自身的存活時間遞減而最終消失﹐以確保資料的真實性。

2. 當發送主機有一個封包要傳送給目的主機的時候﹐並且獲得目的主機的 IP 位址﹔那發送主機會先檢查自己的 ARP 表格中有沒有該 IP 位址的實體位址對應。如果有﹐就直接使用此位址來傳送框包﹔如果沒有﹐則向網路發出一個 ARP Request 廣播封包﹐查詢目的主機的實體位址。這個封包會包含發送端的 IP 位址和實體位址資料。

3. 這時﹐網路上所有的主機都會收到這個廣播封包﹐會檢查封包的 IP 欄位是否和自己的 IP 位址一致。如果不是則忽略﹔如果是則會先將發送端的實體位址和 IP 資料更新到自己的 ARP 表格去﹐如果已經有該 IP 的對應﹐則用新資料覆蓋原來的﹔然後再回應一個 ARP Reply 封包給對方﹐告知發送主機關於自己的實體位址﹔

4. 當發送端接到 ARP Reply 之後﹐也會更新自己的 ARP 表格﹔然後就可以用此紀錄進行傳送了。

如果發送端沒有得到 ARP Reply ﹐則宣告查詢失敗。

ARP 的查詢過程可參考下圖﹕

 

前面說的 ARP 表格﹐只有在 TCP/IP 協定被載入核心之後才會建立﹐如果 TCP/IP 協定被卸載或關閉機器﹐那麼表格就會被清空﹔到下次協定載入或開機的時候再重新建立﹐而同時會向網路發出一個 ARP 廣播﹐告訴其它機器它的目前位址是什麼﹐以便所有機器都能保持最正確的資料。

然而﹐ARP cache 的大小是有所限制的﹐如果超過了界限﹐那麼越長時間沒被使用過渡資料就必須清理掉﹐以騰出空間來儲存更新的資料。所以﹐當機器收到 ARP equest 封包時﹐如果查詢對象不是自己﹐則不會根據發送端位址資料來更新自己的 ARP 表格﹐而是完全忽略該封包。同時﹐每筆存在 cache 中的資料﹐都不是永久保存的﹕每筆資料再更新的時候﹐都會被賦予一個存活倒數計時值﹐如果在倒數時間到達的時候﹐該資料就會被清掉。然而﹐如果該資料在倒數時間到達之前被使用過﹐則計時值會被重新賦予。

當然了﹐ARP 尚有一套機制來處理當 ARP 表格資料不符合實際位址資料的狀況(例如﹐在當前連線尚未結束前﹐收到目的端的位址資料更新訊息)﹔或是目的主機太忙碌而未能回答 ARP 請求等狀況。

ARP 和 RARP 之封包格式

讓我們溫習前面討論 OSI 層級時提到的乙太網路框包格式﹕

乙太網的框包格式

我們可以發現標準的乙太網框包其中有一段 46 到 1500 byte 長度的數據空間﹐假如這是一個 ARP 封包的話﹐那麼該段數據空間就用來包裝整個 ARP 封。ARP 和 RARP 的封包格式是一模一樣的﹕

ARP / ARAP 封包格式

下面我們就封包中每一欄位做一個簡單的說明﹕

Hardware Type

這是指網路界面卡的種類﹐如果該值為 1﹐則表示為乙太網 ( Ethernet )。

Protocol Type

這是指上層網路協定位址種類﹐如果該值為 0x0800﹐則表示為 IP 位址格式。

Hlen

這是指硬體位址長度(單位為 byte)﹐乙太網的位址長度為 6 。

Plen

這是指網路協定位址的長度(單位為 byte)﹐IP 協定位址長度為 4。

Operation

這是指封包類別﹐一共有四種﹕

1 ARP Request

2 ARP Reply

3 RARP Request

4 RARP Reply

Sender HA (Source MAC)

這是指發送端的實體位址﹐如果是乙太網的話﹐將會是一個 6 byte 長度的乙太網位址。

Sender IP(source IP)

這是指發送端的 IP 位址﹐會是一個 4 byte 長度的 IP 位址。

Traget HA(Destination MAC)

這是指目的端的實體位址﹐如果是乙太網的話﹐將會是一個 6 byte 長度的乙太網位址。

Target IP(Destination IP)

這是指目的端的 IP 位址﹐會是一個 4 byte 長度的 IP 位址。

ARP 之 RFC 文件

ARP 的詳細資料可以查詢 RFC-826﹑RFC-814﹑以及 RFC-1166 等文件。而 RARP 的資料則可以參考 RFC-903﹑RFC-906﹑還有 RFC-1293 等文件。

在WordPress.com寫網誌.