前言
計算機網絡核心知識系列博客分爲上、中、下部分,此篇爲(上)。
博客的內容是計算機網絡的核心知識,但也僅僅限於求得“管中窺一豹之形體”,也就是說這是入門級別的博客,若想深入的話,還是得好好啃大部頭。
文章目錄
- 前言
- 1 計算機網絡概述(上)
- 1.1 計算機網絡基本概念
- 1.1.1 什麼是計算機網絡?
- 1.1.2 通信系統模型
- 1.1.3 定義:計算機網絡就是`互連`的、`自治`的計算機集合。
- 1.1.4 距離遠、數量大如何保證互連?
- 1.1.5 什麼是Internet?-組成細節角度
- 1.1.6 什麼是Internet?-服務角度
- 1.1.7問題
- 1.2 計算機網絡結構
- 1.3 網絡核心
- 1 計算機網絡概述(下)
- 1.4 計算機網絡性能
- 1.4.1 速率
- 1.4.2 帶寬
- 1.4.3 延遲/時延(delay或latency)
- 1.4.4 四種分組延遲
- 1.4.5 時延帶寬積(單位:bits(比特))
- 1.4.6 分組丟失(丟包)
- 1.4.7 吞吐量/率(Throughput)
- 1.5 計算機網絡體系結構
- 1.6 計算機網絡發展歷史
- 2 應用層
- 2.1 網絡應用(層)內容概述
- 2.2 網絡應用的基本原理
- 2.3 Web應用
- 2.4 Email應用
- 2.5 DNS(域名解析系統)
- 2.6 P2P應用
- 2.6.1 P2P應用:原理與文件分發
- 2.6.2 文件分發:BitTorrent
- 2.6.3 P2P應用:索引技術
- 2.6.4 洪泛式查詢索引技術:Query flooding
- 2.6.5 層次式覆蓋網絡索引技術
- 2.7 Socket編程
- 2.7.1 Socket編程-應用編程接口(API)
- 2.7.2 Socket編程-Socket API概述
- 2.7.3 Socket編程-Socket API函數(1)
- 2.7.4 Socket編程-Socket API函數(2)
- 2.7.5 Socket API函數小結
- 2.7.6 關於網絡字節順序
- 2.7.7 網絡應用的Socket API調用基本流程
- 2.7.8 Socket編程-客戶端軟件設計
- 解析服務器IP地址
- 解析服務器(熟知)端口號
- 解析協議號
- TCP客戶端軟件流程
- UDP客戶端軟件流程
- 客戶端軟件的實現- `connectsock()`
- 客戶端軟件的實現-UDP客戶端
- 客戶端軟件的實現-TCP客戶端
- 客戶端軟件的實現-異常處理
- 例1:訪問DAYTIME服務的客戶端(TCP)
- 例2:訪問DAYTIME服務的客戶端(UDP)
- 2.7.9 Socket編程-服務器軟件設計
- 3 傳輸層(上)
- 3.1 傳輸層服務
- 3.2 複用和分用
- 3.3 無連接傳輸協議-UDP
- 3.4 可靠數據傳輸的基本原理
- 4 傳輸層(下)
內容提綱:
1 計算機網絡概述(上)
1.1 計算機網絡基本概念
1.1.1 什麼是計算機網絡?
計算機網絡=通信技術+計算機技術
計算機網絡是通信技術
與計算機技術
緊密結合的產物。
1.1.2 通信系統模型
- 計算機網絡就是一種通信網絡
1.1.3 定義:計算機網絡就是互連
的、自治
的計算機集合。
自治
:無主從關係互連
:互聯互通- 通信鏈路
1.1.4 距離遠、數量大如何保證互連?
通過交換網絡
互連主機
1.1.5 什麼是Internet?-組成細節角度
- 全球最大的
互聯網絡
- ISP(Internet Service Provider)網絡互連的“
網絡之網絡
”
- 數以百萬計的互連的
計算設備
集合主機
(hosts)=端系統
(end systems)- 運行各種網絡應用
通信鏈路
- 光纖、銅纜、無線電、衛星…
分組交換
:轉發分組(數據包)路由器
(routers)和交換機
(switches)
- 數以百萬計的互連的
1.1.6 什麼是Internet?-服務角度
爲網絡應用提供通信服務的通信基礎設施:
Web、VolP、Email、網絡遊戲、電子商務、社交網絡…爲網絡應用提供應用編程藉口(API):
- 支持應用程序"連接"Internet,發送/接受數據
- 提供類似於郵政系統的數據傳輸服務
1.1.7問題
僅有硬件(主機、鏈路、路由器...)連接,Internet能否順暢運行?能保證應用數據有序交付嗎?...
回答是不能。還需要協議。
1.2 計算機網絡結構
1.2.1 什麼是網絡協議?
網絡協議(network protocol)
,簡稱協議
,是爲進行網絡中的數據交換而建立的規則、標準或約定。協議
規定了通信實體之間所交換的消息的格式
、意義
、順序
以及針對收到信息或發生的事件所採取的"動作(actions)
"。
協議是計算機網絡有序運行的重要保證。常見的協議有TCP,IP,HTTP,Skype,802.11等。
網絡協議爲計算機網絡中進行數據交換而建立的規則、標準或約定的集合。
例如,網絡中一個微機用戶和一個大型主機的操作員進行通信,由於這兩個數據終端所用字符集不同,因此操作員所輸入的命令彼此不認識。爲了能進行通信,規定每個終端都要將各自字符集中的字符先變換爲標準字符集的字符後,才進入網絡傳送,到達目的終端之後,再變換爲該終端字符集的字符。當然,對於不相容終端,除了需變換字符集字符外還需轉換其他特性,如顯示格式、行長、行數、屏幕滾動方式等也需作相應的變換。
1.2.2 協議的三要素
語法
(Syntax)- 數據與控制信息的結構或格式
- 信號電平
語義
(Semantics)- 需要發出何種控制信息
- 完成何種動作以及做出何種相應
- 差錯控制
時序
(Timing)- 事件順序
- 速度匹配
協議規範了網絡中所有信息發送和接收過程,是學習網絡的重要內容之一。
Internet協議標準
- RFC:Request for Comments
- IETF:互聯網工程任務組(Internet Engineering Task Force)。於此可獲得關於協議的最新、最權威信息。
- 硬件(主機、路由器、通信鏈路等)是計算機網絡的基礎
- 計算機網絡中的數據交換必須遵守事先約定好的
規則
- 如同交通系統
- 任何通信或信息交換過程都需要規則
1.3 網絡核心
互聯的路由器網絡。
1.3.1 數據交換-電路交換
數據交換
:實現數據通過網絡核心從源主機到達目的主機。
- 爲什麼需要數據交換?
- 鏈路問題
如果計算機網絡中有臺計算機,則每一臺計算機需要有條鏈路,這是不現實的。 - 保持計算機網絡的
連通性
- 適用於不同的
網絡規模
- 鏈路問題
- 什麼是交換?
- 動態轉接
- 動態分配傳輸資源
- 動態轉接
- 數據交換的類型
電路交換
-
最典型電路交換網絡:電話網絡
-
電路交換的三個階段:
- 建立連接(呼叫/電路建立)
- 通信
- 釋放連接(拆除電路)
-
獨佔資源
-
電路交換網絡如何共享中繼線?
多路複用(Multiplexing)
-
報文交換
分組交換
多路複用
多路複用(multiplexing)
,簡稱複用
,是通信技術中的基本概念。
- 什麼是多路複用?
鏈路/網絡資源(如帶寬)劃分爲“資源片”- 將資源片分配給各路“呼叫”(calls)
- 每路呼叫
獨佔
分配到的資源片進行通信 - 資源片可能“
閒置
”(idle
) (無共享,因爲是分配好的)
典型多路複用方法
:頻分
多路複用( frequency division multiplexing-FDM )時分
多路複用( time division multiplexing-TDM )波分
多路複用(Wavelength division multiplexing-WDM)碼分
多路複用( Code division multiplexing-CDM )
- 頻分多路複用FDM
將信號分爲頻率不同的幾段。
- 頻分多路複用的各用戶佔用不同的帶寬資源(請注意,這裏的“帶寬 ”是
頻率帶寬
(單位:Hz)而不是數據的發送速率) - 用戶在分配到一定的頻帶後,在通信過程中
自始至終都佔用這個頻帶
- 頻分多路複用的各用戶佔用不同的帶寬資源(請注意,這裏的“帶寬 ”是
- 時分多路複用TDM
- 時分複用則是將時間劃分爲一段段等長的
時分複用幀
(TDM 幀),每個用戶在每個TDM幀中佔用固定序號的時隙 - 每用戶所佔用的時隙是
週期性出現
(其週期就是TDM幀的長度)
- 時分複用的所有用戶是在不同的時間佔用
相同的
頻帶寬度
- 時分複用則是將時間劃分爲一段段等長的
- 波分多路複用WDM
- 波分複用就是光的頻分複用 (準確來說是光的波長複用)
- 波分複用就是光的頻分複用 (準確來說是光的波長複用)
- 碼分多路複用CDM
- 廣泛應用於無線鏈路共享 (如蜂窩網,衛星通信等)
- 每個用戶分配一個唯一的 m bit
碼片序列
(chipping sequence),其中“0”用“-1
”表示、“1”用“+1
”表 示,
例如: S 站的碼片序列:(–1 –1 –1 +1 +1 –1 +1 +1) - 各用戶使用
相同頻率
載波,利用各自碼片序列編碼數據 編碼信號
=(原始數據)(碼片序列)- 如發送比特 1(+1),則發送自己的
m bit 碼片序列
- 如發送比特 0(-1),則發送該碼片序列的
m bit 碼片序列的反碼
- 如發送比特 1(+1),則發送自己的
- 各用戶碼片序列相互
正交
(orthogonal)
- 令爲原始數據序列,各用戶的疊加向量爲
解碼
: 碼片序列與編碼信號的內積
- 舉例:單用戶
- 舉例:多用戶
1.3.2 數據交換-報文、分組交換(1)
報文交換
報文
:源(應用)發送信息整體 (比如:一整
個文件 )
分組交換
現代網絡通信數據交換基本使用分組交換
技術。
分組
:報文分拆出來的一系列相對較小的數據包
- 分組交換需要報文的
拆分
與重組
- 產生
額外開銷
- 分組交換:統計多路複用(Statistical Multiplexing)
不同端分發的文件的分組同時進入鏈路。
如圖帶寬爲1.5Mb/s。
帶寬是不變的,極端情況例如A分發了文件,而B沒有分發文件,則鏈路中A分發文件的分組佔了1.5Mb/s帶寬;
若A與B都分發了文件,則他們分發文件的分組一共佔1.5Mb/s帶寬。
由此可知統計多路複用技術不會有資源(鏈路帶寬)閒置
的情況出現。 - 存儲-轉發(store-and-forward)交換方式
報文交換
與分組交換
均採用存儲-轉發
交換方式- 區別:
- 報文交換以
完整
報文進行“存儲-轉發” - 分組交換以較小的
分組
進行“存儲-轉發” - 問題:報文交換與分組交換孰優孰劣?下一節將回答這個問題。
- 報文交換以
1.3.3 數據交換-報文、分組交換(2)
衡量哪種交換方式更好的標準之一是分組交換的傳輸延遲的大小
。
- 傳輸延遲
發送主機:- 接收應用報文(消息)
- 拆分爲較小長度爲 bits的分組(packets)
- 在傳輸速率爲 的鏈路上傳輸分組
- 舉例說明報文交換和分組交換孰優孰劣
- 報文交換
- 分組交換
- 報文交換
明顯,分組交換
優勢更大。
分組交換的報文交付時間:
例題:
1.3.4 數據交換-報文、分組交換(3)
分組交換
和電路交換
性能孰優孰劣?
- 電路交換:單個用戶會獨佔鏈路,造成資源浪費。
- 分組交換:採用統計多路複用技術,
允許更多用戶同時使用網絡,網絡資源充分共享。
- 分組交換絕對優於電路交換嗎?
- 分組交換適用於
突發
數據傳輸網絡
例如我們下載文件,有時候突然要下載,- 資源充分共享
- 簡單、無需呼叫建立(電路交換需要)
- 分組交換
可能產生擁塞(congestion)
:分組延遲和丟失- 需要協議處理可靠數據傳輸和擁塞控制
- 問題:如何提供電路級性能保障?
例如音視頻應用所需的帶寬保障。
- 分組交換適用於
1 計算機網絡概述(下)
1.4 計算機網絡性能
1.4.1 速率
速率
即數據率
(data rate)或稱數據傳輸速率
或比特率
(bit rate) 。速率往往是指額定速率或標稱速率 。
- 單位時間(秒)傳輸信息(比特)量
- 計算機網絡中最重要的一個性能指標
- 單位:b/s(或bps)、kb/s、Mb/s、Gb/s
- k=、M=、G=
1.4.2 帶寬
- “
帶寬
”(bandwidth)原本指信號具有的頻帶寬度, 即最高頻率與最低頻率之差,單位是赫茲(Hz) - 網絡的“帶寬”通常是數字信道所能傳送的“
最高數據率
”,單位:b/s (bps) - 常用的帶寬單位:
- kb/s ( b/s)
- Mb/s( b/s)
- Gb/s( b/s)
- Tb/s( b/s)
1.4.3 延遲/時延(delay或latency)
問題:分組交換爲什麼會發生丟包和時延?
回答:分組在路由器緩存中排隊
那什麼時候會出現分組排隊的情況?
分組到達速率超出輸出鏈路容量時
- 等待輸出鏈路可用時
1.4.4 四種分組延遲
- :
結點處理延遲 (nodal processing delay)
- 差錯檢測
- 確定輸出鏈路
- 通常<msec(延遲時間爲毫秒級)
- :
排隊延遲 (queueing delay)
- 等待輸出鏈路可用
- 取決於路由器擁塞程度
- R: 鏈路帶寬(bps)
- L: 分組長度 (bits)
- a: 平均分組到達速率
- 流量強度(traffic intensity)= La/R
- La/R ~ 0: 平均排隊延遲很小
- La/R -> 1: 平均排隊延遲很大
- La/R > 1: 超出服務能力,平均排隊延遲無限大!
- :
傳輸延遲 (transmission delay)
- L: 分組長度(bits)
- R: 鏈路帶寬 (bps)
- = L/R
- :
傳播延遲(propagation delay)
- d: 物理鏈路長度
- s: 信號傳播速度 (~2×108 m/sec)
- = d/s
傳輸延遲和傳播延遲的區別:
1.4.5 時延帶寬積(單位:bits(比特))
鏈路的時延帶寬積又稱爲以比特爲單位的鏈路長度
。
1.4.6 分組丟失(丟包)
三大原因:
- 隊列緩存容量有限
- 分組到達已滿隊列將被丟棄 (即丟包)
- 丟棄分組可能由前序結點或源重發(也可能不重發)
1.4.7 吞吐量/率(Throughput)
吞吐量 :表示在發送端與接收端之間傳送數據速率 (b/s)
- 即時吞吐量: 給定時刻的速率
- 平均吞吐量 : 一段時間的平均速率
討論下面情況的吞吐量是多少
吞吐量是還是?
Internet場景的吞吐量
1.5 計算機網絡體系結構
1.5.1 計算機網絡體系結構概述
爲什麼需要計算機網絡體系結構?
因爲計算機網絡是一個非常複雜的系統 , 涉及許多組成部分
,需要一個抽象的體系概念將其統一起來。
之所以說計算機網絡很複雜,是因爲它牽涉到大量硬件和軟件,例如:
- 主機(hosts)
- 路由器(routers)
- 各種鏈路(links)
- 應用(applications)
- 協議(protocols)
- 硬件、軟件
- ……
那麼問題是:是否存在一種系統結構有效描述計算機網絡呢?利用什麼樣的結構才適合呢?
答案:分層結構
。
複雜系統的分層結構
類比:航空旅行
- 分層結構每層完成一種(類)特定服務/功能
每層依賴底層提供的服務,通過層內動作完成相應功能。(底層提供的服務好比一個接口,其上層來說是透明的,只是給其使用而已。) - 網絡體系結構是從
功能上
描述計算機網絡結構 - 計算機網絡體系結構簡稱網絡體系結構 (network architecture)
是分層結構
- 每層遵循某個/些
網絡協議
完成本層功能
由此可以指導協議是按層
使用的。 計算機網絡體系結構
是計算機網絡的各層及其協議的集合- 體系結構是一個計算機網絡的
功能層次及其關係的定義
- 體系結構是
抽象的
只是將計算機網絡抽象出來,具體由硬件還是軟件實現哪些功能不在考慮範圍內。
爲何採用分層結構?
- 結構清晰,有利於識別複雜系統的部件及其關係
分層的參考模型(reference model )
- 模塊化的分層易於系統
更新
、維護
- 任何一層服務實現的改變對於系統其它層都是透明的
- 例如,登機過程的改變並不影響航空系統的其它部分(層)
- 有利於標準化
將某個分層模型定爲一個框架。 - 分層是否有不利之處?
效率較低!例如辦某種證件或是申請某些東西,需要一層一層批下來,非常慢!所以會出現“跨層實現”這種處理方式。
分層網絡體系結構基本概念
實體(entity)
表示任何可發送或接收信息的硬件或軟件進程。- 協議是控制
兩個對等實體
進行通信的規則的集合。協議是“水平的
” 。 - 任一層實體需要使用
下層
服務,並遵循本層協議,實現本層功能,向上層
提供服務。服務是“垂直的
”。 - 下層協議的實現對上層的服務用戶是
透明
的。 - 同系統的相鄰層實體間通過
接口
進行交互,通過服務訪問點 SAP (Service Access Point)
,交換原語
,指定請求的特定服務。
1.5.2 OSI參考模型(1)
開放系統互連 (OSI)參考模型是由國際標準化組織 (ISO) 於1984年提出的分層網絡體系結構模型,目的是支持異構網絡系統
的互聯互通 ,它是異構網絡系統互連的國際標準
,也是理解網絡通信的最佳學習工具
(理論模型) (理論成功,市場失敗 )。
7層
(功能),每層完成特定的網絡功能
層級 | 作用 | 包含的協議 |
---|---|---|
應用層 | 爲特定應用程序提供數據傳輸服務。 | ( TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet |
表示層 | 對上層信息進行變換,保證一個主機應用層信息被另一個主機的應用程序理解,表示層的數據轉換包括數據的加密、壓縮、格式轉換。 | JPEG、ASCII、GIF、DES、 MPEG |
會話層 | 管理主機之間的會話進程,即負責建立、管理、終止。 | RPC、SQL、NFS |
傳輸層 | 提供端對端的接口。 | TCP,UDP |
網絡層 | 爲數據包選擇路由。 | IP,ICMP,ARP,RARP) |
數據鏈路層 | 傳輸有地址的幀,錯誤檢測功能 | SLIP,CSLIP,PPP,ARP,RARP,MTU |
物理層 | 以二進制數據形式在物理媒體上傳輸數據。 | ISO2110,IEEE802,IEEE802.2 |
OSI參考模型解釋的通信過程
從主機A到主機B的傳輸過程(注意傳輸的方向),反之同理。
可以看到不同主機的同一層之間都有協議進行規範和約束,而且中間系統只有物理層
、數據鏈路層
、網絡層
,剩餘的4層合稱爲端-端層(end-end)
。
OSI參考模型數據封裝與通信過程
數據無論經過哪一層(除物理層
和數據鏈路層
之外),都會被該層加一個“某某層頭”,加“頭”之後稱爲數據包
,在OSI模型中稱之爲協議數據單元
。
爲什麼需要數據封裝?
- 增加
控制信息
構造協議數據單元 (PDU) 。“某某頭”中包含有控制信息。 控制信息
主要包括:地址(Address)
: 標識發送端/接收端差錯檢測編碼(Error-detecting code)
: 用於差錯檢測或糾正協議控制(Protocol control)
: 實現協議功能的附加信 息,如: 優先級(priority)、服務質量(QoS)、 安全控制等
1.5.3 OSI參考模型(2)
本節詳細介紹物理層、數據鏈路層、網絡層的功能。(只有數據鏈路層“加頭又加尾”)
物理層功能
- 接口特性
機械特性、電氣特性、功能特性、規程特性 - 比特編碼
考慮該如何給數據編碼進行傳輸。 - 數據率
- 比特同步
在數據通信中最基本的同步方式就是“比特同步”(bit synchronization)或位同步。比特是數據傳輸的最小單位。比特同步是指接收端時鐘已經調整到和發送端時鐘完全一樣,因此接收端收到比特流後,就能夠在每一個比特的中間位置進行判決。比特同步的目的是爲了將發送端發送的每一個比特都正確地接收下來。 - 時鐘同步
- 傳輸模式
- 單工(Simplex)
數據只能單向傳輸。例如電視,只能接受電視臺的信號。 - 半雙工(half-duplex)
數據可以交替傳輸。例如對講機。 - 全雙工(full-duplex)
數據可以同時在雙方之間傳輸。例如手機、微信通話。
- 單工(Simplex)
數據鏈路層功能
數據鏈路層處理過的數據稱爲幀
,並以其作爲數據單位。
- 負責
結點-結點(node-to-node)
數據傳輸 - 組幀(Framing)
通常來說就是給數據“加頭加尾”。“頭尾”中含有差錯檢測等信息,但信息會依協議的不同而有所不同。 - 物理尋址(Physical addressing)
在幀頭中增加發送端和/或接收端的物理地址標識數據幀的發送端和/或接收端。
在數據中添加源物理地址和目的物理地址是非常重要的,否則可能無法準確發送數據。例如廣播通信(所有主機連接在同一條鏈路上):
- 流量控制(Flow control)
避免淹沒接收端。 - 差錯控制(Error control)
檢測並重傳損壞或丟失幀,並避免重複幀 。 - 訪問(接入)控制(Access control)
在任一給定時刻決定哪個設備擁有鏈路(物理介質)控制使用權 。
網絡層功能
在同一個網絡裏,憑數據鏈路層
的物理地址就可以傳輸數據,但如果要跨越多個網絡進行數據傳輸則需要加上網絡層
的地址。
- 路由(Routing)
- 路由器(或網關)互連網絡,並路由分組至最終目的主機
- 路徑選擇
- 分組轉發
其中紅色英文字母代表網絡層
地址,藍色數字代表數據鏈路層
物理地址,經過這樣的處理就可以進行跨網絡
數據傳輸了。
1.5.4 OSI參考模型(3)
本節詳細介紹4個端-端層
的功能。
傳輸層功能
負責源-目的(端-端) (進程間) 完整報文
傳輸 。
- 分段與重組
- SAP尋址 (Sideband Address Port 邊帶尋址端口)
確保將完整報文提交給正確進程,如端口號 。
- 連接控制
傳輸層的“連接”並非電路交換中的連接(如打電話📞),這是邏輯
上的連接。 - 流量控制
傳輸的速率。 - 差錯控制
數據的糾正。
會話層功能
- 對話控制(dialog controlling)
建立、維護。 - 同步(synchronization)
在數據流中插入“同步點”。
同步點:
會話層基於傳輸層所提供的服務,組織和同步進程間的通信,提供會話服務、會話管理和會話同步等功能。其中,所謂同步就是使會話服務用戶對會話的進展情況都有一致的瞭解,在會話被中斷後可以從中斷處繼續下去,而不必從頭恢復會話
。換而言之,會話用戶把報文分成若干個數據單元,並在相鄰的兩單元間插入同步點並加以同步編號
。出現問題時,可將會話的狀態復位到前一個同步點上
繼續進行會話。
- 最“薄”的一層
在現代網絡參考模型中一般沒有單獨的會話層。
表示層功能
處理兩個系統間交換信息的語法與語義(syntax and semantics )
問題 。
同網絡層
一樣,在現代網絡參考模型中一般也沒有單獨的表示層
。
- 數據表示轉化
轉換爲主機獨立的編碼。例如機器大小端
存儲方式。 - 加密/解密
- 壓縮/解壓縮
應用層功能
- 支持用戶通過用戶代理(如瀏覽器)或網絡接口
使用網絡(服務)
- 典型應用層服務:
- 文件傳輸(FTP)
- 電子郵件(SMTP)
- Web(HTTP)
- ……
1.5.5 TCP/IP參考模型
Internet採用該參考模型。
TCP必須提供
可靠性
的良好性能,這正是大多數用戶所期望的而IP又沒有提供的功能。
1.5.6 "5層"參考模型
大部分現代網絡採用該參考模型,因爲它結合了OSI參考模型
和TCP/IP
參考模型的優點。
應用層
: 支持各種網絡應用
FTP, SMTP, HTTP 。傳輸層
: 進程-進程的數據傳輸
TCP,UDP。網絡層
: 源主機到目的主機的數據分組路由與轉發
IP協議、路由協議等 。鏈路層
: 相鄰網絡元素(主機、交換 機、路由器等)的數據傳輸
以太網(Ethernet)、802.11 (WiFi)、 PPP 。物理層
: 比特傳輸
5層模型的數據封裝
注意:
源主機中的幀
按路線第一次到達路由器時會返回到源主機的網絡層恢復成數據報
,然後再按路線傳輸,經過路由器時再變成幀
,然後才傳輸到目的主機。
1.6 計算機網絡發展歷史
1.6.1 “1961-1972”: 早期分組交換原理的提出與應用
- 1961: Kleinrock – 排隊論證實分組交換的有效性
- 1964: Baran – 分組交換應用於軍事網絡
- 1967: ARPA(Advanced Research Projects Agency)提出ARPAnet 構想
- 1969: 第一個ARPAnet 結點運行
- 1972:
- ARPAnet公開演示
- 第一個主機-主機協議NCP (Network Control Protocol)
- 第一個e-mail程序
- ARPAnet擁有15個結點
1.6.2 “1972-1980”: 網絡互連,大量新型、私有網絡的湧現
- 1970:在夏威夷構建了 ALOHAnet衛星網絡
- 1974: Cerf 與 Kahn – 提出網絡互連體系結構
- 1976: Xerox設計了以太網
以太網🔗 - 70’s後期:
- 私有網絡體系結構: DECnet, SNA, XNA
- 固定長度分組交換 (ATM 先驅)
- 1975:ARPAnet移交給美國國防部通信局管理
- 1979: ARPAnet擁有200結點
1.6.3 “1980-1990”: 新型網絡協議與網絡的激增
- 1983:
部署TCP/IP
- 1982: 定義了smtp電子郵件協議
- 1983: 定義了DNS
- 1985: 定義了FTP協議
- 1988: TCP擁塞控制
- 新型國家級網絡:
CSnet, BITnet,NSFnet
, Minitel(法國) - 1986:NSFnet初步形成了一個由骨幹網、區域網和校園網組成的三級網絡
- 100,000臺主機連接公共網絡
1.6.4 “1990, 2000’s”: 商業化 , Web, 新應用
- 1990’s早期: ARPAnet退役
- 1991: NSF解除NSFnet的商業應用限制(1995年退役), 由私營企業經營
- 1992:因特網協會
ISOC成立
- 1990s後期:
Web應用
- 超文本(hypertext) [Bush 1945, Nelson 1960’s]
- HTML, HTTP: Berners-Lee
- 1994: Mosaic、Netscape瀏覽器
- 1990’s後期:Web開始商業應用
- 1990’s後期 – 2000’s:
- 更多極受歡迎的
網絡應用
: 即時消息系統(如QQ), P2P文件共享 - 網絡安全引起重視
- 網絡主機約達50000,
網絡用戶達1億
以上 - 網絡主幹鏈路帶寬達到 Gbps
- 更多極受歡迎的
1.6.5 “2005~今”
- ~7.5億主機
智能手機和平板電腦 寬帶接入
的快速部署- 無處不在的
高速無線接入
快速增長 - 出現
在線社交網絡
:
Facebook: 很快擁有10億用戶 - 服務提供商 (如Google, Microsoft)創建其自己的
專用網絡
繞開Internet,提供“即時”接入搜索、email等服務 - 電子商務、大學、企業等開始在“
雲
”中運行自己的服務 (如, Amazon EC2)
2 應用層
2.1 網絡應用(層)內容概述
本講內容簡介:
- 網絡應用體系結構
客戶機/服務器
:Web、Email等P2P
- 混合結構
- 網絡應用的服務需求
- 可靠性
- 帶寬
- 時延
- Internet傳輸層服務模型
- TCP
- UDP
- 特定網絡應用及協議
- HTTP
- SMTP,POP,IMAP
- DNS
- P2P應用
- Socket編程
- TCP
- UDP
2.2 網絡應用的基本原理
2.2.1 網絡應用的體系結構
客戶機/服務器結構(Client-Server, C/S)
總而言之,這個結構需要大量主機
(充當服務器)。
- 服務器
7*24小時
提供服務永久性
訪問地址/域名- 利用
大量服務器
實現可擴展性
- 客戶機
- 與服務器通信,使用服務器提供的服務
間歇性
接入網絡- 可能使用動態IP地址
不會與其他客戶機直接通信
例子:Web(萬維網)
點對點結構(Peer-to-peer, P2P)
總而言之,這個結構不需要大量主機
(充當服務器)。
沒有永遠在線的服務器
任意端系統/節點之間可以直接通訊
- 節點間歇性接入網絡
- 節點可能改變IP地址
- 優點:
高度可伸縮
- 缺點:
難於管理
混合結構(Hybrid)
集C/S結構
和P2P結構
於一身。
舉例:
Napster
文件傳輸
使用P2P結構文件搜索
採用C/S結構——集中式
- 每個節點向中央服務器登記自己的內容
- 每個節點向中央服務器提交查詢請求, 查找感興趣的內容
2.2.2 網絡應用進程通信
網絡應用的基礎:進程間通信
- 進程:
主機上運行的程序
。
- 同一主機上運行的進程之間如何通信?
- 進程間通信機制
- 操作系統提供
- 不同主機上運行的進程間如何通信?
消息交換。
補充:
有的。千萬別認爲只有C/S結構纔有客戶機進程/服務器進程之分。
套接字: Socket
本質上是操作系統提供的API
,編寫應用層程序也稱爲網絡編程、套接字編程、Socket編程。
- 進程間通信利用socket發送/接收消息實現
- 類似於寄信
- 發送方將消息送到門外郵箱
- 發送方依賴(門外的)傳輸基礎設施將消息傳到接收方所在主機,並送到接收方的門外
- 接收方從門外獲取消息
- 傳輸基礎設施向進程提供API
- 傳輸協議的選擇
- 參數的設置
如何尋址進程
尋址
是一個在計算機科學中非常重要並且經常出現的概念。
- 不同主機上的進程間通信,那麼每個進程必須擁有
標識符
- 如何尋址主機?——IP地址
- Q: 主機有了IP地址後,
是否足以定位進程
? - A: 否。同一主機上可能同時有多個進程需要通信。
- Q: 主機有了IP地址後,
- 端口號/Port number
- 爲主機上每個需要通信的進程分配一個端口號
- HTTPServer: 80
- MailServer:25
- 進程的標識符
IP地址+端口號
應用層協議
- 網絡應用需遵循應用層協議
- 公開協議
- 由RFC(Request For Comments)定義
若想了解某協議的具體內容,可以去閱讀其RFC文檔。 - 允許互操作
- HTTP, SMTP, ……
- 由RFC(Request For Comments)定義
- 私有協議
多數P2P文件共享應用程序。
公開協議和私有協議:
公開協議一般都是標準化的協議,可以說是廣泛被世人所使用的協議。而私有協議一般是個人制定的,例如商家爲保護自己的利益而開發的指定的內部的網絡協議。
應用層協議的內容
- 消息的類型(type)
請求消息
響應消息
- 消息的語法(syntax)/格式
消息中有哪些字段(field)?
每個字段如何描述
- 字段的語義(semantics)
字段中信息的含義。
- 規則(rules)
進程何時發送/響應消息
進程如何發送/響應消息
2.2.3 網絡應用需求
即網絡應用對傳輸服務的需求。
- 數據丟失(data loss)/可靠性(reliability)
某些網絡應用能夠容忍一定的數據丟失:網絡電話
某些網絡應用要求100%可靠的數據傳輸:文件傳輸,telnet
- 時間(timing)/延遲(delay)
有些應用只有在延遲足夠低時才“有效”
網絡電話/網絡遊戲
- 帶寬(bandwidth)
某些應用只有在帶寬達到最低要求時才“有效”:網絡視頻
某些應用能夠適應任何帶寬——彈性應用:email
典型網絡應用對傳輸服務的需求:
2.2.4 Internet提供的傳輸(層)服務
-
TCP服務
面向連接
: 客戶機/服務器進程間需要建立連接可靠的傳輸
流量控制
: 發送方不會發送速度過快,超過接收方的處理能力擁塞控制
: 當網絡負載過重時能夠限制發送方的發送速度不提供時間/延遲保障
不提供最小帶寬保障
-
UDP服務
- 無連接
- 不可靠的數據傳輸
- 不提供:
- 可靠性保障
- 流量控制
- 擁塞控制
- 延遲保障
- 帶寬保障
典型網絡應用所使用的傳輸層服務:
儘管UDP看起來"很無用",但還是大有用處的。
可以查看爲什麼UDP有時比TCP更有優勢?🔗
2.3 Web應用
2.3.1 Web應用概述
Web與HTTP
- World Wide Web: Tim Berners-Lee
- 網頁
- 網頁互相鏈接
Tim Berners-Lee - 網頁(Web Page)包含多個對象(objects)
- 對象:HTML文件、JPEG圖片、視頻文件、動態腳本等
- 基本HTML文件:包含對其他對象引用的鏈接
- 對象的尋址(addressing)
- URL(Uniform ResoureLocator):統一資源定位器 RFC1738
統一資源定位符是對可以從互聯網上得到的資源的位置和訪問方法的一種簡潔的表示
,是互聯網上標準資源的地址
。互聯網上的每個文件都有一個唯一的URL,它包含的信息指出文件的位置以及瀏覽器應該怎麼處理它。它最初是由蒂姆·伯納斯·李發明用來作爲萬維網的地址。現在它已經被萬維網聯盟編制爲互聯網標準RFC1738了。 - Scheme://host:port/path
協議、主機地址、端口號、對象地址
省略了協議https:
- URL(Uniform ResoureLocator):統一資源定位器 RFC1738
HTTP協議概述
- 萬維網應用遵循超文本傳輸協議(HTTP)
- 超文本傳輸協議 (HTTP)
HyperText Transfer Protocol C/S結構
- 客戶—Browser:請求、接收、展示Web 對象
瀏覽器。 - 服務器—WebServer:響應客戶的請求 ,發送對象
- 客戶—Browser:請求、接收、展示Web 對象
- HTTP版本:
- 1.0:RFC 1945
- 1.1:RFC 2068
- 使用TCP傳輸服務
過程如下
:- 服務器在80端口等待客戶的請求
- 瀏覽器發起到服務器的TCP連接(創建套接字Socket)
TCP是傳輸層
協議。 - 服務器接受來自瀏覽器的TCP連接
- 瀏覽器(HTTP客戶端)與Web服務器(HTTP服務器)交換HTTP消息
- 關閉TCP連接
- 無狀態(stateless)
服務器不維護任何有關客戶端過去所發請求的信息。
爲何是無狀態呢?
2.3.2 HTTP連接類型
非持久性連接(Nonpersistent HTTP)
- 每個TCP連接最多允許傳輸一個對象
- HTTP 1.0版本使用非持久性連接
客戶機在服務器中獲取一個資源的過程:
- RTT(Round Trip Time)
從客戶端發送一個很小的數據包到服務器 並返回所經歷的時間。
- 響應時間(Response time)
- 發起、建立TCP連接:
1個RTT
- 發送HTTP請求消息到HTTP響應消息的前幾個字節到達:
1個RTT
- 響應消息中所含的文件/對象傳輸時間
Total=2RTT +文件發送時間
- 發起、建立TCP連接:
持久性連接(Persistent HTTP)
- 每個TCP連接允許傳輸多個對象
- HTTP 1.1版本默認使用持久性連 接
非持久性連接的問題
- 每個對象需要2個RTT
- 操作系統需要爲每個TCP連接開銷資源(overhead)
- 瀏覽器會怎麼做?
- 打開多個並行的TCP連接以獲取網頁所需對象
- 給服務器端造成什麼影響?
持久性連接
- 發送響應後,服務器保持TCP連接的打開
- 後續的HTTP消息可以通過這個連接發送
無流水(pipelining)的持久性連接
- 客戶端只有收到前一個響應後才發送新的請求
- 每個被引用的對象耗時1個RTT
帶有流水機制的持久性連接
- HTTP 1.1的默認選項
- 客戶端只要遇到一個引用對象就儘快發出請求
- 理想情況下,收到所有的引用對象只需耗時約1個RTT
帶流水和不帶流水的區別:
當我們發送一個數據包,正常的理解是收到ACK包之後,再發送下一個數據包,這樣,一個往返
的時間,我們只傳輸了一個數據包
,浪費了大量資源。流水線就是我們會依次發送多個數據包
,這樣,在第一個數據包得到ACK之前
,我們又發出了幾個
,然後再依次接受他們的ACK
,循環往復,大大的提高了網絡的傳輸速率。
計算機學科的所有理論,能通過程序編寫出來的纔有實用價值,那帶流水機制的持久性連接的程序該如何編寫呢?
2.3.3 HTTP消息格式
- HTTP協議有兩類消息
- 請求消息(request)
- 響應消息(response)
HTTP請求消息
- 請求消息:
ASCII:人直接可讀。
HTTP請求消息的通用格式
上傳輸入的方法
例如在網頁上輸入自己的QQ賬號密碼。
POST方法
- 網頁經常需要填寫表格(form)
- 在請求消息的消息體(entity body) 中上傳客戶端的輸入
URL方法
- 使用GET方法
- 輸入信息通過request行的URL字段上傳
方法的類型
-
HTTP/1.0
- GET
- POST
- HEAD
請Server不要將所請求的對象放入響應消息中。
-
HTTP/1.1
- GET. POST, HEAD
- PUT
將消息體中的文件上傳到URL字段所指定的路徑。 - DELETE
刪除URL字段所指定的文件。
HTTP響應消息
HTTP響應狀態代碼
- 響應消息的第一行
- 示例
200 OK
301 Moved Permanently
400 Bad Request
404 Not Found
505 HTTP Version Not Supported
體驗一下HTTP
- 利用telnet登錄到某個Web服務器(網頁,如哈工大官網)
telnet www.hit.edu.cn 80 - 輸入一個HTTP請求
GET /about/profile.htm HTTP/1.1
Host: www.hit.edu.cn
- 查看HTTP服務器所返回的響應消息
2.3.4 Cookie技術
爲什麼需要Cookie?
因爲HTTP協議無狀態
但很多應用需要服務器掌握客戶端的狀態,如網上購物。
Cookie技術
- Cookie技術
- 某些網站爲了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(通常經過加密)。
- RFC6265(cookie規範)
- Cookie的組件
- HTTP響應消息的cookie頭部行
- HTTP請求消息的cookie頭部行
- 保存在客戶端主機上的cookie文件,由瀏覽器管理
- Web服務器端的後臺數據庫
Cookie的原理
Cookie的作用
- Cookie能夠用於:
- 身份認證
“十天內免登陸” - 購物車
- 推薦
- Web e-mail
- …
- 身份認證
- 正由於Cookie的功能,也使其導致了嚴重的隱私問題。
2.3.5 Web緩存技術/代理服務器技術
- 功能:在不訪問服務器的前提下滿足客戶端的HTTP請求。
- 爲什麼要發明這種技術?
縮短客戶請求的響應時間
減少機構/組織的流量
在大範圍內(Internet)實現有效的內容分發
- Web緩存/代理服務器
用戶設定瀏覽器通過緩存進行Web訪問
瀏覽器向緩存/代理服務器發送所有的HTTP請求
如果所請求對象在緩存中,緩存返回對象
否則,緩存服務器向原始服務器發送HTTP 請求,獲取對象,然後返回給客戶端並保存該對象
Web緩存示例(1):
- 假定:
- 對象的平均大小=100,000 比特 (100kb)
- 機構網絡中的瀏覽器平均每秒有15個到原始服務器的請求
- 從機構路由器到原始服務器的往返延遲=2秒
- 網絡性能分析:
- 局域網(LAN)的利用率=15% (15*100000/10M)
- 接入互聯網的鏈路的利用率=100% (15*100000/1.5M)
- 總的延遲=互聯網上的延遲+訪問延遲+局域網延遲=2秒+幾分鐘+幾微秒
通過這個例子的分析我們可以發現,總的延遲是非常大的,主要是因爲接入互聯網的鏈路的利用率=100% 。
Web緩存示例(2):
- 爲解決示例(1)中的問題,採取如下操作
提升互聯網接入帶寬=10Mbps 。
- 網絡性能分析:
- 局域網(LAN)的利用率=15%
- 接入互聯網的鏈路的利用率=15%
- 總的延遲=互聯網上的延遲+訪問延遲+局域網 延遲=2秒+幾微秒+幾微秒
雖說這樣能在一定的程度上解決問題,但成本太高了。
Web緩存示例(3):
重頭戲來了。
- 安裝Web緩存
- 假定緩存命中率是0.4
- 網絡性能分析
- 40%的請求立刻得到滿足
- 60%的請求通過原始服務器滿足
- 接入互聯網的鏈路的利用率下降到60%,從而訪問延遲可以忽略不計,例如10微秒
- 總的平均延遲=互聯網上的延遲+訪問延遲+局 域網延遲=0.6×2.01秒+0.4×n微秒<1.4秒
可以看到,加了一個Web緩存之後總延遲大大下降了!
但是如何確保cache中的內容都是最新版本呢?這就涉及到接下來要介紹的“條件性GET方法”了。
條件性GET方法
- 目標:
如果緩存有最新的版本,則不需要發送請求對象。 - 緩存:
- 在HTTP
請求消息
中聲明所持有版本的日期
- If-modified-since:
- 在HTTP
- 服務器:
- 如果
緩存的版本是最新
的,則響應消息中不包含對象,對象可以從緩存中得到 - HTTP/1.0 304 Not Modified
- 如果
2.4 Email應用
2.4.1 Email應用概述
Email應用的構成
- Email應用的構成組件
- 郵件客戶端(user agent)
- 讀、寫Email消息
- 與服務器交互,收、發Email消息
- Outlook, Foxmail, Thunderbird
- Web客戶端
- 郵件服務器 (Mail Server)
- 郵箱:存儲發給該用戶的Email
- 消息隊列(message queue):存儲等待發送的Email
SMTP協議(Simple Mail Transfer Protocol)
- 郵件服務器之間傳遞消息所使用的協議
- 客戶端:發送消息的服務器
- 服務器:接收消息的服務器
- 郵件客戶端(user agent)
SMTP協議: RFC 2821
-
使用
TCP
進行email消息的可靠傳輸
-
端口25
-
傳輸過程的三個階段
- 握手
- 消息的傳輸
- 關閉
-
命令/響應交互模式
命令(command): ASCII文本
響應(response): 狀態代碼和語句
-
Email消息只能包含7位ASCII碼
Email應用示例
SMTP交互示例
S:服務器
C:客戶端
動手嘗試SMTP交互
SMTP協議
- 使用持久性連接
- 要求消息必須由7位ASCII碼構成
- SMTP服務器利用CRLF.CRLF(回車換行) 確定消息的結束。
與HTTP對比:
- HTTP: 拉式(pull)
- SMTP: 推式(push)
- 都使用命令/響應交互模式
- 命令和狀態代碼都是 ASCII 碼
- HTTP: 每個對象封裝在獨立的響應消息中
- SMTP: 多個對象在由多個部分構成的消息中發送
2.4.2 Email消息格式和POP協議
Email消息格式
- SMTP:email消息的傳輸/交換協議
- RFC 822:文本消息格式標準
- 頭部行(header)
- To
- From
- Subject
與SMTP命令不同
- 消息體(body)
- 消息本身
- 只能是ASCII字符
- 頭部行(header)
Email消息格式:多媒體擴展
因爲郵件只能發送ASCⅡ碼,所以發送圖片等信息時需要多媒體擴展功能。
- MIME:多媒體郵件擴展RFC 2045, 2056
- 通過在郵件頭部增加額外的行以聲明MIME的內容類型
- 通過在郵件頭部增加額外的行以聲明MIME的內容類型
郵件訪問協議
- 郵件訪問協議:客戶端從服務器獲取郵件
- POP: Post Office Protocol [RFC 1939]
認證/授權(客戶端←→服務器)和下載。- “下載並刪除”模式
用戶如果換了客戶端軟件,無法重讀該郵件。 - “下載並保持”模式
不同客戶端都可以保留消息的拷貝。 - POP3是
無狀態
的
- “下載並刪除”模式
POP協議使用過程:
- IMAP: Internet Mail Access Protocol [RFC 1730]
比POP3協議更加先進。- 更多功能
- 更加複雜
- 能夠操縱服務器上存儲的消息
所有消息統一保存在一個地方:服務器
。 - 允許用戶利用文件夾組織消息
- IMAP支持跨會話(Session)的用戶狀態:
- 文件夾的名字
- 文件夾與消息ID之間的映射等
- HTTP:163, QQ Mail等。
在瀏覽器上發送郵件
使用了HTTP協議。比如我在谷歌瀏覽器上使用QQ郵箱。
- POP: Post Office Protocol [RFC 1939]
2.5 DNS(域名解析系統)
Domain Name System。
互聯網上的核心服務,解決了域名和IP地址之間如何映射
的問題。
2.5.1 DNS概述
DNS:Domain Name System
- 如何識別Internet上的主機/路由器? 可以通過下面兩個方法:
- IP地址
- 域名:www.hit.edu.cn
- 問題:域名和IP地址之間如何映射?
- 域名解析系統DNS
- 多層命名服務器構成的分佈式數據庫
- 應用層協議:完成名字的解析
- Internet核心功能,用應用層協議實現
爲什麼在應用層呢? - 網絡邊界複雜
- Internet核心功能,用應用層協議實現
DNS
- DNS服務
- 域名向IP地址的翻譯
- 主機別名
- 郵件服務器別名
- 負載均衡:Web服務器
- 問題:爲什麼不使用集中式的DNS?
- 單點失敗問題
若服務器損壞壞會導致整個互聯網癱瘓。 - 流量問題
- 距離問題
- 維護性問題
- 單點失敗問題
分佈式層次式數據庫
客戶端想要查詢www.amazon.com的IP的過程:
- 根域名服務器:客戶端查詢根服務器,找到com域名解析服務器
- 頂級域名服務器:客戶端查詢com域名解析服務器,找到amazon.com域名解析服務器
- 權威域名服務器:客戶端查詢amazon.com域名解析服務器,獲得www.amazon.com的IP地址
-
DNS根域名服務器
- 本地域名解析服務器(嚴格來說不屬於層次體系)無法解析域名時,訪問根域名服務器
- 根域名服務器
- 如果不知道映射,訪問權威域名服務器
- 獲得映射
- 向本地域名服務器返回映射
-
TLD域名解析服務器
頂級域名服務器(TLD, top-level domain): 負責com, org, net,edu等頂級域名和國家頂級域名,例如cn, uk, fr
等- Network Solutions維護com頂級域名服務器
- Educause維護edu頂級域名服務器
-
權威(Authoritative)域名服務器:組織的域名解析服務器,提供組織內部服務器的解析服務
- 組織負責維護
- 服務提供商負責維護
-
本地域名解析服務器
不嚴格屬於層級體系
每個ISP(互聯網服務提供商(Internet Service Provider))
都有一個本地域名服務器
默認域名解析服務器。- 當主機進行DNS查詢時,查詢被髮送到本地域名服務器
作爲代理(proxy)
,將查詢轉發給(層級式)域名解析服務器系統。
DNS查詢示例:
Cis.poly.edu 的主機想獲得 gaia.cs.umass.edu 的IP地址
迭代查詢
- 被查詢服務器返回域名解析服務器的名字
- “我不認識這個域名,但是你可以問題這服務器”
遞歸查詢
將域名解析的任務交給所聯繫的服務器
DNS記錄緩存和更新
-
域名解析服務器獲得"域名—IP"映射,即
緩存
這一映射- 一段時間過後,緩存條目失效(刪除)
本地域名服務器一般會緩存頂級域名服務器的映射
因此根域名服務器不經常被訪問。
-
記錄的更新/通知機制
- RFC 2136
- Dynamic Updates in the Domain Name System (DNS UPDATE)
2.5.2 DNS記錄和消息格式
DNS記錄
資源記錄(RR, resource records)。
- Type=A
- Name: 主機域名
- Value: IP地址
- Type=NS
- Name: 域(edu.cn)
- Value: 該域權威域名解析服務器的主機域名
- Type=CNAME
- Name: 某一真實域名的別名
例如:
www.ibm.com– servereast.backup2.ibm.com - Value: 真實域名
- Name: 某一真實域名的別名
- Type=MX
Value是與name相對應的郵件服務器。
DNS協議和消息格式
- DNS協議:
查詢(query)和回覆(reply)消息
HTTP:請求響應
SMTP:命令相應
DNS:查詢回覆- 消息格式相同
- 消息頭部
- Identification: 16位查詢編號,回覆使用相同的編號
- flags (待補充)
- 查詢或回覆
- 期望遞歸
- 遞歸可用
- 權威回答
如何註冊域名?
2.6 P2P應用
2.6.1 P2P應用:原理與文件分發
- Peer-to-peer
沒有服務器
任意端系統之間直接通信
- 節點階段性接入Internet
- 節點可能更換IP地址
文件分發:客戶機/服務器vs. P2P ,到底誰快?
-
C/S
從一個服務器向N個節點分發一個文件需要多長時間?
- 服務器串行地發送N個副本
時間: - 客戶機 需要 時間下載
- 服務器串行地發送N個副本
-
P2P
從一個服務器向N個節點分發一個文件需要多長時間?
- 服務器必鬚髮送一個副本
時間: - 客戶機 需要 時間下載
- 總共需要下載 比特
- 最快的可能上傳速率:
(下載是分開下載的,而上傳是一起上傳。)
- 服務器必鬚髮送一個副本
直觀示例:
2.6.2 文件分發:BitTorrent
BitTorrent 基本原理(1)
- 文件劃分爲256KB的chunk
- 節點加入torrent
- 沒有chunk,但是會逐漸積累
向tracker註冊以獲得節點清單
,與某些節點( “鄰居”)建立連接
下載的同時,節點需要向其他節點上傳 chunk
- 節點可能加入或離開
- 一旦節點獲得完整的文件,它可能(自私地)離開或(無私地)留下
BitTorrent 基本原理(2)
- 獲取chunk
- 給定任一時刻,不同的節點持有文件的不同chunk集合
- 節點(Alice)定期查詢每個鄰居所持有的chunk列表
- 節點發送請求,請求獲取缺失的chunk
稀缺優先 。
- 發送chunk: tit-for-tat
- Alice向4個鄰居發送chunk:正在向其發送Chunk,速率最快的4個選擇爲"top4"
每10秒重新評估top 4。
- Alice向4個鄰居發送chunk:正在向其發送Chunk,速率最快的4個選擇爲"top4"
- 每30秒隨機選擇一個其他節點,向其發送chunk
- 新選擇節點可能加入top 4
- “optimistically unchoke”:
上傳速率高,則能夠找到更好的交易夥伴,從而更快地獲取文件。
“你來我往。”
2.6.3 P2P應用:索引技術
P2P: 搜索信息
- P2P系統的
索引
:
信息到節點位置(IP地址+端口號)的映射 。簡單來說就是要找到某一結點及其擁有的文件。 - 文件共享(電驢)
利用索引動態跟蹤節點所共享文件的位置
節點需要告訴索引它擁有哪些文件
節點搜索索引,從而獲知能夠得到哪些文件
- 即時消息(QQ)
索引負責將用戶名映射到位置
當用戶開啓IM應用時,需要通知索引它的位置
節點檢索索引,確定用戶的IP地址
集中式索引技術
- Napster最早採用這種設計
- 節點加入時,通知中央服務器:
- IP地址
- 內容
- Alice查找“Hey Jude”
- Alice從Bob處請求文件
- 節點加入時,通知中央服務器:
集中式索引的問題
內容和文件傳輸是分佈式的, 但是內容定位是高度集中式的。
- 單點失效問題
- 性能瓶頸
- 版權問題?
2.6.4 洪泛式查詢索引技術:Query flooding
使用圖遍歷算法進行搜索。
- 完全分佈式架構
- Gnutella採用這種架構
- 每個節點對它共享的文件進行索引,且只對它共享的文件進行索引
- 查詢消息通過已有的TCP連接發送
- 節點轉發查詢消息
- 如果查詢命中,則利用反向路徑發回查詢節點
覆蓋網絡(overlay network): Graph
- 節點X與Y之間如果有TCP連接, 那麼構成一個邊(
邊鏈接的兩結點存在直接共享關係
) - 所有的活動節點和邊構成覆蓋網絡
- 邊:虛擬鏈路
- 節點一般鄰居數少於10個
2.6.5 層次式覆蓋網絡索引技術
介於集中式索引和洪泛查詢之間的方法。
- 每個節點或者是一個
超級節點
,或者被分配一個超級節點- 節點和超級節點間維持TCP連接
- 某些超級節點對之間維持TCP連接(
邊鏈接的兩結點存在直接共享關係
)
- 超級節點負責跟蹤子節點的內容
案例:Skype
該應用採用了私有協議,所以它架構是我們猜測的。
- 本質上是P2P的:用戶/節點對之間直接通信
- 採用層次式覆蓋網絡索引技術
- 索引負責維護用戶名與IP地址間的映射
- 索引分佈在超級節點上
2.7 Socket編程
2.7.1 Socket編程-應用編程接口(API)
網絡程序設計接口
底層的編程技術一般爲少數人所掌握,因爲其更加複雜。
應用編程接口 API
幾種典型的應用編程接口
- Berkeley UNIX 操作系統定義了一種 API,稱爲套接字接口(socket interface),簡稱
套接字( socket)
。 - 微軟公司在其操作系統中採用了套接字接口 API ,形成了一個稍有不同的 API,並稱之爲 Windows Socket Interface,
WINSOCK
。 - AT&T 爲其 UNIX 系統 V 定義了一種 API,簡寫 爲
TLI
(Transport Layer Interface)。
2.7.2 Socket編程-Socket API概述
API 用於應用進程與傳輸層的信息交互,是操作系統
提供的。
Socket API
- 最初設計
- 面向BSD UNIX-Berkley
- 面向TCP/IP協議棧接口
- 目前
- 事實上的工業標準
- 絕大多數操作系統都支持
- Internet網絡應用最典型的API接口
用於客戶/服務器(C/S) 通信模型
- 應用進程間通信的抽象機制
如何在服務器端找到想找的接口呢?
-
爲使客戶機準確尋找到想找的插口,傳輸層協議給每一個插口都定義了
唯一的編號
。- 標識通信端點(
對外
):
IP地址+端口號 。 - 操作系統/進程如何管理套接字(
對內
):
套接字描述符(socket descriptor
) (小整數 )。
- 標識通信端點(
Socket抽象
- 類似於文件的抽象
在UNIX系統中,Socket是與文件一同被管理的。 - 當應用進程創建套接字時,
操作系統分配一個數據結構
存儲該套接字相關信息 - 返回套接字描述符
Socket的結構
-
操作系統已定義結構
sockaddr_in
:
-
使用
TCP/IP協議簇
的網絡應用程序聲明端點地址變量時,使用結構sockaddr_in
2.7.3 Socket編程-Socket API函數(1)
Socket編程架構(以WinSock爲例)
WSAStartup
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
- 使用Socket的應用程序在
使用Socket之前必須首先調用 WSAStartup函數
- 兩個參數:
- 第一個參數指明程序請求使用的WinSock版本,其中高位字節指明副版本、低位字節指明主版本
十六進制整數,例如0x102表示2.1版
。 - 第二個參數返回實際的WinSock的版本信息
指向WSADATA
結構的指針
- 第一個參數指明程序請求使用的WinSock版本,其中高位字節指明副版本、低位字節指明主版本
舉例:
使用2.1版本的WinSock的程序代碼段wVersionRequested = MAKEWORD( 2, 1 ); err = WSAStartup( wVersionRequested, &wsaData );
WSACleanup
int WSACleanup (void);
- 應用程序在完成對請求的Socket庫的使用,
最後要調用WSACleanup函數
- 解除與Socket庫的綁定
- 釋放Socket庫所佔用的系統資源
socket
sd = socket(protofamily,type,proto);
- 創建套接字
- 操作系統返回套接字描述符(sd)
- 第一個參數(協議族): protofamily =
PF_INET
(TCP/IP) - 第二個參數(套接字類型):
type =SOCK_STREAM
,SOCK_DGRAM
orSOCK_RAW
(TCP/IP) - 第三個參數(協議號):
0
爲默認
舉例:
創建一個流套接字的代碼段struct protoent *p; p=getprotobyname("tcp"); SOCKET sd=socket(PF_INET,SOCK_STREAM,p->p_proto);
Socket面向TCP/IP的服務(套接字)類型
可以看到SOCK_RAW
是比較特殊的,因爲它面向網絡層
而不是傳輸層
。
TCP
:可靠、面向連接、字節流傳輸、點對點UDP
:不可靠、無連接、數據報傳輸
Closesocket
int closesocket(SOCKET sd);
- 關閉一個描述符爲sd的套接字
- 套接字的關閉 : closesocket
- 如果
多個進程
共享一個套接字,調用closesocket
將套接字引用計數減1,減至0才關閉 - 如果進程中有一個線程調用
closesocket
將其與其他線程共享的套接字關閉時,該進程中的其他線程
也將不能
訪問該套接字 。
- 如果
- 返回值:
0
:成功SOCKET_ERROR
:失敗
bind
int bind(sd,localaddr,addrlen);
客戶程序一般不必調用bind函數 。
- 綁定套接字的本地端點地址
IP地址+端口號 。 - 參數:
- 套接字描述符(sd)
- 端點地址(localaddr)
結構sockaddr_in
- 服務器端調用bind函數需要知道:
- 端口號
- IP地址?
關於IP地址,考慮如下情形:
- 服務器應該綁定哪個地址?
- 解決方案
地址通配符:INADDR_ANY
。
使用地址通配符之後無論選哪個IP地址都可以。
2.7.4 Socket編程-Socket API函數(2)
listen
僅用於服務端 。
int listen(sd,queuesize);
- 置服務器端的流套接字處於監聽狀態
僅服務器端調用
僅用於面向連接的流套接字
- 設置連接請求隊列大小(queuesize)
- 返回值:
0
:成功SOCKET_ERROR
:失敗
connect
僅用於客戶端 。
connect(sd,saddr,saddrlen);
- 客戶程序調用connect函數來使客戶套接字(sd)與特定計算機的特定端口(saddr)的套接字(服務)進行連接
僅用於客戶端
- 可用於
TCP客戶端
也可以用於UDP客戶端
調用 Connect 函數。- TCP客戶端:建立TCP連接
- UDP客戶端:指定服務器端點地址
邏輯上連接,物理上未連接。UDP協議規定了物理上無法連接。
accept
僅用於服務端 。
newsock = accept(sd,caddr,caddrlen);
- 服務程序調用accept函數從處於監聽狀態的流套接字 sd 的客戶連接請求隊列中取出排在最前的一個客戶請求,並且創建一個
新的套接字
來與客戶套接字創建連接通道用於TCP套接字
僅用於服務器
利用新創建的套接字 (newsock)與客戶通信
send, sendto
send(sd,*buf,len,flags);
sendto(sd,*buf,len,flags,destaddr,addrlen);
send
函數TCP
套接字(客戶與服務器)或調用了connect函數的UDP客戶端
套接字sendto
函數用於UDP
服務器端套接字與未調用 connect函數的UDP客戶端
套接字
recv, recvfrom
recv(sd,*buffer,len,flags);
recvfrom(sd,*buf,len,flags,senderaddr,saddrlen);
- recv函數從
TCP
連接的另一端接收數據,或者從調用了connect函數的UDP客戶端
套接字接收服務 器發來的數據 - recvfrom函數用於從
UDP
服務器端套接字與未調用connect函數的UDP客戶端
套接字接收對端數據
setsockopt, getsockopt
這兩個函數很少使用。
int setsockopt(int sd, int level, int optname, *optval, int optlen);
int getsockopt(int sd, int level, int optname, *optval, socklen_t *optlen);
- setsockopt()函數用來設置套接字sd的選項參數
- getsockopt()函數用於獲取任意類型、任意狀態套接口的選項當前值,並把結果存入optval
2.7.5 Socket API函數小結
WSAStartup
: 初始化socket庫(僅對WinSock)WSACleanup
: 清楚/終止socket庫的使用 (僅對WinSock)socket
: 創建套接字connect
:“連接”遠端服務器 (僅用於客戶端)closesocket
: 釋放/關閉套接字
WinSock下函數名是closesocket
,UNIX、Linux下函數名是close
。bind
: 綁定套接字的本地IP地址和端口號(通常客戶端不需要調用)listen
: 置服務器端TCP套接字爲監聽模式,並設置隊列 大小 (僅用於服務器端TCP套接字)accept
: 接受/提取一個連接請求,創建新套接字,通過新套接字與客戶端交互(僅用於服務器端的TCP套接字)recv
: 接收數據(用於TCP套接字或連接模式的客戶端UDP套接字)recvfrom
: 接收數據報(用於非連接模式的UDP套接字)send
: 發送數據(用於TCP套接字或連接模式的客戶端 UDP套接字)sendto
:發送數據報(用於非連接模式的UDP套接字)setsockopt
: 設置套接字選項參數getsockopt
: 獲取套接字選項參數
2.7.6 關於網絡字節順序
- TCP/IP定義了標準的用於協議頭中的二進制整數表示:
網絡字節順序
(network byte order)
不同的機器數據存儲方式可能會不同(如大小端),網絡字節順序
是爲了消除這種影響而存在的標準。 - 某些Socket API函數的參數需要存儲爲網絡字節順序(如IP地址、端口號等)
- 可以實現本地字節順序與網絡字節順序間轉換的函數
htons
: 本地字節順序→網絡字節順序(16bits)ntohs
: 網絡字節順序→本地字節順序(16bits)htonl
: 本地字節順序→網絡字節順序(32bits)ntohl
: 網絡字節順序→本地字節順序(32bits)
編程時要注意網絡字節順序和本地字節順序的轉化。
需要注意某些套接字中的參數是否要求必須爲網絡字節順序,當要將這些參數在本地顯示給用戶時要轉化爲本地字節順序。
2.7.7 網絡應用的Socket API調用基本流程
以TCP連接爲例。
2.7.8 Socket編程-客戶端軟件設計
解析服務器IP地址
- 客戶端可能使用
域名
(如:study.163.com)或IP地址(如:123.58.180.121)標識服務器 - IP協議需要使用32位二進制IP地址
- 需要將域名或IP地址轉換爲32位IP地址
- 函數
inet_addr( )
實現點分十進制IP地址到32位IP地址轉換 - 函數
gethostbyname( )
實現域名到32位IP地址轉換
返回一個指向結構hostent
的指針 。
- 函數
解析服務器(熟知)端口號
- 客戶端還可能使用
服務名
(如HTTP)標識服務器端口 - 需要將服務名轉換爲熟知端口號
調用函數getservbyname( )
:- 返回一個指向結構
servent
的指針
- 返回一個指向結構
解析協議號
- 客戶端可能使用
協議名
(如:TCP)指定協議 - 需要將協議名轉換爲協議號(如:6)
調用函數getprotobyname ( )
實現協議名到協議號的轉換 :- 返回一個指向結構
protoent
的指針
- 返回一個指向結構
TCP客戶端軟件流程
- 確定服務器IP地址與端口號
- 創建套接字
- 分配本地端點地址(IP地址+端口號)
操作系統自己完成。 連接服務器(套接字)
物理上連接。- 遵循應用層協議進行通信
- 關閉/釋放連接
UDP客戶端軟件流程
- 確定服務器IP地址與端口號
- 創建套接字
- 分配本地端點地址(IP地址+端口號)
操作系統自己完成。 指定服務器端點地址,構造UDP數據報
邏輯上連接。- 遵循應用層協議進行通信
- 關閉/釋放套接字
客戶端軟件的實現- connectsock()
設計一個 connectsock
過程封裝底層代碼
/* consock.cpp - connectsock */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif /* INADDR_NONE */
void errexit(const char *, ...);
/*-------------------------------------------------------
* connectsock - allocate & connect a socket using TCP or UDP
*------------------------------------------------------
*/
SOCKET connectsock(const char *host, const char *service, const char *transport )
{
struct hostent *phe; /* pointer to host information entry */
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry */
struct sockaddr_in sin; /* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = pse->s_port;
else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 )
errexit("can't get \"%s\" service entry\n", service);
/* Map host name to IP address, allowing for dotted decimal */
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if ( (sin.sin_addr.s_addr = inet_addr(host))==INADDR_NONE)
errexit("can't get \"%s\" host entry\n", host);
/* Map protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s == INVALID_SOCKET)
errexit("can't create socket: %d\n", GetLastError());
/* Connect the socket */
if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==SOCKET_ERROR)
errexit("can't connect to %s.%s: %d\n", host, service,GetLastError());
return s;
}
客戶端軟件的實現-UDP客戶端
設計 connectUDP
過程用於創建連接模式客戶端UDP套接字
/* conUDP.cpp - connectUDP */
#include <winsock.h>
SOCKET connectsock(const char *, const char *, const char *);
/*-------------------------------------------------------
* connectUDP - connect to a specified UDP service
* on a specified host
*-----------------------------------------------------
*/
SOCKET connectUDP(const char *host, const char *service )
{
return connectsock(host, service, "udp");
}
客戶端軟件的實現-TCP客戶端
設計 connectTCP
過程,用於創建客戶端TCP套接字
/* conTCP.cpp - connectTCP */
#include <winsock.h>
SOCKET connectsock(const char *, const char *, const char *);
/*----------------------------------------------------
* connectTCP - connect to a specified TCP service
* on a specified host
*---------------------------------------------------
*/
SOCKET connectTCP(const char *host, const char *service )
{
return connectsock( host, service, "tcp");
}
客戶端軟件的實現-異常處理
/* errexit.cpp - errexit */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
/*----------------------------------------------------------
* errexit - print an error message and exit
*----------------------------------------------------------
*/
/*VARARGS1*/
void errexit(const char *format, ..
{ va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
WSACleanup();
exit(1);
}
例1:訪問DAYTIME服務的客戶端(TCP)
DAYTIME服務
- 獲取日期和時間
- 雙協議服務(TCP、 UDP),端口號13
- TCP版利用TCP連接請求觸發服務
- UDP版需要客戶端發送一個請求
/* TCPdtc.cpp - main, TCPdaytime */
#include <stdlib.h>
#include <stdio.h>
#include <winsock.h>
void TCPdaytime(const char *, const char *);
void errexit(const char *, ...);
SOCKET connectTCP(const char *, const char *);
#define LINELEN 128
#define WSVERS MAKEWORD(2, 0)
/*--------------------------------------------------------
* main - TCP client for DAYTIME service *--------------------------------------------------------
*/
int main(int argc, char *argv[])
{
char *host = "localhost"; /* host to use if none supplied */
char *service = "daytime"; /* default service port */
WSADATA wsadata;
switch (argc) {
case 1:
host = "localhost"; break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1]; break;
default:
fprintf(stderr, "usage: TCPdaytime [host [port]]\n");
exit(1);
}
if (WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
TCPdaytime(host, service);
WSACleanup();
return 0; /* exit */
}
/*-----------------------------------------------------
* TCPdaytime - invoke Daytime on specified host and print results
*-----------------------------------------------------
*/
void TCPdaytime(const char *host, const char *service)
{
char buf[LINELEN+1]; /* buffer for one line of text */
SOCKET s; /* socket descriptor */
int cc; /* recv character count */
s = connectTCP(host, service);
cc = recv(s, buf, LINELEN, 0);
while( cc != SOCKET_ERROR && cc > 0)
{
buf[cc] = '\0'; /* ensure null-termination */
(void) fputs(buf, stdout);
cc = recv(s, buf, LINELEN, 0);
}
closesocket(s);
}
例2:訪問DAYTIME服務的客戶端(UDP)
/* UDPdtc.cpp - main, UDPdaytime */
#include <stdlib.h>
#include <stdio.h>
#include <winsock.h>
void UDPdaytime(const char *, const char *);
void errexit(const char *, ...);
SOCKET connectUDP(const char *, const char *);
#define LINELEN 128
#define WSVERS MAKEWORD(2, 0)
#define MSG “what daytime is it?\n"
/*--------------------------------------------------------
* main - UDP client for DAYTIME service
*--------------------------------------------------------
*/
int main(int argc, char *argv[])
{
char *host = "localhost"; /* host to use if none supplied */
char *service = "daytime"; /* default service port */
WSADATA wsadata;
switch (argc)
{
case 1:
host = "localhost"; break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1]; break;
default:
fprintf(stderr, "usage: UDPdaytime [host [port]]\n");
exit(1);
}
if (WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
UDPdaytime(host, service);
WSACleanup();
return 0; /* exit */
}
/*-----------------------------------------------------
* UDPdaytime - invoke Daytime on specified host and print results
*-----------------------------------------------------
*/
void UDPdaytime(const char *host, const char *service)
{
char buf[LINELEN+1]; /* buffer for one line of text */
SOCKET s; /* socket descriptor */
int n; /* recv character count */
s = connectUDP(host, service);
(void) send(s, MSG, strlen(MSG), 0);
/* Read the daytime */
n = recv(s, buf, LINELEN, 0);
if (n == SOCKET_ERROR)
errexit("recv failed: recv() error %d\n", GetLastError());
else
{
buf[cc] = '\0'; /* ensure null-termination */
(void) fputs(buf, stdout);
}
closesocket(s);
return 0; /* exit */
}
2.7.9 Socket編程-服務器軟件設計
4種類型基本服務器
循環無連接
(Iterative connectionless) 服務器循環面向連接
(Iterative connection-oriented) 服務器併發無連接
(Concurrent connectionless) 服務器併發面向連接
(Concurrent connection-oriented) 服務器
循環無連接服務器基本流程
- 創建套接字
- 綁定端點地址(
INADDR_ANY
+端口號) 反覆
接收來自客戶端的請求- 遵循應用層協議,構造響應報文,發送給 客戶
數據發送
- 服務器端
不能
使用connect()
函數 - 無連接服務器使用
sendto()
函數發送數據報
獲取客戶端點地址
- 調用
recvfrom()
函數接收數據時,自動提取
循環面向連接服務器基本流程
- 創建(主)套接字,並綁定熟知端口號;
- 設置(主)套接字爲被動監聽模式,準備用於服務器;
- 調用
accept()
函數接收下一個連接請求(通過 主套接字),創建新套接字用於與該客戶建立 連接; - 遵循應用層協議,反覆接收客戶請求,構造併發送響應(通過新套接字);
- 完成爲特定客戶服務後,關閉與該客戶之間的連接,返回步驟3.
併發無連接服務器基本流程
- 主線程
1: 創建套接字,並綁定熟知端口號;
2: 反覆調用recvfrom()
函數,接收下一個客戶請求,並創建新線程處理該客戶響應; - 子線程
1: 接收一個特定請求;
2: 依據應用層協議構造響應報文,並調用sendto()
發送;
3: 退出(一個子線程處理一個請求後即終止)。
併發面向連接服務器基本流程
- 主線程
1: 創建(主)套接字,並綁定熟知zi端口號;
2: 設置(主)套接字爲被動監聽模式,準備用於服務器;
3: 反覆調用accept()
函數接收下一個連接請求(通過主套接字),並創建一個新的子線程處理該客戶響應; - 子線程
1: 接收一個客戶的服務請求(通過新創建 的套接字);
2: 遵循應用層協議與特定客戶進行交互;
3: 關閉/釋放連接並退出(線程終止)
服務器的實現
- 設計一個底層過程隱藏底層代碼:
passivesock()
- 兩個高層過程分別用於創建服務器端UDP套接字和TCP套接字(調用
passivesock()
函數):passiveUDP()
passiveTCP()
服務器的實現-passivesock()
/* passsock.cpp - passivesock */
#include <stdlib.h>
#include <string.h>
#include <winsock.h> void errexit(const char *, ...);
/*-----------------------------------------------------------------------
* passivesock - allocate & bind a server socket using TCP or UDP
*------------------------------------------------------------------------
*/
SOCKET passivesock(const char *service, const char *transport, int qlen)
{
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry */
struct sockaddr_in sin;/* an Internet endpoint address */
SOCKET s; /* socket descriptor */
int type; /* socket type (SOCK_STREAM, SOCK_DGRAM)*/
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = (u_short)pse->s_port;
else if ( (sin.sin_port = htons((u_short)atoi(service))) == 0 )
errexit("can't get \"%s\" service entry\n", service);
/* Map protocol name to protocol number */
if ((ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s == INVALID_SOCKET)
errexit("can't create socket: %d\n", GetLastError());
/* Bind the socket */
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
errexit("can't bind to %s port: %d\n", service,GetLastError());
if (type == SOCK_STREAM && listen(s, qlen) == SOCKET_ERROR)
errexit("can't listen on %s port: %d\n", service,GetLastError());
return s;
}
服務器的實現-passiveUDP()
/* passUDP.cpp - passiveUDP */
#include <winsock.h>
SOCKET passivesock(const char *, const char *, int);
/*-------------------------------------------------------------------------------------
* passiveUDP - create a passive socket for use in a UDP server
*-----------------------------------------------------------------------------------
*/
SOCKET passiveUDP(const char *service)
{
return passivesock(service, "udp", 0);
}
服務器的實現-passiveTCP()
/* passTCP.cpp - passiveTCP */
#include <winsock.h>
SOCKET passivesock(const char *, const char *, int);
/*-----------------------------------------------------------------------------------
* passiveTCP - create a passive socket for use in a TCP server
*-----------------------------------------------------------------------------------
*/
SOCKET passiveTCP(const char *service, int qlen)
{
return passivesock(service, "tcp", qlen);
}
例1:無連接循環DAYTIME服務器
/* UDPdtd.cpp - main, UDPdaytimed */
#include <stdlib.h>
#include <winsock.h>
#include <time.h>
void errexit(const char *, ...);
SOCKET passiveUDP(const char *);
#define WSVERS MAKEWORD(2, 0)
/*------------------------------------------------------------------------
* main - Iterative UDP server for DAYTIME service
*------------------------------------------------------------------------
*/
void main(int argc, char *argv[])
{
struct sockaddr_in fsin; /* the from address of a client */
char *service = "daytime"; /* service name or port number */
SOCKET sock; /* socket */
int alen; /* from-address length */
char *pts; /* pointer to time string */
time_t now; /* current time */
WSADATA wsadata;
switch (argc)
{
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: UDPdaytimed [port]\n");
}
if (WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
sock = passiveUDP(service);
while (1)
{
alen = sizeof(struct sockaddr);
if (recvfrom(sock, buf, sizeof(buf), 0,(struct sockaddr *)&fsin, &alen) == SOCKET_ERROR)
errexit("recvfrom: error %d\n", GetLastError());
(void) time(&now);
pts = ctime(&now);
(void) sendto(sock, pts, strlen(pts), 0,
(struct sockaddr *)&fsin, sizeof(fsin)); }
return 1; /* not reached */
}
例2:面向連接併發DAYTIME服務器
/* TCPdtd.cpp - main, TCPdaytimed */
#include <stdlib.h>
#include <winsock.h>
#include <process.h>
#include <time.h>
void errexit(const char *, ...);
void TCPdaytimed(SOCKET);
SOCKET passiveTCP(const char *, int);
#define QLEN 5
#define WSVERS MAKEWORD(2, 0)
/*------------------------------------------------------------------------
* main - Concurrent TCP server for DAYTIME service
*------------------------------------------------------------------------
*/
void main(int argc, char *argv[])
{
struct sockaddr_in fsin; /* the from address of a client */
char *service = "daytime"; /* service name or port number*/
SOCKET msock, ssock; /* master & slave sockets */
int alen; /* from-address length */
WSADATA wsadata;
switch (argc)
{
case 1: break;
case 2: service = argv[1]; break;
default: errexit("usage: TCPdaytimed [port]\n");
}
if (WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
msock = passiveTCP(service, QLEN);
while (1)
{
alen = sizeof(struct sockaddr);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if (ssock == INVALID_SOCKET)
errexit("accept failed: error number %d\n",GetLastError());
if (_beginthread((void (*)(void *)) TCPdaytimed, 0, (void *)ssock) < 0)
{
errexit("_beginthread: %s\n", strerror(errno));
}
}
return 1; /* not reached */
}
/*----------------------------------------------------------------------
* TCPdaytimed - do TCP DAYTIME protocol
*-----------------------------------------------------------------------
*/
void TCPdaytimed(SOCKET fd)
{
char *pts; /* pointer to time string */
time_t now; /* current time */
(void) time(&now);
pts = ctime(&now
(void) send(fd, pts, strlen(pts), 0);
(void) closesocket(fd); }
3 傳輸層(上)
3.1 傳輸層服務
3.1.1 本章學習內容概括
- 理解傳輸層服務的基本理論和基本機制
- 複用/分用
- 可靠數據傳輸機制
- 流量控制機制
- 擁塞控制機制
- 掌握Internet的傳輸層協議
- UDP:無連接傳輸服務
- TCP:面向連接的傳輸服務
- TCP擁塞控制
3.1.2 傳輸層服務概述
- 傳輸層協議爲運行在不同Host上的進程 提供了一種
邏輯通信機制
- 端系統運行傳輸層協議
發送方
:將應用遞交的消息分成一個或多個的Segment,並向下傳給網絡層。接收方
:將接收到的segment組裝成消息, 並向上交給應用層。- 傳輸層可以爲應用提供多種協議
- Internet上的TCP
- Internet上的UDP
3.1.3 傳輸層 vs. 網絡層
- 網絡層:提供
主機
之間的邏輯通信機制 - 傳輸層:提供
應用進程
之間的邏輯通信機制- 位於網絡層之上
- 依賴於網絡層服務
- 對網絡層服務進行(可能的)增強
3.1.4 Internet傳輸層協議
- 可靠、按序的交付服務(TCP)
- 擁塞控制
- 流量控制
- 連接建立
- 不可靠的交付服務(UDP)
- 基於
“盡力而爲(Best-effort)”
的網絡層 ,沒有做(可靠性方面的)擴展 - 兩種服務均不保證
- 延遲
- 帶寬
- 基於
3.2 複用和分用
即多路複用和多路分用。
3.2.1 分用如何工作?
- 主機接收到IP數據報(datagram)
- 每個數據報攜帶源IP地址、目的IP地址。
- 每個數據報攜帶一個傳輸層的段(Segment )。
- 每個段攜帶源端口號和目的端口號
- 主機收到Segment之後,傳輸層協議提取IP地址和端口號信息,將Segment導向相應的Socket
- TCP做更多處理
3.2.2 無連接分用
-
利用端口號創建Socket
DatagramSocket mySocket1 = new DatagramSocket(99111);
DatagramSocket mySocket2 = new DatagramSocket(99222); -
UDP的Socket用
二元組標識
- (目的IP地址,目的端口號)
-
主機收到UDP段後
- 檢查段中的目的端口號
- 將UDP段導向綁定在該端口號的 Socket
-
來自不同源IP地址和/或源端口號的 IP數據包被導向同一個Socket
3.2.3 面向連接的分用
- TCP的Socket用四元組標識
- 源IP地址
- 源端口號
- 目的IP地址
- 目的端口號
- 接收端利用所有的四個值將Segment導向合適的Socket
- 服務器可能同時支持多個TCP Socket
- 每個Socket用自己的四元組標識
- Web服務器爲每個客戶端開不同的 Socket
3.2.4 面向連接的分用:多線程Web服務器
有時一個進程佔用的資源過大,就會將其分成多個線程。
3.3 無連接傳輸協議-UDP
UDP: User Datagram Protocol [RFC 768]。
多用於容錯性較高
的應用軟件。
- 基於Internet IP協議
- 複用/分用
- 簡單的錯誤校驗
- ·“Best effort”服務·,UDP段可能
- 丟失
- 非按序到達
- 無連接
- UDP發送方和接收方之間不需要握手
- 每個UDP段的處理獨立於其他段
- 常用於流媒體應用
- 容忍丟失
- 速率敏感
- UDP還用於
- DNS
- SNMP
- 在UDP上實現可靠數據傳輸?
- 在應用層增加可靠性機制
- 應用特定的錯誤恢復機制
3.3.1 UDP校驗和(checksum)
目的:檢測UDP段在傳輸中是否發生錯誤(如位翻轉)。
- 發送方
- 將段的內容視爲16-bit整數
- 校驗和計算:計算所有整數的和 ,進位加在和的後面,將得到的值按位求反,得到校驗和
- 發送方將校驗和放入校驗和字段
- 接收方
- 計算所收到段的校驗和
- 將其與校驗和字段進行對比
- 不相等:檢測出錯誤
相等:沒有檢測出錯誤(但可能有錯誤)
校驗和計算示例
- 注意:
- 最高位進位必須被加進去
- 示例:
3.4 可靠數據傳輸的基本原理
3.4.1 可靠數據傳輸概述
什麼是可靠?
不錯、不丟、不亂。- 可靠數據傳輸協議
- 可靠數據傳輸對應用層、傳輸層、鏈路層都很重要
- 網絡Top-10問題
- 信道的不可靠特性決定了可靠數據傳輸協議(rdt)的複雜性
可靠數據傳輸協議基本結構:接口
可靠數據傳輸協議
可靠數據傳輸協議——Rdt協議。
- 漸進地設計可靠數據傳輸協議的發送方和接收方
- 只考慮單向數據傳輸
- 但控制信息雙向流動
- 利用狀態機(Finite State Machine, FSM)刻畫傳輸協議
3.4.2 Rdt 1.0:可靠信道上的可靠數據傳輸
- 底層信道完全可靠
- 不會發生錯誤(bit error)
- 不會丟棄分組
- 發送方和接收方的
FSM獨立
FSM: 有限狀態機
有限狀態機-Finite State Machine,簡寫爲 FSM,是表示有限個狀態及在這些狀態之間的轉移和動作等行爲的數學模型,在計算機領域有着廣泛的應用。通常 FSM 包含幾個要素:狀態的管理、狀態的監控、狀態的觸發、狀態觸發後引發的動作。
3.4.3 Rdt 2.0:產生位錯誤的信道
- 底層信道可能翻轉分組中的位(bit)
- 利用
校驗和
檢測位錯誤
- 利用
- 如何從錯誤中恢復?
確認機制(Acknowledgements, ACK)
: 接收方顯式地告知發送方分組已正確接收NAK
:接收方顯式地告知發送方分組有錯誤- 發送方收到NAK後,
重傳
分組
- 基於這種重傳機制的rdt協議稱爲
ARQ
(Automatic Repeat reQuest)協議 - Rdt 2.0中引入的新機制
- 差錯檢測
- 接收方反饋控制消息: ACK/NAK
- 重傳
FSM規約
無錯誤場景
有錯誤場景
3.4.4 Rdt 2.1和2.2
Rdt 2.0有什麼缺陷?
- 如果ACK/NAK消息發生錯誤/被破壞(corrupted)會怎麼樣?
- 爲ACK/NAK增加校驗和,檢錯並糾錯
- 發送方收到被破壞ACK/NAK時不知道接收方發生了什麼,添加額外的控制消息
- 如果ACK/NAK壞掉,發送方重傳
- 不能簡單的重傳:產生
重複分組
- 如何解決重複分組問題?
序列號(Sequence number)
: 發送方給每個分組增加序列號- 接收方丟棄重複分組
Rdt 2.1: 發送方, 應對ACK/NAK破壞
Rdt 2.1: 接收方, 應對ACK/NAK破壞
沒搞懂,後續再補充
Rdt 2.1 vs. Rdt 2.0
發送方
:- 爲每個分組增加了序列號
- 兩個序列號(0, 1)就夠用,爲什麼 ?
- 需校驗ACK/NAK消息是否發生錯誤
- 狀態數量翻倍
- 狀態必須“記住”“當前”的分組 序列號
接收方
- 需判斷分組是否是重複
- 當前所處狀態提供了期望收到分組 的序列號
- 注意:接收方無法知道ACK/NAK是否被髮送方正確收到
- 需判斷分組是否是重複
3.4.5 Rdt 2.2: 無NAK消息協議
- 我們真的需要兩種確認消息(ACK + NAK)嗎?
- 與rdt 2.1功能相同,但是隻使用ACK
- 如何實現?
- 接收方通過ACK告知最後一個被正確接收的分組
- 在ACK消息中
顯式地加入被確認分組的序列號
- 發送方收到重複ACK之後,採取與收到NAK消息相同的動作
- 重傳當前分組
FSM片段
沒搞懂,後續再補充
3.4.6 Rdt 3.0
如果信道既可能發生錯誤,也可能丟失分組,怎麼辦?
“校驗和 + 序列號 + ACK + 重傳”夠用嗎?- 方法:發送方等待“
合理
”時間- 如果沒收到ACK,重傳
- 如果分組或ACK只是延遲而不是丟了
- 重傳會產生重複,序列號機制能夠處理
- 接收方需在ACK中顯式告知所確認的分組
- 需要
定時器
Rdt 3.0發送方FS
Rdt 3.0示例(1)
Rdt 3.0示例(2)
Rdt 3.0性能分析
- Rdt 3.0能夠正確工作,但性能很差
- 示例:1Gbps鏈路,15ms端到端傳播延遲,1KB分組
- 發送方利用率:發送方發送時間百分比
一次完整的分組傳輸往返所耗的時間僅僅只有0.027%是有用的。 - 在1Gbps鏈路上每30毫秒才發送一個分組→33KB/sec
30ms發送一個1kb分組,1s則發送了33Kb。
難怪我家100M的寬帶網速才3M多。。。
- 網絡協議限制了物理資源的利用
- 發送方利用率:發送方發送時間百分比
Rdt 3.0: 停等操作
Rdt 3.0 性能如此之差的原因。
3.4.7 流水線機制與滑動窗口協議
- 流水線機制:提高資源利用率
流水線協議
- 允許發送方在收到ACK之前
連續發送
多個分組- 更大的
序列號範圍
- 發送方和/或接收方需要更大的存儲空間以
緩存分組
- 更大的
滑動窗口協議
滑動窗口協議: Sliding-window protocol
- 窗口
- 允許使用的序列號範圍
- 窗口尺寸爲N:最多有N個等待確認的消息
- 滑動窗口
- 隨着協議的
運行
,窗口在序列號空間內向前滑動
- 滑動窗口協議:
GBN
,SR
- 隨着協議的
3.4.8 Go-Back-N(GBN)協議
屬於滑動窗口協議之一。
Go-Back-N(GBN)協議: 發送方
-
分組頭部包含k-bit序列號
-
窗口尺寸爲N,最多允許N個分組未確認
-
ACK(n): 確認到序列號n(包含n)的分組均已被正確接收
- 可能收到重複ACK
-
爲空中的分組設置
計時器(timer)
-
超時
Timeout(n)
事件: 重傳序列號大於等於n,還未收到ACK的所有分組
GBN: 發送方擴展FSM
Go-Back-N(GBN)協議: 接收方
- ACK機制: 發送擁有最高序列號的、已被正確接收的分組的ACK
- 可能產生重複ACK
- 只需要記住唯一的expectedseqnum
- 亂序到達的分組:
- 直接丟棄接收方沒有緩存
- 重新確認序列號最大的、按序到達的分組
GBN: 接收方擴展FSM
GBN示例
練習題
- 問題:數據鏈路層採用後退N幀(GBN)協議,發送方已經發送了編號爲 0~7的幀。當計時器超時時,若發送方只收到
0、2、3
號幀的確認 ,則發送方需要重發的幀數是多少?分別是那幾個幀? - 解:根據GBN協議工作原理,GBN協議的確認是累積確認,所以 此時發送端需要重發的幀數是4個,依次分別是
4、5、6、7
號幀。
3.4.9 Selective Repeat(SR)協議
屬於滑動窗口協議之一。
- GBN有什麼缺陷?
- 接收方對每個分組單獨進行確認
- 發送方只重傳那些沒收到ACK的分組
- SR的改進
- 設置緩存機制,緩存亂序到達的分組
- 爲每個分組設置定時器
接收方也有窗口
Selective Repeat:發送方/接收方窗口
博主覺得下面的圖看了也是白看。
SR協議運作方式示例
建議配合視頻觀看。👉🔗
SR協議的“困境”
3.4.10 可靠數據傳輸原理與協議回顧
- 信道的(不可靠)特性
- 可靠數據傳輸的需求
- Rdt 1.0
- Rdt 2.0, rdt 2.1, rdt 2.2
- Rdt 3.0
- 流水線與滑動窗口協議
- GBN
- SR
4 傳輸層(下)
4.1 面向連接傳輸協議-TCP
4.1.1 TCP概述
-
TCP段結構
-
TCP: 序列號和ACK
序列號
:- 序列號指的是segment中第一個字節的編號, 而不是segment的編號
加入於1kb數據,以500b爲一段共分爲2段,第2段的序列號應該是500或501.
- 建立TCP連接時,雙方隨機選擇序列
ACKs
:- 希望接收到的下一個字節的序列號
- 累計確認:該序列號之前的所有字節均已被正確接收到
不是純粹的GBN
也不是純粹的SR
。
Q
: 接收方如何處理亂序到達的Segment?- A: TCP規範中沒有規定,由TCP的實現者做出決策
4.1.2 TCP可靠數據傳輸
TCP可靠數據傳輸概述
- TCP在IP層提供的不可靠服務基礎上實現
可靠數據傳輸服務
- 流水線機制
- 累積確認
- TCP使用單一重傳定時器
- 觸發重傳的事件
- 超時
- 收到重複ACK
- 漸進式
- 暫不考慮重複ACK
- 暫不考慮流量控制
- 暫不考慮擁塞控制
TCP:RTT和超時
-
RTT
問題
:如何設置定時器的超時時間?- 大於RTT ,但是RTT是變化的
- 過短:不必要的重傳
- 過長:對段丟失時間反應慢
問題
:如何估計RTT?- SampleRTT: 測量從段發出去到收到ACK的時間
- 忽略重傳
- SampleRTT變化
- 測量多個SampleRTT,求平均值 ,形成RTT的估計值 EstimatedRTT
- 測量多個SampleRTT,求平均值 ,形成RTT的估計值 EstimatedRTT
- SampleRTT: 測量從段發出去到收到ACK的時間
-
超時
定時器超時時間的設置:
- EstimatedRTT + “安全邊界”
- EstimatedRTT變化大較大的邊界
-
測量RTT的變化值: SampleRTT與EstimatedRTT的差值
-
定時器超時時間的設置:
TCP發送方事件
-
從應用層收到數據
- 創建Segment
- 序列號是Segment第一個字節的編號
- 開啓計時器
- 設置超時時間:
- TimeOutInterval
-
超時
- 重傳引起超時的Segment
- 重啓定時器
-
收到ACK
- 如果確認此前未確認的Segment •
- 更新SendBase
- 如果窗口中還有未被確認的分組, 重新啓動定時器
- 如果確認此前未確認的Segment •
TCP發送端程序的僞代碼
TCP重傳示例
第三種情況可以通過重傳收到ACK100。
TCP-各種需重傳場景下ACK該如何生成
快速重傳機制
先保留一下這個說法:TCP有快速重傳機制,UDP沒有快速重傳機制。
- TCP的實現中,如果發生超 時,超時時間間隔將重新設 置,即將超時時間間隔加倍 ,導致其
很大
- 重發丟失的分組之前要等待很 長時間
- 通過重複ACK檢測分組丟失
- Sender會背靠背地發送多個分 組
- 如果某個分組丟失,可能會引 發多個重複的ACK
- 如果sender收到對同一數據的 3個ACK,則假定該數據之後 的段已經丟失
快速重傳
:在定時器超時之前即 進行重傳
快速重傳算法
4.1.3 TCP流量控制
-
接收方爲TCP連接分配buffer
上層應用有可能接收不來緩存中的數據(上層應用可能處理 buffer中數據的速度較慢)。
-
流量控制的作用
發送方不會傳輸的太多 、太快以至於淹沒接收方 (buffer溢出) 。 -
TCP流量控制其實就是速度匹配機制
發送的速度和接收的速度要匹配好。
TCP流量控制原理詳述
Buffer中的可用空間(spare room)
= RcvWindow
= RcvBuffer-[LastByteRcvd-LastByteRead]- Receiver通過在 Segment 的頭部字段將
RcvWindow
告訴Sender - Sender限制自己已經發送的但還未收到ACK的數據不超過接收方的空閒 RcvWindow尺寸
- Receiver告知Sender RcvWindow=0,會出現什麼情況?
會出現死鎖。
解決辦法: 就算spare room
已經爲0,sender還是要佔點空間告訴receiver現在RecWindow
有多大,如果RecWindow
已經不是0
的話receiver就可以接收buffer了。
4.1.4 TCP連接管理
-
TCP sender和receiver在傳輸數 據前需要建立
連接
-
初始化TCP變量
- Seq. #
- Buffer和流量控制信息
-
Client:連接發起者
Socket clientSocket = new Socket(“hostname”,“port number”); -
Server: 等待客戶連接請求
Socket connectionSocket = welcomeSocket.accept(); -
TCP連接管理:建立
TCP的三次握手機制
Step 1
: client host sends TCP SYN segment to server- specifies initial seq #
- no data
Step 2
: server host receives SYN, replies with SYNACK segment- server allocates buffers
- specifies server initial seq. #
Step 3
: client receives SYNACK, replies with ACK segment, which may contain dat
TCP連接管理:關閉
client closes socket: clientSocket.close();Step 1
:client
向server發送TCP FIN 控制segmentStep 2
:server
收到FIN, 回覆ACK. 關閉連接, 發送 FIN.Step 3
:client
收到FIN, 回覆ACK.- 進入“等待” –如果收到FIN,會重新發送ACK
Step 4
:server
收到ACK. 連接關閉.
TCP連接管理模型
4.2 擁塞控制原理
擁塞(Congestion)
- 非正式定義:“太多發送主機發送了太多數據或者發送速度太快 ,以至於網絡無法處理”
- 表現:
- 分組丟失(路由器緩存溢出)
- 分組延遲過大(在路由器緩存中排隊)
- 擁塞控制 vs. 流量控制
擁塞控制
與流量控制
是不同的概念。擁塞控制
好比是對社會中所有
交通要道的車流量控制,流量控制
好比是對一條馬路
的車流量控制。 - A top-10 problem
4.2.1 擁塞控制原理(1)
擁塞的成因和代價:場景1
- 場景配置
- 兩個senders,兩個 receivers
- 一個路由器, 無限緩存
- 沒有重傳
- 場景1下的性能
- :發送速率
- :接收速率
- C:帶寬
擁塞的成因和代價:場景2
-
場景配置
- 一個路由器, 有限buffers
- Sender重傳分組
-
場景2下的性能
- 情況a: Sender能夠通過某種機制獲知路由器buffer信息,有空閒才發:
- 情況b: 丟失後才重發:
- 情況c:分組丟失和定時器超時後都重發 變得更大
- 情況a: Sender能夠通過某種機制獲知路由器buffer信息,有空閒才發:
情況
b
和c
都是由於分組丟失需要重傳而降低了帶寬的利用率。對於給定的”goodput”,要做更多的工作 (重傳) ,故造成資源的浪費。這是擁塞的其中一個代價。
擁塞的成因和代價:場景3
-
場景配置
- 四個發送方
- 多跳
- 超時/重傳
-
場景3下的性能
假設D發送分組給B,A發送分組給C,此時在路由R2處就會出現資源的爭奪。並且,假如A發送給C的分組成功經過了R1,但在R2處丟失了,那麼此分組在R1處的處理也被浪費了。當分組被drop時,任何用於該分組的“上游”傳輸能力全都被浪費掉。
這是擁塞的另一個代價。
4.2.2 擁塞控制原理(2)
擁塞控制的方法
- 端到端擁塞控制:
- 網絡層不需要顯式的提供支持
- 端系統通過觀察loss,delay等網絡行爲判斷是否發生擁塞
TCP採取這種方法
- 網絡輔助的擁塞控制:
- 路由器向發送方顯式地反饋網絡擁塞信息
- 簡單的擁塞指示(1bit):SNA, DECbit, TCP/IP ECN, ATM)
- 指示發送方應該採取何種速率
案例:ATM ABR擁塞控制
-
ABR:available bit rate
- “彈性服務”
- 如果發送方路徑 “underloaded”
使用可用帶寬 。 - 如果發送方路徑擁塞
將發送速率降到最低保障速率。。
-
RM(resource management) cells
- 發送方發送
- 交換機設置RM cell位(網絡輔助)
NI
bit: rate不許增長CI
bit: 擁塞指示
- RM cell由接收方返回給發送方
-
在RM cell中有顯式的速率(ER)字段:兩個字節
- 擁塞的交換機可以將ER置爲更低的值
- 發送方獲知路徑所能支持的最小速率
-
數據cell中的EFCI位: 擁塞的交換機將其設爲1
- 如果RM cell前面的data cell的EFCI位被設爲1,那麼發送方在返回的RM cell中置CI位
4.3 TCP擁塞控制及TCP性能分析
4.3.1 TCP擁塞控制
-
Sender限制發送速率
-
CongWin:
- 動態調整以改變發送速率
- 反映所感知到的網絡擁塞
-
問題:如何感知網絡擁塞?
- Loss事件=timeout或3個重複 ACK
- 發生loss事件後,發送方降低速率
-
如何合理地調整發送速率?
- 加性增—乘性減:
AIMD
- 慢啓動:
SS
- 加性增—乘性減:
加性增—乘性減: AIMD
原理
:逐漸增加發送速率,謹慎探測可用帶寬,直到發生loss- 方法: AIMD
- Additive Increase:
每個RTT將CongWin增大一個MSS
——擁塞避免 - Multiplicative Decrease:
發生loss後CongWin減半
- Additive Increase:
TCP慢啓動: SS
- TCP連接建立時, CongWin=1
- 例:MSS=500 byte, RTT=200msec
- 初始速率=20kbps
- 可用帶寬可能遠遠高於初始速率:
- 希望快速增長
原理
:- 當連接開始時,
指數性增長
指數性增長
(算法如上圖)- 每個RTT將CongWin翻倍
- 收到每個ACK進行操作
- 初始速率很慢,但是快速攀升
- 當連接開始時,
- 希望快速增長
Threshold變量
慢啓動SS中的指數何使轉換爲線性增長呢?引入Thewshold變量
。
Q
:何時應該指數性增長切 換爲線性增長(擁塞避免 )?A
: 當CongWin達到Loss事件前值的1/2時.
實現方法
:
- 變量
Threshold
- Loss事件發生時, Threshold 被設爲Loss事件前
CongWin
值的1/2。
Loss事件的處理
- 3個重複ACKs:
- CongWin切到一半
- 然後線性增長
- Timeout事件:
- CongWin直接設爲1個MSS
- 然後指數增長
- 達到threshold後, 再線性增長
TCP擁塞控制: 總結
一
- When CongWinis below Threshold, sender in
slow-start
phase, window grows exponentially. - When CongWinis above Threshold, sender is in
congestion-avoidance
phase, window grows linearly. - When a
triple duplicate ACK
occurs, Thresholdset to CongWin/2and CongWinset to Threshold. - When
timeout
occurs, Thresholdset to CongWin/2and CongWinis set to 1 MSS.
二
4.3.2 TCP性能分析
TCP throughput: 吞吐率
- 給定擁塞窗口大小和RTT,TCP的平均吞吐率是多少?
- 忽略掉Slow start
- 假定發生超時時CongWin的大小爲
W
,吞吐率是W/RTT
- 超時後,CongWin=
W/2
,吞吐率是W/2RTT
- 平均吞吐率爲:0.75W/RTT
未來的TCP
-
舉例:每個Segment有1500個byte, RTT是100ms,希望獲得 10Gbps的吞吐率
- throughput = WMSS8/RTT, 則
W=throughput * RTT/(MSS*8) - throughput=10Gbps, 則W=83,333
- throughput = WMSS8/RTT, 則
-
窗口大小爲83,333
-
吞吐率與丟包率(loss rate, L)的關係
- CongWin從W/2增加至W時出現第一個丟包,那麼一共發送的分組數爲 W/2+(W/2+1)+(W/2+2)+….+W = 3W2/8+3W/4
- W很大時,3W2/8>>3W/4,,因此L ≈ 8/(3W2)
-
L = 2·10 - 10
Wow!!! -
高速網絡下需要設計新的TCP
TCP的公平性
-
公平性?
- 如果K個TCP Session共享相同的瓶頸帶寬R,那麼每個Session的平均速率爲R/K
- 如果K個TCP Session共享相同的瓶頸帶寬R,那麼每個Session的平均速率爲R/K
-
TCP具有公平性嗎
?
是的
-
TCP的公平性
公平性與UDP
- 多媒體應用通常不使用TCP, 以免被擁塞控制機制限制速率
- 使用UDP:以恆定速率發送, 能夠容忍丟失
產生了不公平
- 研究:TCP friendly
-
公平性與併發TCP連接
- 某些應用會打開多個併發連接
- Web瀏覽器
產生公平性問題
-
例子:鏈路速率爲R,已有9個連接
- 新來的應用請求1個TCP,獲得 R/10的速率
- 新來的應用請求11個TCP,獲得 R/2的速率
研究
TCP friendly
的UDP
是當下的熱點之一。
4.4 傳輸層總結
- 傳輸層服務的基本原理
複用/解複用
可靠數據傳輸
流量控制
-擁塞控制
- Internet的傳輸層
UDP
TCP
- 下一章
離開網絡“邊界”
進入網絡“核心”
參考資料:
哈工大MOOC https://www.icourse163.org/learn/HIT-154005#/learn/announce
百度百科
網絡
聲明: 轉載請標明來處,創作不易,謝謝。