以下內容概念全部來自wiki,代碼來自WebRTC
私有網絡
IPV4的私有IP定義在RFC 1918
RFC1918 規定區塊名 | IP地址區段 | IP數量 | 分類網絡 說明 | 最大CIDR區塊(子網掩碼) | 主機端位長 |
---|---|---|---|---|---|
24位區塊 | 10.0.0.0 – 10.255.255.255 | 16,777,216 | 單個A類網絡 | 10.0.0.0/8 (255.0.0.0) | 24位 |
20位區塊 | 172.16.0.0 – 172.31.255.255 | 1,048,576 | 16個連續B類網絡 | 172.16.0.0/12 (255.240.0.0) | 20位 |
16位區塊 | 192.168.0.0 – 192.168.255.255 | 65,536 | 256個連續C類網絡 | 192.168.0.0/16 (255.255.0.0) | 16位 |
IPV6的私有IP定義在RFC 4193,地址塊fc00 :: / 7已保留。這些地址稱爲唯一本地地址(Unique Local Addresses,ULA)。 它們被定義爲單播地址,並在路由前綴中包含一個40位的隨機數,以防止在兩個私有網絡互連時發生衝突。 儘管在本地使用,但唯一本地地址的IPv6地址範圍是全局的。
塊 | 前綴 | Global ID (隨機) | Subnet ID | Number of addresses in subnet |
48 bits | 16 bits | 64bits | ||
fd00::/8 | fd | xx:xxxx:xxxx | yyyy | 18,446,744,073,709,551,616 |
下面給出WebRTC中是如何判斷私有地址的代碼
bool IPIsPrivate(const IPAddress& ip) {
switch (ip.family()) {
case AF_INET: {
return IsPrivateV4(ip.v4AddressAsHostOrderInteger());
}
case AF_INET6: {
return IPIsLinkLocal(ip) || IPIsLoopback(ip);
}
}
return false;
}
uint32_t IPAddress::v4AddressAsHostOrderInteger() const {
if (family_ == AF_INET) {
return NetworkToHost32(u_.ip4.s_addr);
} else {
return 0;
}
}
inline uint32_t NetworkToHost32(uint32_t n) {
return be32toh(n);
}
bool IsPrivateV4(uint32_t ip_in_host_order) {
return ((ip_in_host_order >> 24) == 127) ||
((ip_in_host_order >> 24) == 10) ||
((ip_in_host_order >> 20) == ((172 << 4) | 1)) ||
((ip_in_host_order >> 16) == ((192 << 8) | 168)) ||
((ip_in_host_order >> 16) == ((169 << 8) | 254));
}
bool IPIsLinkLocal(const IPAddress& ip) {
// Can't use the helper because the prefix is 10 bits.
in6_addr addr = ip.ipv6_address();
return addr.s6_addr[0] == 0xFE && addr.s6_addr[1] == 0x80;
}
bool IPIsLoopback(const IPAddress& ip) {
switch (ip.family()) {
case AF_INET: {
return (ip.v4AddressAsHostOrderInteger() >> 24) == 127;
}
case AF_INET6: {
return ip == IPAddress(in6addr_loopback);
}
}
return false;
}
如何判斷IPV6是不是ULA
bool IPIsULA(const IPAddress& ip) {
// Can't use the helper because the prefix is 7 bits.
in6_addr addr = ip.ipv6_address();
return (addr.s6_addr[0] & 0xFE) == 0xFC;
}
分類網絡
爲了和已存在的IP地址空間及IP數據報兼容,對IP地址的定義在1981年的RFC 791進行了修改。修改後的IP地址共有三種網絡地址長度不同的單播地址。如下表所示:
Class | 前綴位 | 網絡地址位數 | 剩餘的位數 | 網絡數 | 每個網絡的主機數 | 開始地址 | 結束地址 | 對應的CIDR修飾 | 默認子網掩碼 |
---|---|---|---|---|---|---|---|---|---|
A類地址 | 0 | 8 | 24 | 128 | 16,777,214 | 0.0.0.0 | 127.255.255.255 | /8 | 255.0.0.0 |
B類地址 | 10 | 16 | 16 | 16,384 | 65,534 | 128.0.0.0 | 191.255.255.255 | /16 | 255.255.0.0 |
C類地址 | 110 | 24 | 8 | 2,097,152 | 254 | 192.0.0.0 | 223.255.255.255 | /24 | 255.255.255.0 |
D類地址(羣播) | 1110 | 未定義 | 未定義 | 未定義 | 未定義 | 224.0.0.0 | 239.255.255.255 | /4 | 未定義 |
E類地址(保留) | 1111 | 未定義 | 未定義 | 未定義 | 未定義 | 240.0.0.0 | 255.255.255.255 | /4 | 未定義 |
路由形式
路由(routing)就是通過互聯的網絡把信息從源地址傳輸到目的地址的活動。路由發生在OSI網絡參考模型中的第三層即網絡層。
單播
單播(原文:unicast)是指數據包在計算機網絡的傳輸中,目的地址爲單一目標的一種傳輸方式。它是現今網絡應用最爲廣泛,通常所使用的網絡協議或服務大多采用單播傳輸,例如一切基於TCP的協議。
每次只有兩個實體相互通信,發送端和接收端都是唯一確定的。
廣播
廣播(英語:broadcast)是指將信息數據包發往指定網絡範圍內的所有設備。其發送範圍稱爲“廣播域”。
並非所有的計算機網絡都支持廣播,例如X.25網絡和幀中繼都不支持廣播,而且也沒有在“整個互聯網範圍中”的廣播。IPv6亦不支持廣播,廣播的相應功能由多播代替。
通常來說,廣播都是限制在局域網範圍內,比如以太網或令牌環網絡。因爲廣播在廣域網中可能造成比在局域網中大的多的影響。
廣播地址:
- 以太網和IPv4網都用全1的地址表示廣播,分別是
ff:ff:ff:ff:ff:ff
和255.255.255.255
。 - 令牌環網絡使用IEEE 802.2控制域中的一個特殊值來表示廣播。
多播
在計算機網絡中,多播(英語:multicast,臺灣又譯作多點發送、多點廣播或羣播,中國大陸又譯作組播)是一種羣組通信,它把信息同時傳遞給一組目的計算機。多播可以是一對多或多對多佈置。不應將其與物理層的點到多點通信混淆。
羣組通信可由應用層多播實現,也可由網絡級多播協助實現,後者能讓一個源地址用一次傳輸將數據發給羣組。數據到達包含該組成員的網絡區域時,由路由器、交換機、基站子系統等網絡組件自動完成複製分發。網絡級多播可能通過數據鏈路層的一對多地址交換實現,如以太網多播地址、異步傳輸模式(ATM)、P2MP及Infiniband多播,也可能通過網絡層由IP多播實現。在IP多播中,多播發生在IP路由層面,路由器創建一個最佳路徑將數據發往多播目的地址。
多播通常應用於IP網絡上的流媒體傳輸,如IPTV、多點視頻會議等。
TCP/IP模型
通常人們認爲OSI模型的最上面三層(應用層、表示層和會話層)在TCP/IP組中是一個應用層。由於TCP/IP有一個相對較弱的會話層,由TCP和RTP下的打開和關閉連接組成,並且在TCP和UDP下的各種應用提供不同的端口號,這些功能能夠被單個的應用程序(或者那些應用程序所使用的庫)增加。與此相似的是,IP是按照將它下面的網絡當作一個黑盒子的思想設計的,這樣在討論TCP/IP的時候就可以把它當作一個獨立的層。
層數 | 層名 | 說明 |
---|---|---|
4 | 應用層 | 例如HTTP、FTP、DNS(如BGP和RIP這樣的路由協議,儘管由於各種各樣的原因它們分別運行在TCP和UDP上,仍然可以將它們看作網絡層的一部分) |
3 | 傳輸層 | 例如TCP、UDP、RTP、SCTP(如OSPF這樣的路由協議,儘管運行在IP上也可以看作是網絡層的一部分) |
2 | 網絡互聯層 | 對於TCP/IP來說這是因特網協議(IP)(如ICMP和IGMP這樣的必須協議儘管運行在IP上,也仍然可以看作是網絡互連層的一部分;ARP不運行在IP上) |
1 | 網絡訪問(鏈接)層 | 例如以太網、Wi-Fi、MPLS等。 |
UDP
在TCP/IP模型中,UDP爲網絡層以上和應用層以下提供了一個簡單的接口。UDP只提供數據的不可靠傳遞,它一旦把應用程序發給網絡層的數據發送出去,就不保留數據備份(所以UDP有時候也被認爲是不可靠的數據報協議)。UDP在IP數據報的頭部僅僅加入了複用和數據校驗字段。
UDP適用於不需要或在程序中執行錯誤檢查和糾正的應用,它避免了協議棧中此類處理的開銷。對時間有較高要求的應用程序通常使用UDP,因爲丟棄數據包比等待或重傳導致延遲更可取。
由於UDP缺乏可靠性且屬於無連接協議,所以應用程序通常必須容許一些丟失、錯誤或重複的數據包。某些應用程序(如TFTP)可能會根據需要在應用程序層中添加基本的可靠性機制。
一些應用程序不太需要可靠性機制,甚至可能因爲引入可靠性機制而降低性能,所以它們使用UDP這種缺乏可靠性的協議。流媒體,實時多人遊戲和IP語音(VoIP)是經常使用UDP的應用程序。 在這些特定應用中,丟包通常不是重大問題。如果應用程序需要高度可靠性,則可以使用諸如TCP之類的協議。
例如,在VoIP中延遲和抖動是主要問題。如果使用TCP,那麼任何數據包丟失或錯誤都將導致抖動,因爲TCP在請求及重傳丟失數據時不向應用程序提供後續數據。如果使用UDP,那麼應用程序則需要提供必要的握手,例如實時確認已收到的消息。
由於UDP缺乏擁塞控制,所以需要基於網絡的機制來減少因失控和高速UDP流量負荷而導致的擁塞崩潰效應。換句話說,因爲UDP發送端無法檢測擁塞,所以像使用包隊列和丟棄技術的路由器之類的網絡基礎設備會被用於降低UDP過大流量。數據擁塞控制協議(DCCP)設計成通過在諸如流媒體類型的高速率UDP流中增加主機擁塞控制,來減小這個潛在的問題。
TCP
在因特網協議族(Internet protocol suite)中,TCP層是位於IP層之上,應用層之下的中間層。不同主機的應用層之間經常需要可靠的、像管道一樣的連接,但是IP層不提供這樣的流機制,而是提供不可靠的包交換。
應用層向TCP層發送用於網間傳輸的、用8位字節表示的數據流,然後TCP把數據流分割成適當長度的報文段(通常受該計算機連接的網絡的數據鏈路層的最大傳輸單元(MTU)的限制)。之後TCP把結果包傳給IP層,由它來透過網絡將包傳送給接收端實體的TCP層。TCP爲了保證不發生丟包,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的包發回一個相應的確認信息(ACK);如果發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設爲已丟失並進行重傳。TCP用一個校驗和函數來檢驗數據是否有錯誤,在發送和接收時都要計算校驗和。
其他概念
名詞 | 說明 |
---|---|
MTU | 最大傳輸單元是指資料連結層上面所能通過的最大數據包大小(以字節爲單位)。最大傳輸單元這個參數通常與通信接口有關(網絡卡、串口等) |
NTP | 網絡時間協議,NTP使用64比特的時間戳,其中32位表示秒,32位表示秒的小數,NTP以1900年1月1日作爲開始時間,因此第一次翻轉將在2036年2月7日發生 |
RTT | 來回通信延遲(Round-trip delay time) |
FEC | 前向糾錯(forward error correction),是一種在單向通信系統中控制傳輸錯誤的技術,通過連同數據發送額外的信息進行錯誤恢復,以降低比特誤碼率 |
CRC | 循環冗餘校驗(Cyclic redundancy check),一種數據完整性檢測算法 |
WebRTC中CRC32算法的實現代碼如下:
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
static const uint32_t kCrc32Polynomial = 0xEDB88320;
static uint32_t kCrc32Table[256] = {0};
static void EnsureCrc32TableInited() {
if (kCrc32Table[arraysize(kCrc32Table) - 1])
return; // already inited
for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) {
uint32_t c = i;
for (size_t j = 0; j < 8; ++j) {
if (c & 1) {
c = kCrc32Polynomial ^ (c >> 1);
} else {
c >>= 1;
}
}
kCrc32Table[i] = c;
}
}
uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) {
EnsureCrc32TableInited();
uint32_t c = start ^ 0xFFFFFFFF;
const uint8_t* u = static_cast<const uint8_t*>(buf);
for (size_t i = 0; i < len; ++i) {
c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
}
return c ^ 0xFFFFFFFF;
}