RPF
逆向路徑轉發
的基本思想是:當多播數據報到達多播路由器時,路由器作RPF檢查,以決定是否轉發或拋棄該數據報。RPF檢查過程如下:檢查數據報的源地址,以確定該數據報經過的接口是否在從源到此路由器的最短路徑上,若是,則RPF檢查成功,轉發該數據報到此路由器的輸出接口表的所有接口,否則RPF檢查失敗拋棄該數據報。
ICMP
ICMP協議是IP協議的補充,用於IP層的差錯報告、擁塞控制、路徑控制以及路由器或主機信息的獲取。ICMP與IP協議位於同一個層次(IP層),但ICMP報文是封裝在IP數據報的數據部分進行傳輸的。
ICMP報文由首部和數據段組成。首部為定長的8個字節,前4個字節是通用部分,后4個字節隨報文類型的不同有所差異。
ICMP一般報文格式
類型1 | 代碼1 | 校驗和2 |
首部其他部分4 | ||
數據 |
ICMP報文類型值對應報文
類型值 | 報文類型 |
---|---|
3 | 信宿不可達 |
4 | 源端抑制 |
5 | 重定向 |
11 | 超時 |
12 | 參數錯誤 |
13/14 | 時間戳請求和應答 |
8/0 | 回應請求和應答 |
17/18 | 地址掩碼請求和應答 |
10/9 | 路由器詢問和通告 |
相同類型值的不同代碼值也決定不同的功能
ARP
ARP 協議包(ARP 報文)主要分為 ARP 請求包和 ARP 響應包。
ARP報文格式
每個字段的含義如下。
- 硬件類型:指明了發送方想知道的硬件接口類型,以太網的值為 1。
- 協議類型:表示要映射的協議地址類型。它的值為 0x0800,表示 IP 地址。
- 硬件地址長度和協議長度:分別指出硬件地址和協議的長度,以字節為單位。對於以太網上 IP 地址的ARP請求或應答來說,它們的值分別為 6 和 4。
- 操作類型:用來表示這個報文的類型,ARP 請求為 1,ARP 響應為 2,RARP 請求為 3,RARP 響應為 4。
- 發送方 MAC 地址:發送方設備的硬件地址。
- 發送方 IP 地址:發送方設備的 IP 地址。
- 目標 MAC 地址:接收方設備的硬件地址。
- 目標 IP 地址:接收方設備的IP地址。
IP
IP數據報格式
IP 數據報文由首部(稱為報頭)和數據兩部分組成。首部的前一部分是固定長度,共 20 字節,是所有 IP 數據報必須具有的。在首部的固定部分的后面是一些可選字段,其長度是可變的。
IP 報頭的最小長度為 20 字節,上圖中每個字段的含義如下:
-
版本(version)
占 4 位,表示 IP 協議的版本。通信雙方使用的 IP 協議版本必須一致。目前廣泛使用的IP協議版本號為 4,即 IPv4。
-
首部長度(網際報頭長度IHL)
占 4 位,可表示的最大十進制數值是 15。這個字段所表示數的單位是 32 位字長(1 個 32 位字長是 4 字節)。因此,當 IP 的首部長度為 1111 時(即十進制的 15),首部長度就達到 60 字節。當 IP 分組的首部長度不是 4 字節的整數倍時,必須利用最后的填充字段加以填充。
數據部分永遠在 4 字節的整數倍開始,這樣在實現 IP 協議時較為方便。首部長度限制為 60 字節的缺點是,長度有時可能不夠用,之所以限制長度為 60 字節,是希望用戶盡量減少開銷。最常用的首部長度就是 20 字節(即首部長度為 0101),這時不使用任何選項。
-
區分服務(tos)
也被稱為服務類型,占 8 位,用來獲得更好的服務。這個字段在舊標准中叫做服務類型,但實際上一直沒有被使用過。1998 年 IETF 把這個字段改名為區分服務(Differentiated Services,DS)。只有在使用區分服務時,這個字段才起作用。
-
總長度(totlen)
首部和數據之和,單位為字節。總長度字段為 16 位,因此數據報的最大長度為 2^16-1=65535 字節。
-
標識(identification)
用來標識數據報,占 16 位。IP 協議在存儲器中維持一個計數器。每產生一個數據報,計數器就加 1,並將此值賦給標識字段。當數據報的長度超過網絡的 MTU,而必須分片時,這個標識字段的值就被復制到所有的數據報的標識字段中。具有相同的標識字段值的分片報文會被重組成原來的數據報。
-
標志(flag)
占 3 位。第一位未使用,其值為 0。第二位稱為 DF(不分片),表示是否允許分片。取值為 0 時,表示允許分片;取值為 1 時,表示不允許分片。第三位稱為 MF(更多分片),表示是否還有分片正在傳輸,設置為 0 時,表示沒有更多分片需要發送,或數據報沒有分片。
-
片偏移(offsetfrag)
占 13 位。當報文被分片后,該字段標記該分片在原報文中的相對位置。片偏移以 8 個字節為偏移單位。所以,除了最后一個分片,其他分片的偏移值都是 8 字節(64 位)的整數倍。
-
生存時間(TTL)
表示數據報在網絡中的壽命,占 8 位。該字段由發出數據報的源主機設置。其目的是防止無法交付的數據報無限制地在網絡中傳輸,從而消耗網絡資源。
路由器在轉發數據報之前,先把 TTL 值減 1。若 TTL 值減少到 0,則丟棄這個數據報,不再轉發。因此,TTL 指明數據報在網絡中最多可經過多少個路由器。TTL 的最大數值為 255。若把 TTL 的初始值設為 1,則表示這個數據報只能在本局域網中傳送。
-
協議
表示該數據報文所攜帶的數據所使用的協議類型,占 8 位。該字段可以方便目的主機的 IP 層知道按照什么協議來處理數據部分。不同的協議有專門不同的協議號。
ICMP 的協議號為 1,IGMP的協議號為2,TCP 的協議號為 6,UDP 的協議號為 17。
-
首部檢驗和(checksum)
用於校驗數據報的首部,占 16 位。數據報每經過一個路由器,首部的字段都可能發生變化(如TTL),所以需要重新校驗。而數據部分不發生變化,所以不用重新生成校驗值。
-
源地址
表示數據報的源 IP 地址,占 32 位。
-
目的地址
表示數據報的目的 IP 地址,占 32 位。該字段用於校驗發送是否正確。
-
可選字段
該字段用於一些可選的報頭設置,主要用於測試、調試和安全的目的。這些選項包括嚴格源路由(數據報必須經過指定的路由)、網際時間戳(經過每個路由器時的時間戳記錄)和安全限制。
-
填充
由於可選字段中的長度不是固定的,使用若干個 0 填充該字段,可以保證整個報頭的長度是 32 位的整數倍。
-
數據部分
表示傳輸層的數據,如保存 TCP、UDP、ICMP 或 IGMP 的數據。數據部分的長度不固定
UDP
UDP報文格式
UDP 報文中每個字段的含義如下:
- 源端口:這個字段占據 UDP 報文頭的前 16 位,通常包含發送數據報的應用程序所使用的 UDP 端口。接收端的應用程序利用這個字段的值作為發送響應的目的地址。這個字段是可選的,所以發送端的應用程序不一定會把自己的端口號寫入該字段中。如果不寫入端口號,則把這個字段設置為 0。這樣,接收端的應用程序就不能發送響應了。
- 目的端口:接收端計算機上 UDP 軟件使用的端口,占據 16 位。
- 長度:該字段占據 16 位,表示 UDP 數據報長度,包含 UDP 報文頭和 UDP 數據長度。因為 UDP 報文頭長度是 8 個字節,所以這個值最小為 8。
- 校驗值:該字段占據 16 位,可以檢驗數據在傳輸過程中是否被損壞。
TCP
TCP的主要特點
- 提供面向連接的服務。兩個使用TCP協議進行數據傳輸的應用進程之間首先必須建立TCP連接,並且在數據傳輸完畢后釋放連接。一般把請求連接的一方叫客戶機進程,而響應連接請求的一方叫服務器進程,即TCP連接的建立采用C/S工作模型。
- 提供全雙工數據傳輸服務。只要建立了TCP連接,就能在兩個應用進程之間進行雙向的數據傳輸服務,但是這種傳輸只是端到端的傳輸,不支持廣播和多播。
- 提供面向字節流的服務。兩個建立了TCP連接的應用進程之間交換的是字節流。端到端不保留數據記錄的邊界,也就是說在傳輸層面上不存在數據記錄的概念。
快重傳,快恢復
快重傳
發送方連續收到3個重復的ACK報文,意識到該數據包可能丟失,無論重傳計時器是否溢出,都立即重傳該數據包。
快恢復
快重傳發送之后,不執行慢啟動算法而是執行擁塞避免算法
Nagle,Clark和延遲確認算法
Nagle:針對發送端產生數據較慢,造成每次發送的報文段的數據量較小的情況。主要思想是強制發送方等待,讓它收集發送數據以發送大塊數據,即通過降低發送次數來加大每次發送的數據量。
Clark:針對接收方處理數據較慢,而造成頻繁發送確認報文的情況。主要思想是只要接收方的接收緩沖區已滿,則每次接收到TCP報文后返回窗口值為0的確認報文以停止發送方的數據發送,直到接收緩沖區的空閑區域已經能容納最大長度的報文段或有一半以上的接收緩沖空間已空閑,再發送一個窗口值不為0的確認報文,以重新更新發送方的滑動窗口大小,使發送方繼續發送數據。
延遲確認:當接收方收到報文段后,並不馬上回復確認報文,而是等待接收緩沖區已經有一定數量的空閑空間后,再回送確認報文段。這樣便可減慢發送方滑動窗口的滑動速度,進而降低數據的發送速度。同時也減少了確認報文的數量,進而減少了通信量。但是延遲確認的延遲時間過長有可能迫使發送方重傳沒有確認的報文,因此延遲確認的時間不能太長,一般不能超過500ms。
端口
(協議,主機IP,端口)三元組唯一標識一個進程。
常見熟知端口對應協議
端口號 | 協議 |
---|---|
20/21 | FTP |
22 | SSH |
23 | Telnet |
25 | SMTP |
53 | DNS |
110 | POP3 |
80/443 | HTTP/HTTPS |
143/993 | IMAP/IMAPS |
161/162 | SNMP |
函數
inet_ntoa()
將網絡地址轉換成“.”點隔的字符串格式。
linux下:
函數聲明:char *inet_ntoa(struct in_addr in);
inet_addr()
將一個點分十進制的IP轉換成一個長整數型數。
原型:in_addr_t inet_addr(const char *cp);
gethostbyname()
原型:struct hostent *gethostbyname(const char *name);
name:指向主機名的指針。
gethostbyaddr()
返回對應於給定地址的主機信息。
struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family);
addr參數實際上不是char * 類型,而是一個指向存放IPv4地址的某個in_addr結構的指針;len參數是這個結構的大小,對於IPv4地址為4;family參數為AF_INET。
setsockopt()
原型:int setsockopt(int s,int level,int optname,const char *optval,int optlen);
s:標識一個套接字的描述符。
level:選項定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。
optname:需設置的選項。
optval:指針,指向存放選項值的緩沖區。
optlen:optval緩沖區長度。
WSAStartup()
原型:int PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
WSASocket()
SOCKET WSASocket (
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags
);
af:[in]一個地址族規范。僅支持AF_INET格式,亦即ARPA Internet地址格式。
type:新套接口的類型描述。
protocol:套接口使用的特定協議,如果調用者不願指定協議則定為0。
lpProtocolInfo:一個指向PROTOCOL_INFO結構的指針,該結構定義所創建套接口的特性。如果本參數非零,則前三個參數(af, type, protocol)被忽略。
iFlags:套接口屬性描述。
WSARecv()
int WSAAPI WSARecv(
[in] SOCKET s,
[in, out] LPWSABUF lpBuffers,
[in] DWORD dwBufferCount,
[out] LPDWORD lpNumberOfBytesRecvd,
[in, out] LPDWORD lpFlags,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
[in] s
標識連接套接字的描述符。
[in, out] lpBuffers
指向WSABUF結構數組的指針。每個WSABUF結構都包含一個指向緩沖區的指針和緩沖區的長度(以字節為單位)。
[in] dwBufferCount
lpBuffers數組中WSABUF結構的數量。
[out] lpNumberOfBytesRecvd
指向此調用在接收操作立即完成時接收的數據數(以字節為單位)的指針。
如果lp重疊參數不是NULL,則對此參數使用NULL以避免潛在的錯誤結果。僅當lp重疊參數不是NULL時,此參數才能為NULL。
[in, out] lpFlags
指向用於修改WSARecv函數調用行為的標志的指針。有關詳細信息,請參閱"備注"部分。
[in] lpOverlapped
指向WSAOVERLAPPED結構的指針(對於非重疊套接字,忽略)。
[in] lpCompletionRoutine
類型:_In_opt_LPWSAOVERLAPPED_COMPLETION_ROUTINE
指向在接收操作完成時調用的完成例程的指針(對於非重疊套接字,忽略該指針)。
結構體
in_addr
struct in_addr {
in_addr_t s_addr;
};
in_addr_t一般為32位的unsigned int,其字節順序為網絡字節順序。
typedef struct in_addr {
union {
struct{ unsigned char s_b1,s_b2, s_b3,s_b4;} S_un_b;
struct{ unsigned short s_w1, s_w2;} S_un_w;
unsigned long S_addr;
} S_un;
} IN_ADDR;
闡述下in_addr的含義,很顯然它是一個存儲ip地址的共用體有三種表達方式:
第一種用四個字節來表示IP地址的四個數字;
第二種用兩個雙字節來表示IP地址;
第三種用一個長整型來表示IP地址。
hostent
hostent是host entry的縮寫,該結構記錄主機的信息,包括主機名、別名、地址類型、地址長度和地址列表。之所以主機的地址是一個列表的形式,原因是當一個主機有多個網絡接口時,自然有多個地址。
struct hostent{
char * h_name;
char ** h_aliases;
short h_addrtype;
short h_length;
char ** h_addr_list;
#define h_addr h_addr_list[0];
};
h_name – 地址的正式名稱。
h_aliases – 空字節-地址的預備名稱的指針。
h_addrtype –地址類型; 通常是AF_INET。
h_length – 地址的比特長度。
h_addr_list – 零字節-主機網絡地址指針。網絡字節順序。
h_addr - h_addr_list中的第一地址。
sockaddr
struct sockaddr {
unsigned short sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
sa_family :是2字節的地址家族,一般都是“AF_xxx”的形式,它的值包括三種:AF_INET,AF_INET6和AF_UNSPEC。
如果指定AF_INET,那么函數就不能返回任何IPV6相關的地址信息;如果僅指定了AF_INET6,則就不能返回任何IPV4地址信息。
AF_UNSPEC則意味着函數返回的是適用於指定主機名和服務名且適合任何協議族的地址。如果某個主機既有AAAA記錄(IPV6)地址,同時又有A記錄(IPV4)地址,那么AAAA記錄將作為sockaddr_in6結構返回,而A記錄則作為sockaddr_in結構返回
通常用的都是AF_INET。
sockaddr_in
struct sockaddr_in {
short int sin_family; /* Address family */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
unsigned char sin_zero[8]; /* Same size as struct sockaddr */
};
sin_family:指代協議族,在socket編程中只能是AF_INET
sin_port:存儲端口號(使用網絡字節順序)
sin_addr:存儲IP地址,使用in_addr這個數據結構
sin_zero:是為了讓sockaddr與sockaddr_in兩個數據結構保持大小相同而保留的空字節。