在計算機通信領域中,IP頭是構成所有TCP/IP網路報文的基礎。因此,了解IP頭的結構和各個欄位的含義,對於網路通信的理解和網路應用點問題的調試都非常重要。本文將從多個方面詳細闡述IP頭的相關內容。
一、IPHeader的結構
typedef struct ip_hdr {
#if BYTE_ORDER == LITTLE_ENDIAN
u_char ip_hl:4, /* 小端模式,低位元組存儲在內存的低地址中 */
ip_v:4;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_char ip_v:4, /* 大端模式,低位元組存儲在內存的高地址中 */
ip_hl:4;
#endif
u_char ip_tos; /* 服務類型欄位 */
short ip_len; /* 報文總長度 */
u_short ip_id; /* 報文標誌 */
short ip_off; /* 分片偏移 */
u_char ip_ttl; /* 生存時間 */
u_char ip_p; /* 協議類型 */
u_short ip_sum; /* 校驗和 */
struct in_addr ip_src,ip_dst; /* 源IP地址和目的IP地址 */
} IP_HDR;
IP頭包含多個欄位,其中包括版本、頭部長度、服務類型、總長度、標識、分片偏移、TTL、協議類型、校驗和、源IP地址以及目的IP地址等。位於每個欄位後面的注釋中,有關於該欄位的簡單解釋。
二、IPHeader的版本
IP頭中的版本欄位(ip_v)記錄了IP協議的版本。IPv4的版本為4,而IPv6的版本為6。IPv4是當前使用最廣泛的IP協議版本,而IPv6協議是IPv4的下一代協議,具有更大的地址空間,能夠支持更多的設備與應用程序連接到互聯網。
三、IPHeader的TTL欄位
Time-To-Live(TTL)欄位是IP頭的一個重要欄位,它標識了IP數據包在網路上可以傳輸的最大跳數。每次經過一個路由器,TTL值就會減少1。當TTL值為0時,數據包將被丟棄,並向發送的主機返回一個ICMP TTL超時消息。因此,TTL的設置對於網路路由的優化非常重要。
四、IPHeader的協議類型欄位
IP頭中的協議類型欄位(ip_p)標識了上層協議類型,例如TCP、UDP、ICMP和IGMP等。它的值對應於IANA協議號分配,詳情請參考IANA的網站。
五、IPHeader的校驗和欄位
IP頭中的校驗和(ip_sum)是UDP、TCP和ICMP協議中使用的校驗和的基礎。它用於保證報文在從源到目的地的傳輸過程中的完整性。計算校驗和時,所有16位字的1’s complement被累加在一起。在累加結束後,將結果的1’s complement取反,得到的值就是校驗和。在將ICMP、TCP和UDP包發送到網路時,將自動計算生成校驗和,並存儲在校驗和欄位中。
六、IPHeader的源IP地址和目的IP地址
IP協議使用IP地址來唯一標識每個連接到互聯網或者私有網路上的設備,就像人類通過姓名和地址之間的聯繫一樣,IP地址在網路通信中扮演了相同的角色。源IP地址表示報文數據包來自哪個設備,目的IP地址表示接收數據包的設備在互聯網上的位置。
七、IPHeader的應用實例
#include <netinet/ip.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#define PACKET_SIZE 4096
int main()
{
int saddr_size , data_size;
struct sockaddr saddr;
unsigned char *buffer = (unsigned char *)malloc(PACKET_SIZE);
int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
if(sock_raw < 0)
{
perror("Could not create socket");
return 1;
}
while(1)
{
saddr_size = sizeof saddr;
// 接收原始數據包
data_size = recvfrom(sock_raw , buffer , PACKET_SIZE , 0 , &saddr , (socklen_t*)&saddr_size);
if(data_size version);
printf("Header length : %d\n" , iph->ihl);
printf("Type Of Service : %d\n" , iph->tos);
printf("Total length : %d\n" , iph->tot_len);
printf("Identification : %d\n" , iph->id);
printf("Time to live : %d\n" , iph->ttl);
printf("Protocol : %d\n" , iph->protocol);
printf("Checksum : %d\n" , iph->check);
printf("Source address : %d.%d.%d.%d\n" , (iph->saddr>>24)&0xff , (iph->saddr>>16)&0xff , (iph->saddr>>8)&0xff , iph->saddr&0xff);
printf("Destination address : %d.%d.%d.%d\n" , (iph->daddr>>24)&0xff , (iph->daddr>>16)&0xff , (iph->daddr>>8)&0xff , iph->daddr&0xff);
}
close(sock_raw);
return 0;
}
上述代碼中使用socket函數創建一個原始套接字,然後使用recvfrom函數從緩衝區中解析IP頭,並對IP頭進行操作,最後輸出相關信息。通常情況下,處理IP頭時需要使用網路庫庫函數或者相關的系統調用。
原創文章,作者:ICSX,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/146822.html
微信掃一掃
支付寶掃一掃