onps堆疊的移植涉及幾個部分:1)系統配置及裁剪;2)基礎資料型別定義;3)RTOS適配層實作;4)撰寫網卡驅動并注冊網卡,本文作為onps堆疊移植的指導性檔案將給出一般性的移植說明及建議,具體的移植樣例工程及說明請移步碼云下載:
- 《onps網路協議堆疊移植及使用說明v1.0》
- 目標os為rt-thread的移植樣例工程(STM32F407VET6及STM32F103RCT6兩個平臺)
- 目標os為ucos-ii的移植樣例工程(硬體平臺同上)
關于onps堆疊的前世今生請移步上一篇博文《開源網路協議堆疊onps誕生記》,
1. onps堆疊的配置及裁剪
協議堆疊原始碼(碼云/github)port/include/port/sys_config.h檔案是協議堆疊的組態檔,它提供了一系列的配置宏用于裁剪、配置協議堆疊,我們可以根據目標系統的具體情況對協議堆疊進行裁剪,調整配置,以減少或增加對系統資源的占用率,組態檔主要涉及幾方面的內容:
1)打開或關閉某個功能模塊;
2)指定mmu(記憶體管理單元)管理的記憶體大小;
3)協議層相關配置項,如預設ttl值、路由表大小、arp快取表大小等;
onps堆疊在資料鏈路層支持兩種型別的網路介面:ethernet有線以太網路介面;ppp點對點撥號網路介面,用戶必須選擇其中至少一個介面:
#define SUPPORT_PPP 1 //* 是否支持ppp:1,支持;0,不支持
#define SUPPORT_ETHERNET 1 //* 是否支持ethernet:1,支持;0,不支持
注意,你的目標系統要么支持ppp,要么支持ethernet,要么二者都支持,不能兩個都選擇不支持,否則協議堆疊將無法正常作業,另外協議堆疊還提供了幾個常用的網路工具供用戶選擇使用,用戶可以根據具體應用情形選擇打開或關閉相關工具:
//* 網路工具配置項,0:不支持;1:支持,協議堆疊將編譯連接工具代碼到目標系統
//* ===============================================================================================
#define NETTOOLS_PING 1 //* ping工具,確定目標網路地址是否能到達
#define NETTOOLS_DNS_CLIENT 1 //* dns查詢客戶端,通過指定的dns服務器查詢請求域名對應的ip地址
#define NETTOOLS_SNTP 1 //* sntp客戶端,通過指定的ntp服務器進行網路校時
//* ===============================================================================================
考慮協議堆疊的目標系統可能無法提供pc下常見的檔案存盤系統,所以協議堆疊的除錯日志等資訊是通過標準輸出提供的:
#define SUPPORT_PRINTF 1 //* 是否支持呼叫printf()輸出相關除錯或系統資訊
#if SUPPORT_PRINTF
#define PRINTF_THREAD_MUTEX 1 //* 是否支持使用printf執行緒互斥鎖,確保不同執行緒的除錯輸出資訊不被互相干擾,值為1則支持互斥鎖
#define DEBUG_LEVEL 1 //* 共5個除錯級別:
//* 0 輸出協議堆疊底層嚴重錯誤
//* 1 輸出所有系統錯誤(包括0級錯誤)
//* 2 輸出協議堆疊重要的配置、運行資訊,同時包括0、1級資訊
//* 3 輸出網卡的原始通訊通訊報文(ppp為收發,ethnernet為發送),以及0、1、2級資訊
//* 4 輸出ethernet網卡接收的原始通訊報文,被協議堆疊丟棄的非法(校驗和錯誤、通訊鏈路不存在等原因)通訊報文,以及0、1、2、3級資訊(除ethernet發送的原始報文)
#endif
基本上所有單片機系統均會提供幾個串行口,我們只需選擇其中一個將其作為printf函式的標準輸出口,我們就可以使能協議堆疊支持日志輸出功能,通過printf()函式輸出的日志資訊對目標系統進行除錯,如果你的目標系統支持某個串口作為printf()函式的標準輸出口,建議將SUPPORT_PRINTF宏置1,打開協議堆疊的日志輸出功能,PRINTF_THREAD_MUTEX宏用于解決多執行緒環境下日志輸出的沖突問題,如果你的目標系統互斥資源夠用,建議打開該功能,否則你在標準輸出口看到的日志會出現亂序問題,
協議堆疊在很多情形下需要動態申請不同大小的記憶體以供接下來的邏輯處理程序使用,所以,為了最大限度地提高協議堆疊運行程序中的記憶體利用率并盡可能地減少記憶體碎片,我們還單獨設計了一個獨立的記憶體管理單元(mmu),考慮協議堆疊的目標系統為資源受限的單片機系統,這種系統的記憶體資源往往都是極度緊張的,因此我們提供了配置宏讓用戶決定分配多少位元組的記憶體空間給協議堆疊的mmu:
//* 記憶體管理單元(mmu)相關配置項,其直接影響協議堆疊能分配多少個socket給用戶使用
//* ===============================================================================================
#define BUDDY_PAGE_SIZE 32 //* 系統能夠分配的最小頁面大小,其值必須是2的整數次冪
#define BUDDY_ARER_COUNT 9 //* 指定buddy演算法管理的記憶體塊陣列單元數量
#define BUDDY_MEM_SIZE 8192 //* buddy演算法管理的記憶體總大小,其值由BUDDY_PAGE_SIZE、BUDDY_ARER_COUNT兩個宏計算得到:
//* 32 * (2 ^ (9 - 1)),即BUDDY_MEM_SIZE = BUDDY_PAGE_SIZE * (2 ^ (BUDDY_ARER_COUNT - 1))
//* 之所以在此定義好要管理的記憶體大小,原因是buddy管理的記憶體其實就是一塊提前分配好的靜態存盤時期的位元組型
//* 一維陣列,以此來確保協議堆疊不占用寶貴的堆空間
//* ===============================================================================================
協議堆疊的記憶體管理單元采用了buddy伙伴演算法,上述三個宏的關系參見BUDDY_MEM_SIZE宏的注釋,前面說過,mmu管理的記憶體用于協議堆疊的不同業務情形,其中最核心的一種業務情形就是socket,用戶分配的記憶體大小直接決定了用戶撰寫網路應用時能夠申請的socket數量,如果你在申請分配一個新的socket時報ERRREQMEMTOOLARGE(The requested memory is too large, please refer to the macro definition BUDDY_MEM_SIZE)或ERRNOFREEMEM(The mmu has no memory available)錯誤,則意味著記憶體已經不夠用了,需要你增加記憶體或者檢視你的代碼看是否存在未及時釋放的socket句柄,另外,決定記憶體利用效率的關鍵配置項是BUDDY_PAGE_SIZE宏,因為mmu分配記憶體的最小單位就是“頁”,這個宏設定單個記憶體頁的大小,單位為位元組,其值必須是2的整數次冪,如果你的通訊報文不大,建議把頁面大小調整的小一些,比如16位元組、32位元組等,以盡量減少單個頁面的空余位元組數,
sys_config.h檔案的其余宏均為協議層相關的配置項,這其中有幾個與底層網路介面相關的配置項需要特別關注:
#define SUPPORT_PPP 1 //* 是否支持ppp模塊:1,支持;0,不支持,如果選擇支持,則系統會將ppp模塊代碼加入到協議堆疊中
#if SUPPORT_PPP
#define APN_DEFAULT "4gnet" //* 根據實際情況在這里設定預設APN
#define AUTH_USER_DEFAULT "card" //* ppp認證預設用戶名
#define AUTH_PASSWORD_DEFAULT "any_char" //* ppp認證預設口令
#define PPP_NETLINK_NUM 1 //* 協議堆疊加載幾路ppp鏈路(系統存在幾個modem這里就指定幾就行)
#define SUPPORT_ECHO 1 //* 對端是否支持echo鏈路探測
#define WAIT_ACK_TIMEOUT_NUM 5 //* 在這里指定連續幾次接收不到對端的應答報文就進入協議堆疊故障處理流程(STACKFAULT),這意味著當前鏈路已經因嚴重故障終止了
#else
#define PPP_NETLINK_NUM 0
#endif
#define SUPPORT_ETHERNET 1 //* 是否支持ethernet:1,支持;0,不支持
#if SUPPORT_ETHERNET
#define ETHERNET_NUM 1 //* 要添加幾個ethernet網卡(實際存在幾個就添加幾個)
#define ARPENTRY_NUM 32 //* arp條目快取表的大小,只要不小于局域網內目標通訊節點的個數即可確保arp尋址次數為1,否則就會出現頻繁尋址的可能,當然這也不會妨礙正常通訊邏輯,只不過這會降低通訊效率
#else
#define ETHERNET_NUM 0
#endif
如果目標系統需要用到ppp撥號,我們在打開協議堆疊對ppp模塊的支持后還需要設定預設的撥號引數值,比如apn、撥號賬號及密碼等,當然你也可以不用設定,后面我們在撰寫os適配層介面的時候也會設定這幾項,系統會使用os適配層的設定值代替預設值,另外協議堆疊在設計之初即考慮支持多路ppp同時撥號的情形,目標系統支持幾路ppp,宏PPP_NETLINK_NUM值置幾即可,SUPPORT_ECHO宏指定ppp鏈路是否啟用echo回顯探測功能,某些ppp接入服務商可能會關閉此項功能,如果你不確定,建議預設情況下關閉此功能,因為echo鏈路探測功能一旦被啟用,協議堆疊會每隔一小段時間發送探測報文到對端,對端如果不支持此功能會丟棄該探測報文不做任何回應,這將導致協議堆疊判定ppp鏈路故障,從而主動結束鏈路、重新撥號,
協議堆疊同樣支持多路ethernet網卡,ETHERNET_NUM宏用于指定目標系統存在幾路ethernet網卡,這里需要特別注意的是ARPENTRY_NUM宏,這個宏用于指定ethernet網路環境下進行通訊時mac地址快取表的大小,如果快取表過小,進行通訊的目標地址并不在快取表中時,協議堆疊會先發送arp查詢報文,得到對端的mac地址后才會發送實際的通訊報文,雖然這一切都是協議堆疊自動進行的,但通訊效率會受到影響,如果目標系統的記憶體夠用,建議放大快取表的容量,最合理的大小是等于計劃通訊的目標地址的數量,
其余協議層相關的配置項均屬于ip及其支持的上層協議:
//* ip支持的上層協議相關配置項
//* ===============================================================================================
#define SUPPORT_IPV6 0 //* 是否支持IPv6:1,支持;0,不支持
#define SUPPORT_SACK 0 //* 系統是否支持sack項,sack項需要協議堆疊建立發送佇列,這個非常消耗記憶體,通用版本不支持該項
#define ICMPRCVBUF_SIZE_DEFAULT 128 //* icmp發送echo請求報文時指定的接識訓沖區的預設大小,注意,如果要發送較大的ping包就必須指定較大的接識訓沖區
#define TCPRCVBUF_SIZE_DEFAULT 2048 //* tcp層預設的接識訓沖區大小,大小應是2^n次冪才能最大限度不浪費budyy模塊分配的記憶體
#define TCPUDP_PORT_START 20000 //* TCP/UDP協議動態分配的起始埠號
#define TCP_WINDOW_SCALE 0 //* 視窗擴大因子預設值
#define TCP_CONN_TIMEOUT 30 //* 預設TCP連接超時時間
#define TCP_ACK_TIMEOUT 3 //* 預設TCP應答超時時間
#define TCP_MSL 15 //* 指定TCP鏈路TIMEWAIT態的最大關閉時長:2 * TCP_MSL,單位:秒
#define TCP_LINK_NUM_MAX 16 //* 系統支持最多建立多少路TCP鏈路(涵蓋所有TCP客戶端 + TCP服務器的并發連接數),超過這個數量將無法建立新的tcp鏈路
#if SUPPORT_ETHERNET
#define TCPSRV_BACKLOG_NUM_MAX 10 //* tcp服務器支持的最大請求佇列數量,任意時刻所有已開啟的tcp服務器的請求連接佇列數量之和應小于該值,否則將會出現拒絕連接的情況
#define TCPSRV_NUM_MAX 2 //* 系統能夠同時建立的tcp服務器數量
#define TCPSRV_RECV_QUEUE_NUM 64 //* tcp服務器接收佇列大小,所有已開啟的tcp服務器共享該佇列資源,如果單位時間內到達所有已開啟tcp服務器的報文數量較大,應將該值調大
#endif
#define UDP_LINK_NUM_MAX 4 //* 呼叫connect()函式連接對端udp服務器的最大數量(一旦呼叫connect()函式,收到的非服務器報文將被直接丟棄)
#define SOCKET_NUM_MAX 16 //* 系統支持的最大SOCKET數量,如實際應用中超過這個數量則會導致用戶層業務邏輯無法全部正常運行(icmp/tcp/udp業務均受此影響),其值應大于等于TCP_LINK_NUM_MAX值
#define IP_TTL_DEFAULT 64 //* 預設TTL值
#define ROUTE_ITEM_NUM 8 //* 系統路由表數量
//* ===============================================================================================
目前協議堆疊暫不支持ipv6也不支持tcp sack選項(后續版本會支持),所以SUPPORT_IPV6和SUPPORT_SACK兩個宏不要做任何改動,始終為0即可,ICMPRCVBUF_SIZE_DEFAULT宏與ping工具有關,如果你不想使用ping工具可以將這個值設小一些以節省記憶體,TCP_WINDOW_SCALE宏建議不要做任何調整,對于記憶體空間有限的單片機系統tcp視窗直接使用指定值即可,TCP_ACK_TIMEOUT宏用于指定tcp報文發送到對端后等待對端回饋tcp ack報文的超時時間,單位:秒,UDP_LINK_NUM_MAX宏決定了目標系統在使用udp通訊時,能夠建立的udp客戶端的最大數量,比如目標系統需要建立5個udp客戶端,由于UDP_LINK_NUM_MAX值為4,那么只有4個客戶端能正常呼叫connect()函式,第5個客戶端在呼叫connect()函式時會報ERRNOUDPLINKNODE(the udp link list is empty)錯誤,ROUTE_ITEM_NUM宏用于指定系統快取的路由條目數量,你可以根據實際網路情形調整這個值,但不能低于目標系統注冊的網卡數量,協議層相關的其它配置項請根據注釋自行依據實際情況進行調整即可,
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/527740.html
標籤:其他
上一篇:邏輯分析儀使用介紹
