九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
手把手教你手?jǐn)]通訊協(xié)議(二)-網(wǎng)絡(luò)的基礎(chǔ)

經(jīng)過上一篇的手把手教你手?jǐn)]通訊協(xié)議(一) S7協(xié)議解析 中,大家有沒有發(fā)現(xiàn)缺了很大一部分篇幅,而且也只講到了UDP的包頭;由于UDP是讓大家簡(jiǎn)單的看到以太網(wǎng)的工作方式,接下去我們通過開源的LwIP協(xié)議棧來好好了解以太網(wǎng)的真實(shí)工作方式,我將會(huì)在這一期結(jié)束的時(shí)候,給大家實(shí)現(xiàn)一個(gè)基于STM32的modbusTCP 主站的小demo。

第一節(jié):協(xié)議層簡(jiǎn)介

首先我們還是根據(jù)標(biāo)準(zhǔn)的TCP/IP協(xié)議棧來分析傳輸層和鏈路層的網(wǎng)絡(luò)是怎樣打包的;

首先我們先了解幾個(gè)基礎(chǔ)協(xié)議及網(wǎng)絡(luò)分層:

網(wǎng)絡(luò)接口層:定義數(shù)據(jù)幀(對(duì)電信號(hào)0/1進(jìn)行的特定分組)、確認(rèn)主機(jī)的物理地址(MAC地址),通過傳輸介質(zhì)在網(wǎng)絡(luò)上傳輸數(shù)據(jù)幀。網(wǎng)絡(luò)接口有不同的實(shí)現(xiàn)方式,比如可以通過有線或無線的方式收發(fā)數(shù)據(jù)幀,不同的實(shí)現(xiàn)方式意味著不同的幀結(jié)構(gòu)、傳輸速率等。

網(wǎng)絡(luò)層:定義網(wǎng)絡(luò)地址(IP地址)、區(qū)分網(wǎng)段、對(duì)于子網(wǎng)內(nèi)的數(shù)據(jù)包進(jìn)行MAC尋址、對(duì)于不同子網(wǎng)的數(shù)據(jù)包進(jìn)行路由,實(shí)現(xiàn)網(wǎng)絡(luò)中主機(jī)到主機(jī)的通信。主要有PPP協(xié)議、SLIP協(xié)議、ARP、ipv4等基礎(chǔ)協(xié)議。

傳輸層:定義端口(Port)、標(biāo)識(shí)應(yīng)用程序身份、實(shí)現(xiàn)端口到端口的通信,TCP協(xié)議可以保證數(shù)據(jù)傳輸?shù)目煽啃浴?/span>

應(yīng)用層:定義數(shù)據(jù)格式并按照對(duì)應(yīng)的格式解讀數(shù)據(jù)(下層傳送過來的是字節(jié)流,不能很好的被程序識(shí)別)。應(yīng)用層定義了各種各樣的協(xié)議來規(guī)范數(shù)據(jù)格式,常見的有 HTTP、FTP、SMTP 等。

第二節(jié):數(shù)據(jù)包及內(nèi)存存儲(chǔ)結(jié)構(gòu)

由上面的基礎(chǔ)知識(shí)、我們根據(jù)理論知識(shí),我們根據(jù)LwIP來進(jìn)行學(xué)習(xí)。其實(shí)其實(shí)網(wǎng)絡(luò)層級(jí)來說:TCP和UDP類似,但TCP需要實(shí)現(xiàn)可靠連接,網(wǎng)卡接收的數(shù)據(jù)包,有可能是成千上萬(wàn)字節(jié),也有可能是幾個(gè)字節(jié),所以我們需要對(duì)其數(shù)據(jù)進(jìn)行打包處理。

由于內(nèi)存分配問題可以談的很深、涉及到編譯原理、字節(jié)對(duì)齊這些,篇幅有限,不展開。反正主要是兩種方式、一種是鏈表、一種是內(nèi)存池方式,各種系統(tǒng)中也都會(huì)講到,我們主要從數(shù)據(jù)包開始說明:

struct pbuf { struct pbuf *next; void *payload; u16_t tot_len; u16_t len; u8_t type; u8_t flags; u16_t ref;};
typedef enum {  PBUF_RAM, /* pbuf data is stored in RAM */  PBUF_ROM, /* pbuf data is stored in ROM */  PBUF_REF, /* pbuf comes from the pbuf pool */  PBUF_POOL /* pbuf payload refers to RAM */} pbuf_type;

這兩個(gè)看上去是不是很熟悉,就是一個(gè)鏈表節(jié)點(diǎn)。分配完成后就是這樣:

組成鏈表后的形式大概是這樣的:

這個(gè)就是數(shù)據(jù)包在內(nèi)存中存儲(chǔ)的方式了。

第三節(jié):網(wǎng)絡(luò)接口

在 LWIP 中,是通過一個(gè)叫做 netif 的網(wǎng)絡(luò)結(jié)構(gòu)體來描述一個(gè)硬件網(wǎng)絡(luò)接口的。

struct netif { struct netif *next; // 指向下一個(gè) netif 結(jié)構(gòu)的指針 struct ip_addr ip_addr; // IP 地址相關(guān)配置 struct ip_addr netmask; struct ip_addr gw; err_t (* input)(struct pbuf *p, struct netif *inp); //調(diào)用這個(gè)函數(shù)可以從網(wǎng)卡上取得一個(gè) // 數(shù)據(jù)包 err_t (* output)(struct netif *netif, struct pbuf *p, // IP 層調(diào)用這個(gè)函數(shù)可以向網(wǎng)卡發(fā)送 struct ip_addr *ipaddr); // 一個(gè)數(shù)據(jù)包 err_t (* linkoutput)(struct netif *netif, struct pbuf *p); // ARP 模塊調(diào)用這個(gè)函數(shù)向網(wǎng) // 卡發(fā)送一個(gè)數(shù)據(jù)包 void *state; // 用戶可以獨(dú)立發(fā)揮該指針,用于指向用戶關(guān)心的網(wǎng)卡信息 u8_t hwaddr_len; // 硬件地址長(zhǎng)度,對(duì)于以太網(wǎng)就是 MAC 地址長(zhǎng)度,為 6 各字節(jié) u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; //MAC 地址 u16_t mtu; // 一次可以傳送的最大字節(jié)數(shù),對(duì)于以太網(wǎng)一般設(shè)為 1500 u8_t flags; // 網(wǎng)卡狀態(tài)信息標(biāo)志位 char name[2]; // 網(wǎng)絡(luò)接口使用的設(shè)備驅(qū)動(dòng)類型的種類 u8_t num; // 用來標(biāo)示使用同種驅(qū)動(dòng)類型的不同網(wǎng)絡(luò)接口 };

舉個(gè)例子來實(shí)現(xiàn)一張網(wǎng)卡的初始化:

static struct netif enc28j60;//聲明了一個(gè) netif 結(jié)構(gòu)的變量 enc28j60 struct ip_addr ipaddr, netmask, gw; //聲明了三個(gè)分別用于暫存 IP 地址、子網(wǎng)掩碼和網(wǎng)關(guān)地址的變量IP4_ADDR(&gw, 192,168,0,1); IP4_ADDR(&ipaddr, 192,168,0,60); IP4_ADDR(&netmask, 255,255,255,0); netif_init(); netif_add(&enc28j60, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input); netif_set_default(&enc28j60); netif_set_up(&enc28j60); err_t ethernetif_init(struct netif *netif) { netif->name[0] = IFNAME0; //初始化變量 enc28j60 的 name 字段 netif->name[1] = IFNAME1; // IFNAME 在文件外定義的,這里不必關(guān)心它的具體值  netif->output = etharp_output; //IP 層發(fā)送數(shù)據(jù)包函數(shù) netif->linkoutput = low_level_output; // //ARP 模塊發(fā)送數(shù)據(jù)包函數(shù) low_level_init(netif); //底層硬件初始化函數(shù) return ERR_OK; } static void low_level_init(struct netif *netif) { netif->hwaddr_len = ETHARP_HWADDR_LEN; //設(shè)置變量 enc28j60 的 hwaddr_len 字段 netif->hwaddr[0] = 'F'; //初始化變量 enc28j60 的 MAC 地址 netif->hwaddr[1] = 'O'; //設(shè)什么地址用戶自由發(fā)揮吧,但是不要與其他 netif->hwaddr[2] = 'R'; //網(wǎng)絡(luò)設(shè)備的 MAC 地址重復(fù)。 netif->hwaddr[3] = 'E'; netif->hwaddr[4] = 'S'; netif->hwaddr[5] = 'T'; netif->mtu = 1500; //最大允許傳輸單元 //允許該網(wǎng)卡廣播和 ARP 功能,并且該網(wǎng)卡允許有硬件鏈路連接 netif->flags = NETIF_FLAG_BROADCAST | \ NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; enc28j60_init(netif->hwaddr); //與底層驅(qū)動(dòng)硬件驅(qū)動(dòng)程序密切相關(guān)的硬件初始化函數(shù) } 

這里我們完成了初始化一張名為enc28j60 的網(wǎng)卡。

接下去是網(wǎng)卡的接收和發(fā)送主要通過low_level_input 和 low_level_output這兩個(gè)函數(shù)來實(shí)現(xiàn)。然后在操作系統(tǒng)中直接調(diào)用這兩個(gè)函數(shù)就行了。

以UC/OSII的網(wǎng)卡數(shù)據(jù)接收為例:

第一步創(chuàng)建線程:

OSTaskCreate(ethernetif_input,(void *)&enc28j60, &T_ETHERNETIF_INPUT_STK[T_ETHERNETIF_INPUT_STKSIZE-1] ETH_IF_TASK_PRIO);

第二步:數(shù)據(jù)包接收

void ethernetif_input(void *arg) //創(chuàng)建該進(jìn)程時(shí),要將某個(gè)網(wǎng)絡(luò)接口結(jié)構(gòu)的 netif 結(jié)構(gòu)指 { //針作為參數(shù)傳入 struct eth_hdr *ethhdr; struct pbuf *p; struct netif *netif = (struct netif *)arg; while (1) { p = low_level_input (netif); // 接收一個(gè)數(shù)據(jù)包 if (p == NULL) // 如果數(shù)據(jù)包為空, continue; // 則循環(huán)結(jié)束,啟動(dòng)下次接收過程 ethhdr = p->payload; // 取得數(shù)據(jù)包內(nèi)數(shù)據(jù) switch (htons(ethhdr->type)) // 判斷數(shù)據(jù)包類型 { // 只對(duì) IP 數(shù)據(jù)包和 ARP 數(shù)據(jù)包進(jìn)行處理 case ETHTYPE_IP: // IP 數(shù)據(jù)包 case ETHTYPE_ARP: // ARP 數(shù)據(jù)包 if (netif->input(p, netif)!=ERR_OK) // 將數(shù)據(jù)包發(fā)送到上層應(yīng)用函數(shù) { pbuf_free(p); p = NULL; } break; default: pbuf_free(p); p = NULL; break; } //switch } //while } //main 函數(shù) 

至此,數(shù)據(jù)包的接收可算大功告成 。

第四節(jié):網(wǎng)絡(luò)層

接下去我們要進(jìn)行網(wǎng)絡(luò)層協(xié)議的講解了:

(1) ARP:全稱 Address Resolution Protocol,譯作地址解析協(xié)議,是位于TCP/IP協(xié)議棧底層的協(xié)議。

ARP的協(xié)議包格式:

struct etharp_hdr { PACK_STRUCT_FIELD(struct eth_hdr ethhdr); // 14 字節(jié)的以太網(wǎng)數(shù)據(jù)報(bào)頭 PACK_STRUCT_FIELD(u16_t hwtype); // 2 字節(jié)的硬件類型 PACK_STRUCT_FIELD(u16_t proto); // 2 字節(jié)的協(xié)議類型 PACK_STRUCT_FIELD(u16_t _hwlen_protolen); // 兩個(gè) 1 字節(jié)的長(zhǎng)度字段 PACK_STRUCT_FIELD(u16_t opcode); // 2 字節(jié)的操作字段 op PACK_STRUCT_FIELD(struct eth_addr shwaddr); // 6 字節(jié)源 MAC 地址 PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); // 4 字節(jié)源 IP 地址 PACK_STRUCT_FIELD(struct eth_addr dhwaddr); // 6 字節(jié)目的 MAC 地址 PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); // 4 字節(jié)目的 IP 地址 } PACK_STRUCT_STRUCT;

我們可以把他轉(zhuǎn)化成這個(gè)結(jié)構(gòu)體。

接下去這個(gè)圖我們可以看到ARP的工作流程:

說白了就是兩個(gè)功能:通過ARP協(xié)議實(shí)現(xiàn)IP地址和MAC地址的映射,或者廣播獲取目標(biāo)MAC地址。

嘿嘿嘿,這里有人知道為啥撥號(hào)叫PPPOE么?或者說校園網(wǎng)、閃訊這些校園網(wǎng)絡(luò)是怎么進(jìn)行獨(dú)立收費(fèi)的么。理解了這一層的協(xié)議,可以做很多事情噢。

(2)IP協(xié)議

IP層其實(shí)在上一章節(jié)也有講到過。

最重要的是在網(wǎng)絡(luò)標(biāo)識(shí)那一標(biāo)識(shí)位置確認(rèn)了使用了什么協(xié)議。8位協(xié)議字段用來描述該IP數(shù)據(jù)包是來自于上層的哪個(gè)協(xié)議,如該值為1表示為ICMP協(xié)議,該值為2表示IGMP協(xié)議,該值為6表示TCP協(xié)議,該值為17表UDP協(xié)議。

前面我說們說到TCP包需要分包,接下去一個(gè)圖可以很清晰的解釋LwIP是怎么進(jìn)行分包的:

這一層的東西太多了,不展開。IP層的講解主要了解這些就夠了。

再說個(gè)大家感興趣東西:ping和tracert ,其實(shí)在連接過程中,就是用ICMP協(xié)議實(shí)現(xiàn)的,主要用來測(cè)試路徑和時(shí)間。其實(shí)第一次接觸hack也是從ICMP攻擊開始的。中美黑客大戰(zhàn),我也是拿了腳本,貢獻(xiàn)了一份力(ORZ)。

第五節(jié):傳輸層

接下去我們說說傳輸層:這一層的東西很多很多,偷懶了。

這里先補(bǔ)充一點(diǎn):在PLC還沒分配IP地址時(shí),我們是怎么找到設(shè)備并分配IP的?沒有IP地址是怎么發(fā)現(xiàn)PLC或模塊的地址的?

先以Rockwell的EtherNet/IP舉個(gè)例子,由于Rockwell的CIP協(xié)議大多數(shù)功能都是基于標(biāo)準(zhǔn)以太網(wǎng)協(xié)議實(shí)現(xiàn),所以可以很貼合現(xiàn)在這個(gè)系列。AB模塊可以通過一個(gè)叫BOOTP的工具進(jìn)行模塊的發(fā)現(xiàn)和IP地址分配,很好理解,AB的PLC是使用BOOTP協(xié)議進(jìn)行PLC或模塊的發(fā)現(xiàn)的。為什么我們現(xiàn)在挺少聽說BOOTP了呢?因?yàn)楝F(xiàn)在大家都在用DHCP的方式了Bootp其實(shí)是基于UDP協(xié)議進(jìn)行設(shè)備發(fā)現(xiàn)的。其實(shí)我們上下位機(jī)的通訊基本靠TCP協(xié)議,而下位機(jī)之間的通訊基本是基于UDP進(jìn)行通訊,UDP協(xié)議的本身協(xié)議特點(diǎn)可以實(shí)現(xiàn)模塊之間的高速通訊,更適合用于現(xiàn)場(chǎng)網(wǎng)絡(luò),本系列主要以與上位機(jī)通訊為主,所以減少UDP這一塊的解釋。

西門子的協(xié)議對(duì)這一層的協(xié)議進(jìn)行了一些修改,以下圖為例(來自西門子官網(wǎng))。這個(gè)下次再聊。

下級(jí)預(yù)告:本系列知識(shí)點(diǎn)的重點(diǎn)了:TCP的建立和斷開

TCP的全稱大家自行百度:主要功能是為上層提供一個(gè)可靠連接(雖然容易出線粘包問題)。

這里先給大家看一張圖(別的地方截取過來的):這是TCP連接的狀態(tài)轉(zhuǎn)化。

對(duì)這一期就先到這邊,TCP的內(nèi)容留在下一期。

結(jié)尾

總結(jié)一下

Summary

1、LwIP協(xié)議棧主要用于嵌入式系統(tǒng)的以太網(wǎng)協(xié)開發(fā)。該協(xié)議棧為很輕量級(jí)的以太網(wǎng)協(xié)議棧,通過該協(xié)議棧的學(xué)習(xí),可以很好的理解以太網(wǎng)是怎么工作的,采用該協(xié)議棧,我在很多項(xiàng)目中實(shí)現(xiàn)了MQTT、S7協(xié)議、ModbusTCP協(xié)議等工業(yè)協(xié)議的開發(fā),還有一些私有協(xié)議的開發(fā),很好的用于網(wǎng)絡(luò)中間件的開發(fā)。

2、講解了物理接口層、鏈路層、網(wǎng)絡(luò)層、傳輸層的部分協(xié)議實(shí)現(xiàn)和打包方式。講的比較簡(jiǎn)單,也是給大家一個(gè)可以參考的方向。

留兩個(gè)問題

問題1:IP數(shù)據(jù)包失序后怎么處理?

問題2:TCP發(fā)生粘包問題如何處理(或者說S7協(xié)議、CIP協(xié)議等是怎么處理粘包問題)?

2022年2月

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
LwIP網(wǎng)絡(luò)接口結(jié)構(gòu)體
LWIP UDP 協(xié)議分析
lwip之地址解析協(xié)議ARP
Lwip之IP/MAC地址沖突檢測(cè)
LwIP在stm32上的無操作系統(tǒng)移植
基于Aurix的以太網(wǎng)實(shí)踐:TCP Client實(shí)現(xiàn)坑點(diǎn)
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服