计算机网络核心知识(上)
前言
計算機網絡核心知識系列博客分為上、中、下部分,此篇為(上)。
博客的內容是計算機網絡的核心知識,但也僅僅限于求得“管中窺一豹之形體”,也就是說這是入門級別的博客,若想深入的話,還是得好好啃大部頭。
文章目錄
- 前言
- 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.2.1 什么是網絡協議?
- 1.2.2 協議的三要素
- 1.3 網絡核心
- 1.3.1 數據交換-電路交換
- 多路復用
- 1.3.2 數據交換-報文、分組交換(1)
- 報文交換
- 分組交換
- 1.3.3 數據交換-報文、分組交換(2)
- 1.3.4 數據交換-報文、分組交換(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.5.1 計算機網絡體系結構概述
- 復雜系統的分層結構
- 為何采用分層結構?
- 分層網絡體系結構基本概念
- 1.5.2 OSI參考模型(1)
- OSI參考模型解釋的通信過程
- OSI參考模型數據封裝與通信過程
- 為什么需要數據封裝?
- 1.5.3 OSI參考模型(2)
- 物理層功能
- 數據鏈路層功能
- 網絡層功能
- 1.5.4 OSI參考模型(3)
- 傳輸層功能
- 會話層功能
- 表示層功能
- 應用層功能
- 1.5.5 TCP/IP參考模型
- 1.5.6 "5層"參考模型
- 5層模型的數據封裝
- 1.6 計算機網絡發展歷史
- 1.6.1 "1961-1972": 早期分組交換原理的提出與應用
- 1.6.2 "1972-1980": 網絡互連,大量新型、私有網絡的涌現
- 1.6.3 "1980-1990": 新型網絡協議與網絡的激增
- 1.6.4 "1990, 2000's": 商業化 , Web, 新應用
- 1.6.5 "2005~今"
- 2 應用層
- 2.1 網絡應用(層)內容概述
- 2.2 網絡應用的基本原理
- 2.2.1 網絡應用的體系結構
- 客戶機/服務器結構(Client-Server, C/S)
- 點對點結構(Peer-to-peer, P2P)
- 混合結構(Hybrid)
- 2.2.2 網絡應用進程通信
- 網絡應用的基礎:進程間通信
- 套接字: Socket
- 如何尋址進程
- 應用層協議
- 應用層協議的內容
- 2.2.3 網絡應用需求
- 2.2.4 Internet提供的傳輸(層)服務
- 2.3 Web應用
- 2.3.1 Web應用概述
- Web與HTTP
- HTTP協議概述
- 2.3.2 HTTP連接類型
- 非持久性連接(Nonpersistent HTTP)
- 持久性連接(Persistent HTTP)
- 2.3.3 HTTP消息格式
- HTTP請求消息
- HTTP請求消息的通用格式
- 上傳輸入的方法
- 方法的類型
- HTTP響應消息
- HTTP響應狀態代碼
- 體驗一下HTTP
- 2.3.4 Cookie技術
- 為什么需要Cookie?
- Cookie技術
- Cookie的原理
- Cookie的作用
- 2.3.5 Web緩存技術/代理服務器技術
- 條件性GET方法
- 2.4 Email應用
- 2.4.1 Email應用概述
- Email應用的構成
- SMTP協議: RFC 2821
- Email應用示例
- SMTP交互示例
- 動手嘗試SMTP交互
- SMTP協議
- 2.4.2 Email消息格式和POP協議
- Email消息格式
- Email消息格式:多媒體擴展
- 郵件訪問協議
- 2.5 DNS(域名解析系統)
- 2.5.1 DNS概述
- DNS:Domain Name System
- DNS
- 分布式層次式數據庫
- DNS記錄緩存和更新
- 2.5.2 DNS記錄和消息格式
- DNS記錄
- DNS協議和消息格式
- 如何注冊域名?
- 2.6 P2P應用
- 2.6.1 P2P應用:原理與文件分發
- 文件分發:客戶機/服務器vs. P2P ,到底誰快?
- 2.6.2 文件分發:BitTorrent
- BitTorrent 基本原理(1)
- BitTorrent 基本原理(2)
- 2.6.3 P2P應用:索引技術
- P2P: 搜索信息
- 集中式索引技術
- 集中式索引的問題
- 2.6.4 洪泛式查詢索引技術:Query flooding
- 2.6.5 層次式覆蓋網絡索引技術
- 案例:Skype
- 2.7 Socket編程
- 2.7.1 Socket編程-應用編程接口(API)
- 網絡程序設計接口
- 應用編程接口 API
- 幾種典型的應用編程接口
- 2.7.2 Socket編程-Socket API概述
- Socket API
- 如何在服務器端找到想找的接口呢?
- Socket抽象
- Socket的結構
- 2.7.3 Socket編程-Socket API函數(1)
- Socket編程架構(以WinSock為例)
- WSAStartup
- WSACleanup
- socket
- Closesocket
- bind
- 2.7.4 Socket編程-Socket API函數(2)
- listen
- connect
- accept
- send, sendto
- recv, recvfrom
- setsockopt, getsockopt
- 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編程-服務器軟件設計
- 4種類型基本服務器
- 循環無連接服務器基本流程
- 數據發送
- 獲取客戶端點地址
- 循環面向連接服務器基本流程
- 并發無連接服務器基本流程
- 并發面向連接服務器基本流程
- 服務器的實現
- 服務器的實現-`passivesock() `
- 服務器的實現-`passiveUDP() `
- 服務器的實現-`passiveTCP() `
- 例1:無連接循環DAYTIME服務器
- 例2:面向連接并發DAYTIME服務器
- 3 傳輸層(上)
- 3.1 傳輸層服務
- 3.1.1 本章學習內容概括
- 3.1.2 傳輸層服務概述
- 3.1.3 傳輸層 vs. 網絡層
- 3.1.4 Internet傳輸層協議
- 3.2 復用和分用
- 3.2.1 分用如何工作?
- 3.2.2 無連接分用
- 3.2.3 面向連接的分用
- 3.2.4 面向連接的分用:多線程Web服務器
- 3.3 無連接傳輸協議-UDP
- 3.3.1 UDP校驗和(checksum)
- 校驗和計算示例
- 3.4 可靠數據傳輸的基本原理
- 3.4.1 可靠數據傳輸概述
- 可靠數據傳輸協議基本結構:接口
- 可靠數據傳輸協議
- 3.4.2 Rdt 1.0:可靠信道上的可靠數據傳輸
- 3.4.3 Rdt 2.0:產生位錯誤的信道
- FSM規約
- 無錯誤場景
- 有錯誤場景
- 3.4.4 Rdt 2.1和2.2
- Rdt 2.0有什么缺陷?
- Rdt 2.1: 發送方, 應對ACK/NAK破壞
- Rdt 2.1: 接收方, 應對ACK/NAK破壞
- Rdt 2.1 vs. Rdt 2.0
- 3.4.5 Rdt 2.2: 無NAK消息協議
- FSM片段
- 3.4.6 Rdt 3.0
- Rdt 3.0發送方FS
- Rdt 3.0示例(1)
- Rdt 3.0示例(2)
- Rdt 3.0性能分析
- Rdt 3.0: 停等操作
- 3.4.7 流水線機制與滑動窗口協議
- 流水線協議
- 滑動窗口協議
- 3.4.8 Go-Back-N(GBN)協議
- Go-Back-N(GBN)協議: 發送方
- GBN: 發送方擴展FSM
- Go-Back-N(GBN)協議: 接收方
- GBN: 接收方擴展FSM
- GBN示例
- 練習題
- 3.4.9 Selective Repeat(SR)協議
- Selective Repeat:發送方/接收方窗口
- SR協議運作方式示例
- SR協議的“困境”
- 3.4.10 可靠數據傳輸原理與協議回顧
- 4 傳輸層(下)
- 4.1 面向連接傳輸協議-TCP
- 4.1.1 TCP概述
- 4.1.2 TCP可靠數據傳輸
- TCP可靠數據傳輸概述
- TCP:RTT和超時
- TCP發送方事件
- TCP發送端程序的偽代碼
- TCP重傳示例
- TCP-各種需重傳場景下ACK該如何生成
- 快速重傳機制
- 快速重傳算法
- 4.1.3 TCP流量控制
- TCP流量控制原理詳述
- 4.1.4 TCP連接管理
- 4.2 擁塞控制原理
- 4.2.1 擁塞控制原理(1)
- 擁塞的成因和代價:場景1
- 擁塞的成因和代價:場景2
- 擁塞的成因和代價:場景3
- 4.2.2 擁塞控制原理(2)
- 擁塞控制的方法
- 案例:ATM ABR擁塞控制
- 4.3 TCP擁塞控制及TCP性能分析
- 4.3.1 TCP擁塞控制
- 加性增—乘性減: `AIMD`
- TCP慢啟動: `SS`
- Threshold變量
- Loss事件的處理
- TCP擁塞控制: 總結
- 4.3.2 TCP性能分析
- TCP throughput: 吞吐率
- 未來的TCP
- TCP的公平性
- 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 數據交換-電路交換
數據交換:實現數據通過網絡核心從源主機到達目的主機。
- 為什么需要數據交換?
- N2N^2N2鏈路問題
如果計算機網絡中有NNN臺計算機,則每一臺計算機需要有N?1N-1N?1條鏈路,這是不現實的。 - 保持計算機網絡的連通性
- 適用于不同的網絡規模
- N2N^2N2鏈路問題
- 什么是交換?
- 動態轉接
- 動態分配傳輸資源
- 動態轉接
- 數據交換的類型
- 電路交換
-
最典型電路交換網絡:電話網絡
-
電路交換的三個階段:
- 建立連接(呼叫/電路建立)
- 通信
- 釋放連接(拆除電路)
-
獨占資源
-
電路交換網絡如何共享中繼線?
多路復用(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 碼片序列的反碼
- 各用戶碼片序列相互正交(orthogonal)
1mSi?Sj={1,i=j0,i=?j1mSi?Sj ̄={?1,i=j0,i=?j\frac{1}{m}S_i\cdot S_j =\begin {cases} 1,& i=j \\ 0,&i\not=j \end{cases} \quad \frac{1}{m}S_i\cdot \overline{S_j} =\begin {cases} -1,& i=j \\ 0,&i\not=j \end{cases}m1?Si??Sj?={1,0,?i=ji?=j?m1?Si??Sj??={?1,0,?i=ji?=j? - 令{di}\{di\}{di}為原始數據序列,各用戶的疊加向量為
- 解碼: 碼片序列與編碼信號的內積
1mSi?P={1,Si∈P?1,Si ̄∈P0,Si,Si ̄?P\frac{1}{m}S_i\cdot P=\begin{cases} 1, & S_i\in P \\ -1,& \overline{S_i}\in P \\ 0, & S_i,\overline{S_i}\notin P \end{cases}m1?Si??P=??????1,?1,0,?Si?∈PSi??∈PSi?,Si??∈/?P? - 舉例:單用戶
- 舉例:多用戶
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)
衡量哪種交換方式更好的標準之一是分組交換的傳輸延遲的大小。
- 傳輸延遲
發送主機:- 接收應用報文(消息)
- 拆分為較小長度為 LLL bits的分組(packets)
- 在傳輸速率為 RRR 的鏈路上傳輸分組
- 舉例說明報文交換和分組交換孰優孰劣
- 報文交換
- 分組交換
- 報文交換
明顯,分組交換優勢更大。
分組交換的報文交付時間:
例題:
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=10310^3103、M=10610^6106、G=10910^9109
1.4.2 帶寬
- “帶寬”(bandwidth)原本指信號具有的頻帶寬度, 即最高頻率與最低頻率之差,單位是赫茲(Hz)
- 網絡的“帶寬”通常是數字信道所能傳送的“最高數據率”,單位:b/s (bps)
- 常用的帶寬單位:
- kb/s (10310^3103 b/s)
- Mb/s(10610^6106 b/s)
- Gb/s(10910^9109 b/s)
- Tb/s(101210^121012 b/s)
1.4.3 延遲/時延(delay或latency)
問題:分組交換為什么會發生丟包和時延?
回答:分組在路由器緩存中排隊
那什么時候會出現分組排隊的情況?
- 分組到達速率超出輸出鏈路容量時
- 等待輸出鏈路可用時
1.4.4 四種分組延遲
- dprocd_{proc}dproc?: 結點處理延遲 (nodal processing delay)
- 差錯檢測
- 確定輸出鏈路
- 通常<msec(延遲時間為毫秒級)
- dqueued_{queue}dqueue?: 排隊延遲 (queueing delay)
- 等待輸出鏈路可用
- 取決于路由器擁塞程度
- R: 鏈路帶寬(bps)
- L: 分組長度 (bits)
- a: 平均分組到達速率
- 流量強度(traffic intensity)= La/R
- La/R ~ 0: 平均排隊延遲很小
- La/R -> 1: 平均排隊延遲很大
- La/R > 1: 超出服務能力,平均排隊延遲無限大!
- dtransd_{trans}dtrans?: 傳輸延遲 (transmission delay)
- L: 分組長度(bits)
- R: 鏈路帶寬 (bps)
- dtransd_{trans}dtrans? = L/R
- dpropd_{prop}dprop?: 傳播延遲(propagation delay)
- d: 物理鏈路長度
- s: 信號傳播速度 (~2×108 m/sec)
- dpropd_{prop}dprop? = d/s
傳輸延遲和傳播延遲的區別:
1.4.5 時延帶寬積(單位:bits(比特))
鏈路的時延帶寬積又稱為以比特為單位的鏈路長度 。
1.4.6 分組丟失(丟包)
三大原因:
- 隊列緩存容量有限
- 分組到達已滿隊列將被丟棄 (即丟包)
- 丟棄分組可能由前序結點或源重發(也可能不重發)
1.4.7 吞吐量/率(Throughput)
吞吐量 :表示在發送端與接收端之間傳送數據速率 (b/s)
- 即時吞吐量: 給定時刻的速率
- 平均吞吐量 : 一段時間的平均速率
討論下面情況的吞吐量是多少
吞吐量是RsR_sRs?還是RcR_cRc??
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又沒有提供的功能。
TCP協議🔗
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: 否。同一主機上可能同時有多個進程需要通信。
- 端口號/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
- 網頁
- 網頁互相鏈接
- 網頁(Web Page)包含多個對象(objects)
- 對象:HTML文件、JPEG圖片、視頻文件、動態腳本等
- 基本HTML文件:包含對其他對象引用的鏈接
- 對象的尋址(addressing)
- URL(Uniform ResoureLocator):統一資源定位器 RFC1738
統一資源定位符是對可以從互聯網上得到的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址。互聯網上的每個文件都有一個唯一的URL,它包含的信息指出文件的位置以及瀏覽器應該怎么處理它。它最初是由蒂姆·伯納斯·李發明用來作為萬維網的地址。現在它已經被萬維網聯盟編制為互聯網標準RFC1738了。 - Scheme://host:port/path
協議、主機地址、端口號、對象地址
- 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 +文件發送時間
持久性連接(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/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個副本
時間:NF/usNF/u_sNF/us? - 客戶機 iii 需要 F/diF/d_iF/di? 時間下載
- 服務器串行地發送N個副本
-
P2P
從一個服務器向N個節點分發一個文件需要多長時間?
- 服務器必須發送一個副本
時間:F/usF/u_sF/us? - 客戶機 iii 需要 F/diF/d_iF/di? 時間下載
- 總共需要下載 N?FN\cdot FN?F 比特
- 最快的可能上傳速率:us+Σuiu_s + \Sigma u_ius?+Σui?
(下載是分開下載的,而上傳是一起上傳。)
- 服務器必須發送一個副本
直觀示例:
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的程序代碼段
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 or SOCK_RAW(TCP/IP) - 第三個參數(協議號):0為默認
舉例:
創建一個流套接字的代碼段
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的指針
- 返回一個指向結構servent的指針
解析協議號
- 客戶端可能使用協議名(如:TCP)指定協議
- 需要將協議名轉換為協議號(如:6)
調用函數getprotobyname ( )實現協議名到協議號的轉換 :- 返回一個指向結構protoent的指針
- 返回一個指向結構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版需要客戶端發送一個請求
例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) 服務器
循環無連接服務器基本流程
數據發送
- 服務器端不能使用 connect() 函數
- 無連接服務器使用 sendto() 函數發送數據報
獲取客戶端點地址
- 調用 recvfrom() 函數接收數據時,自動提取
循環面向連接服務器基本流程
并發無連接服務器基本流程
- 主線程
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
- Step 1: client host sends TCP SYN segment to server
- TCP的三次握手機制
- TCP連接管理:關閉
client closes socket: clientSocket.close();- Step 1: client向server發送TCP FIN 控制segment
- Step 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下的性能
- λin\lambda_{in}λin?:發送速率
- λout\lambda_{out}λout?:接收速率
- C:帶寬
擁塞的成因和代價:場景2
-
場景配置
- 一個路由器, 有限buffers
- Sender重傳分組
-
場景2下的性能
- 情況a: Sender能夠通過某種機制獲知路由器buffer信息,有空閑才發:
λin=λout\mathbf{\lambda_{in}=\lambda_{out}}λin?=λout?
- 情況b: 丟失后才重發:
λin′>λout\mathbf{\lambda'_{in}>\lambda_{out}}λin′?>λout?
- 情況c:分組丟失和定時器超時后都重發 λin′\lambda'_{in}λin′? 變得更大
λin′>λin>λout\mathbf{\lambda'_{in}>\lambda_{in}>\lambda_{out}}λin′?>λin?>λout?
- 情況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減半
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 timeoutoccurs, 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)
W=83LThroughput=0.75?MSS?83LRTT≈1.22?MSSRTTLW=\sqrt{\dfrac{8}{3L}} \quad Throughput=\frac{0.75\cdot MSS\cdot \sqrt{\frac{8}{3L}}}{RTT}\approx \frac {1.22\cdot MSS}{RTT\sqrt L}W=3L8??Throughput=RTT0.75?MSS?3L8???≈RTTL?1.22?MSS?
-
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
- 公平性與UDP
-
公平性與并發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
百度百科
網絡
聲明: 轉載請標明來處,創作不易,謝謝。
總結
以上是生活随笔為你收集整理的计算机网络核心知识(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 专题导读:大数据驱动的智能计算体系架构
- 下一篇: 作者:谢华美(1976-),男,中国人民