娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

歷史上的今天

今天是:2025年04月28日(星期一)

正在發生

2018年04月28日 | 分析TCP/IP協議棧代碼之IP & ICMP(STM32平臺)

發布者:以泉換泉 來源: eefocus關鍵字:TCP  IP協議棧  IP  ICMP  STM32平臺 手機看文章 掃描二維碼
隨時隨地手機看文章

1. IP介紹

IP是TCP/IP協議族中最為核心的協議。大家,如TCP、UDP、ICMP及IGMP數據,都是在IP數據報格式基礎上再封裝一層再來傳輸的(見圖1 - 4)。


不可靠(unreliable)的意思是它不能保證 IP數據報能成功地到達目的地。 IP僅提供最好的傳輸服務。如果發生某種錯誤時,如某個路由器暫時用完了緩沖區, IP有一個簡單的錯誤處理算法:丟棄該數據報,然后發送 ICMP消息報給信源端。任何要求的可靠性必須由上層來提供(如TCP) 。

無連接(connectionless)這個術語的意思是I P并不維護任何關于后續數據報的狀態信息。每個數據報的處理是相互獨立的。這也說明, IP數據報可以不按發送順序接收。如果一信源向相同的信宿發送兩個連續的數據報(先是 A,然后是B) ,每個數據報都是獨立地進行路由選擇,可能選擇不同的路線,因此B可能在A到達之前先到達。

2. IP首部

I P數據報的格式如圖3 - 1所示。普通的IP首部長為20個字節,除非含有選項字段。


分析圖3 - 1中的首部。最高位在左邊,記為0 bit;最低位在右邊,記為31 bit。4個字節的32 bit值以下面的次序傳輸:首先是0~7 bit,其次8~15 bit,然后1 6~23 bit,最后是24~31 bit。這種傳輸次序稱作big endian字節序。由于TCP/IP首部中所有的二進制整數在網絡中傳輸時都要求以這種次序,因此它又稱作網絡字節序。

目前的協議版本號是4,因此IP有時也稱作IPv4。

服務類型(TOS)字段包括一個3 bit的優先權子字段(現在已被忽略) ,4 bit的TO S子字段和1 bit未用位但必須置0。4 bit的TO S分別代表:最小時延、最大吞吐量、最高可靠性和最小費用。

總長度字段是指整個I P數據報的長度,以字節為單位。

標識字段唯一地標識主機發送的每一份數據報。通常每發送一份報文它的值就會加 1。在大多數從伯克利派生出來的系統中,每發送一個I P數據報,I P層都要把一個內核變量的值加1,不管交給IP的數據來自哪一層。內核變量的初始值根據系統引導時的時間來設置。

TTL(time-to-live)生存時間字段設置了數據報可以經過的最多路由器數。TTL的初始值由源主機設置(通常為3 2或6 4) ,一旦經過一個處理它的路由器,它的值就減去1。當該字段的值為0時,數據報就被丟棄,并發送 ICMP報文通知源主機。

協議字段可以識別是哪個協議向I P傳送數據。

首部檢驗和字段是根據IP首部計算的檢驗和碼。它不對首部后面的數據進行計算。 ICMP、IGMP、UDP和TCP在它們各自的首部中均含有同時覆蓋首部和數據檢驗和碼。

目前,這些任選項定義如下:

? 安全和處理限制(用于軍事領域,詳細內容參見 RFC 1108[Kent 1991])

? 記錄路徑(讓每個路由器都記下它的IP地址,見7 . 3節)

? 時間戳(讓每個路由器都記下它的IP地址和時間,見7 . 4節)

? 寬松的源站選路(為數據報指定一系列必須經過的 IP地址,見8 . 5節)

? 嚴格的源站選路(與寬松的源站選路類似,但是要求只能經過指定的這些地址,不能經過其他的地址) 。

------------------------------------------以上內容整理于《TCP/IP協議詳解:卷1》--------------------------------------

------------------------------------------以下內容產生于代碼及分析--------------------------------------

3. IP宏定義實現

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


// ******* IP *******
//IP首部長度
#define IP_HEADER_LEN   20

//IP版本號位置 以太網首部2+6+6,與下面那個在用的時候上區別下
#define IP_HEADER_LEN_VER_P 0xe

//IP版本號位置 以太網首部2+6+6
#define IP_P 0xe
//IP 16位標志位置
#define IP_FLAGS_P 0x14
//IP 生存時間位置
#define IP_TTL_P 0x16
//IP協議類型位置,如ICMP,TCP,UDP 1個字節
#define IP_PROTO_P 0x17
//首部校驗和
#define IP_CHECKSUM_P 0x18
// IP源地址位置 14+12
#define IP_SRC_P 0x1a
// IP目標地址位置 14+12+4
#define IP_DST_P 0x1e

//IP總長度
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11

//協議類型
#define IP_PROTO_ICMP_V 0x01
#define IP_PROTO_TCP_V 0x06
#define IP_PROTO_UDP_V 0x11


4. IP函數實現

以太網的header在IP的header之前,很簡單的,介紹先。

 配置以太網的頭,為14字節:6字節目的mac地址+6字節源mac地址+2字節協議類型

1
2
3
4
5
6
7
8
9
10
11
12
13


// make a return eth header from a received eth packet
void make_eth(unsigned char *buf)
{
    unsigned char  i = 0;

    //copy the destination mac from the source and fill my mac into src
    while(i < sizeof(mac_addr))
    {
        buf[ETH_DST_MAC + i] = buf[ETH_SRC_MAC + i];
        buf[ETH_SRC_MAC + i] = macaddr[i];
        i++;
    }
}


展開之后如下所示,其在以太網幀中的位置與之前的宏定義是一一對應的。


IP與ARP一樣,需要判定是不是發給本機的(eth_type_is_ip_and_my_ip函數),還有與填充make_eth  函數一樣需要填充函數(make_ip函數),此外還有填充其他雜七雜八和16位首部校驗和函數(fill_ip_hdr_checksum函數)

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


//判定過程與eth_type_is_arp_and_my_ip類似
unsigned char  eth_type_is_ip_and_my_ip(unsigned char *buf, unsigned  int len)
{
    unsigned char  i = 0;

    //eth+ip+udp header is 42
    if(len < MIN_FRAMELEN)
    {
        return(0);
    }

    if(buf[ETH_TYPE_H_P] != ETHTYPE_IP_H_V || buf[ETH_TYPE_L_P] != ETHTYPE_IP_L_V)
    {
        return(0);
    }

    if(buf[IP_HEADER_LEN_VER_P] != 0x45)
    {
        // must be IP V4 and 20 byte header
        return(0);
    }

    while(i < sizeof(ipv4_addr))
    {
        if(buf[IP_DST_P + i] != ipaddr[i])
        {
            return(0);
        }

        i++;
    }

    return(1);
}
//下面那個ip填充函數調用它,主要是補充填充和校驗和
void fill_ip_hdr_checksum(unsigned char *buf)
{
    unsigned  int ck;
    // clear the 2 byte checksum
    buf[IP_CHECKSUM_P] = 0;
    buf[IP_CHECKSUM_P + 1] = 0;
    buf[IP_FLAGS_P] = 0x40; // don't fragment
    buf[IP_FLAGS_P + 1] = 0; // fragement offset
    buf[IP_TTL_P] = 64; // ttl
    // calculate the checksum:
    //校驗和計算,在下下面那個函數里面,輸入參數的含義下面看就曉得了
    ck = checksum(&buf[IP_P], IP_HEADER_LEN, 0);
    buf[IP_CHECKSUM_P] = ck >> 8;
    buf[IP_CHECKSUM_P + 1] = ck & 0xff;
}

// make a return ip header from a received ip packet
//與以太網填充函數類似,填充ip地址
void make_ip(unsigned char *buf)
{
    unsigned char  i = 0;

    while(i < sizeof(ipv4_addr))
    {
        buf[IP_DST_P + i] = buf[IP_SRC_P + i];
        buf[IP_SRC_P + i] = ipaddr[i];
        i++;
    }

    fill_ip_hdr_checksum(buf);
}

5. IP校驗和實現

校驗和函數式如何得出校驗和值的呢?看《TCP/IP協議詳解:卷1》里面咋說的吧。

        ”為了計算一份數據報的 IP檢驗和,首先把檢驗和字段置為 0。然后,對首部中每個 16 bit進行二進制反碼求和(整個首部看成是由一串 16 bit的字組成) ,結果存在檢驗和字段中。當收到一份I P數據報后,同樣對首部中每個16 bit進行二進制反碼的求和。由于接收方在計算過程中包含了發送方存在首部中的檢驗和,因此,如果首部在傳輸過程中沒有發生任何差錯,那么接收方計算的結果應該為全 1。如果結果不是全1(即檢驗和錯誤) ,那么I P就丟棄收到的數據報。但是不生成差錯報文,由上層去發現丟失的數據報并進行重傳。

        ICMP、IGMP、UDP和TCP都采用相同的檢驗和算法,盡管TCP和UDP除了本身的首部和數據外,在IP首部中還包含不同的字段。在RFC 1071[Braden, Borman and Patridge 1988]中有關于如何計算Internet檢驗和的實現技術。由于路由器經常只修改 TTL段(減1) ,因此當路由器轉發一份報文時可以增加它的檢驗和,而不需要對 IP整個首部進行重新計算。 RFC1141[Mallory and Kullberg 1990]為此給出了一個很有效的方法。“

        但是本協議棧的實現順序上與以上說的略有不同,《TCP/IP協議詳解:卷1》是先反碼再求和,本協議棧里面是先求和再反碼,當然都是按照16bit單位的單元來的。那結果一樣么?

比如:

11101010 01010100

10000000 11111110

先反碼再求和:

取反

00010101 10101011

01111111 00000001

求和

10010100 10101100

先求和再反碼:

求和

1 01101011 01010010

將進位加置最后來保持16位(下面的代碼如是說)

01101011 01010011

取反

10010100 10101100

沒錯,不完全驗證兩種方法的結果是一致的,不是科班出身,感覺上有啥子理論來說明某種順序的調換在對二進制運算結果方面的影響是無關的。

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45


unsigned  int checksum(unsigned char * buf, unsigned  int len,unsigned char  type)
{
    // type 0=ip 
    //      1=udp
    //      2=tcp
    unsigned long sum = 0;
    
    //if(type==0){
    //        // do not add anything
    //}
    if(type==1)
    {
        sum+=IP_PROTO_UDP_V; // protocol udp
        // the length here is the length of udp (data+header len)
        // =length given to this function - (IP.scr+IP.dst length)
        sum+=len-8; // = real tcp len
    }
    if(type==2)
    {
        sum+=IP_PROTO_TCP_V; 
        // the length here is the length of tcp (data+header len)
        // =length given to this function - (IP.scr+IP.dst length)
        sum+=len-8; // = real tcp len
    }
    // build the sum of 16bit words
    while(len >1)
    {
        sum += 0xFFFF & (*buf<<8|*(buf+1));
        buf+=2;
        len-=2;
    }
    // if there is a byte left then add it (padded with zero)
    if (len)
    {
        sum += (0xFF & *buf)<<8;
    }
    // now calculate the sum over the bytes in the sum
    // until the result is only 16bit long
    while (sum>>16)
    {
        sum = (sum & 0xFFFF)+(sum >> 16);
    }
    // build 1's complement:
    return( (unsigned  int) sum ^ 0xFFFF);
}

------------------------------------------------------------------------------------------------------

6. ICMP簡介

注意:ICMP在TCP/IP分層上與IP屬于同一層,因此放在與IP一塊,但是ICMP是封裝在IP數據報里面的。


ICMP:Internet Control Messages Protocol, 網間控制報文協議


ICMP報文的格式如圖6 - 2所示。所有報文的前4個字節都是一樣的,但是剩下的其他字節則互不相同。下面我們將逐個介紹各種報文格式。類型字段可以有1 5個不同的值,以描述特定類型的 ICMP報文。某些ICMP報文還使用代碼字段的值來進一步描述不同的條件。

檢驗和字段覆蓋整個ICMP報文。使用的算法與I P首部檢驗和算法相同。ICMP的檢驗和是必需的。


7. ICMP宏定義及函數實現

雖然ICMP具有很多的子協議,但是其中最著名的要數ping程序,即ICMP回顯請求和應答報文。通過使用ping命令來判斷報文是否可以到達目標地址。ICMP的實現是一個逐步遵守規則的過程,即向固定的字節填充數據,其實本協議棧也就實現了這個ping。

“ping”這個名字源于聲納定位操作。 Ping程序由Mike Muuss編寫,目的是為了測試另一臺主機是否可達。該程序發送一份 ICMP回顯請求報文給主機,并等待返回 ICMP回顯應答。


當返回ICMP回顯應答時,要打印出序列號和TTL,并計算往返時間(TTL位于 IP首部中的生存時間字段)。

ICMP回顯應答需要做好兩步,第一步檢查IP首部中的協議類型是否為ICMP報文;第二,檢查ICMP首部中的ICMP類型是否為ICMP請求,如果是則生成ICMP回顯應答并通過以太網驅動芯片發送。為了便于調試,在接收到ICMP回顯請求時通過串口輸出發起方的IP地址,ping命令發起方的IP地址存在于IP首部中的源IP地址部分。

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


// ******* ICMP *******
//回顯應答
#define ICMP_TYPE_ECHOREPLY_V 0
//回顯請求
#define ICMP_TYPE_ECHOREQUEST_V 8
//ICMP類型
#define ICMP_TYPE_P 0x22
//ICMP首部校驗和
#define ICMP_CHECKSUM_P 0x24

void make_echo_reply_from_request(unsigned char * buf,unsigned  int len)
{
    make_eth(buf);
    make_ip(buf);

     //ICMP_DEBUG插入此處
    buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;   //回顯應答
    // we changed only the icmp.type field from request(=8) to reply(=0).
    // we can therefore easily correct the checksum:
    if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))
    {
        buf[ICMP_CHECKSUM_P+1]++;
    }
    buf[ICMP_CHECKSUM_P]+=0x08;
    //
    enc28j60PacketSend(len,buf);
}

8 ICMP實驗調試

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


void make_echo_reply_from_request(unsigned char * buf,unsigned  int len)
{
        int i=0;
    make_eth(buf);
    make_ip(buf);
        #ifdef ICMP_DEBUG
        printf("ping命令發起者的IP地址 : \r\n");
      while(i    {
            //注意這里是IP_SRC_P,不是ARP包了,因為包的類型變了
            printf("%d",buf[IP_SRC_P+i]);/*這里錯了,應該是IP_DST_P,why?看函數名,好了,看了串口的輸出才看出來的*/
            if(i!=sizeof(ipv4_addr)-1)
                printf(".");
            else
                printf("\r\n");
            i++;
        }
        i=0;
        #endif
    buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;   //回送應答
    // we changed only the icmp.type field from request(=8) to reply(=0).
    // we can therefore easily correct the checksum:
    if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))
    {
        buf[ICMP_CHECKSUM_P+1]++;
    }
    buf[ICMP_CHECKSUM_P]+=0x08;
    //
    enc28j60PacketSend(len,buf);
}

在程序的無線循環中,需要層層進行查詢。其實就是各種if語句來判定以太網幀的那些個標記為是不是所要找的類型。

1.查詢以太網中是否有數據,若無數據則返回。

2.保存源MAC地址,待返回時使用。

3.查詢是否為ARP報文并返回ARP報文

4.保存源IP地址,待返回時使用。

6.查詢是否為IP報文,若非IP報文返回。

5.查詢是否為ICMP報文并返回ICMP回顯應答。


這里可以修改fill_ip_hdr_checksum函數里面的ttl(time to live)值,來確定IP包的生存周期,就是經過幾個路由之后被丟棄掉。修改為以下的125。



如果按照注釋里面改正之后~~~



關鍵字:TCP  IP協議棧  IP  ICMP  STM32平臺 引用地址:分析TCP/IP協議棧代碼之IP & ICMP(STM32平臺)

上一篇:分析TCP/IP協議棧代碼之ARP(STM32平臺)
下一篇:分析TCP/IP協議棧代碼之TCP(STM32平臺)

推薦閱讀

  世強元件電商,RICHO(理光微電子)電源管理IC樣品申請活動,正在火熱進行中,點擊活動網站:?注冊成為世強元件電商VIP會員,即可參與活動。此次可以申請的樣品包括,R1524x?系列、RP130x?系列、RP170x?系列、R1513x?系列、R1517x?系列、R1245x系列、RP550x系列、R5110x?系列等,可以應用在汽車配件的電源、汽車音響設備、導航系統、車身控制、電...
現如今的移動PC行業,如同股市的多頭和空頭一樣,正站在十字路口。在業內看來,行業未來發展已然受到消費者需求的倒逼,其定位越來越朝著精準化方向發展——極端注重輕便的辦公本與極端注重性能的游戲本。但事實上,相比于辦公本的諸多局限性,游戲本的向下兼容性顯然更高。特別是在近兩三年來諸多3A大作面世后,游戲本的地位更是不斷凸顯。而隨著技術不斷...
在設備通信中,UART非常常見,也是最簡單的,但是,PC尤其是筆記本基本都舍棄了傳統的UART端口,只能使用usb轉UART的IC來做信號轉換,這樣效率低,而且還要針對IC安裝專門的驅動,非常不方便,而在有些特殊設備上,甚至驅動無法安裝,是否可以不安裝驅動與PC通信呢?當然可以!在USB盛行的今天,USB通信變得極其簡單,而在USB中有一個重要的通信標準,就是...
簡介:使用BRR和BSRR寄存器可以方便地快速地實現對端口某些特定位的操作,而不影響其它位的狀態。比如希望快速地對GPIOE的位7進行翻轉,則可以:GPIOE->BSRR = 0x80; // 置&#39;1&#39;GPIOE->BRR = 0x80; // 置&#39;0&#39;如果使用常規&#39;讀-改-寫&#39;的方法:GPIOE->ODR = GPIOE->ODR | 0x80; // 置&#39;1&#39;GPIOE->ODR = GPIOE->OD...

史海拾趣

小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 弋阳县| 通道| 沅陵县| 三江| 中西区| 达州市| 禹城市| 浦北县| 从化市| 于田县| 将乐县| 大名县| 通山县| 自治县| 嘉峪关市| 沈阳市| 海口市| 本溪| 镇平县| 登封市| 乃东县| 安达市| 文昌市| 广德县| 镇赉县| 台南县| 岳西县| 高要市| 泾阳县| 莱西市| 龙江县| 望都县| 驻马店市| 孝义市| 马鞍山市| 观塘区| 墨玉县| 阳东县| 商洛市| 满城县| 邛崃市|