lwip
概述
LwIP(Light Weight Internet Protoco1)是瑞士計算機科學院(Swedish Institute of Computer Science)AdamDunkels等人開發(fā)的一套用于嵌入式系統(tǒng)的開放源代碼TCP/IP協(xié)議棧。LWIP的含義是Light Weight(輕型)IP協(xié)議。LWIP可以移植到操作系統(tǒng)上,也可以在無操作系統(tǒng)的情況下獨立運行。LWIP TCP/IP實現(xiàn)的重點是在保持TCP協(xié)議主要功能的基礎上減少對RAM的占用。一般它只需要幾十KB的RAM和40 KB左右的ROM就可以運行,這使LWIP協(xié)議棧適合在小型嵌入式系統(tǒng)中使用。 官網(wǎng):https://savannah.nongnu.org/projects/lwip/將LwIP協(xié)議棧分成四層: 1.應用層 2.傳輸層 3.網(wǎng)絡層 4.網(wǎng)卡層 本文將2,3,4統(tǒng)稱為協(xié)議層 應用層支持: arp, dhcpd, dns, httpd, ifconfig, iperf, lsfd, mdns, netbiosns, ping, sendfile, snmp, sntp, telnetd, tftp
協(xié)議層支持: IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over multiple network interfaces ICMP (Internet Control Message Protocol) for network maintenance and debugging IGMP (Internet Group Management Protocol) for multicast traffic management MLD (Multicast listener discovery for IPv6). Aims to be compliant with RFC 2710. No support for MLDv2 ND (Neighbor discovery and stateless address autoconfiguration for IPv6). Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address autoconfiguration) UDP (User Datagram Protocol) including experimental UDP-lite extensions TCP (Transmission Control Protocol) with congestion control, RTT estimation and fast recovery/fast retransmit raw/native API for enhanced performance Optional Berkeley-like socket API DNS (Domain names resolver)
版權(quán)信息
Apache license v2.0
目錄結(jié)構(gòu)
├── api
│ ├── api_lib.c # 庫
│ ├── api_msg.c # 消息機制
│ ├── err.c # 異常api
│ ├── netbuf.c # 網(wǎng)絡緩存api
│ ├── netdb.c # dns實現(xiàn)
│ ├── netifapi.c # 網(wǎng)卡api
│ ├── sockets.c # 套接字api
│ └── tcpip.c # tcpip任務實現(xiàn)
├── apps # LwIP 應用
│ ├── arp # arp應用
│ ├── dhcpd # dhcpd應用
│ ├── dns # dns應用
│ ├── httpd # httpd應用
│ ├── ifconfig # ifconfig應用
│ ├── iperf # iperf應用
│ ├── lsfd # lsfd應用
│ ├── mdns # mdns應用
│ ├── netbiosns # netbiosns應用
│ ├── ping # ping應用
│ ├── sendfile # sendfile應用
│ ├── snmp # snmp應用
│ ├── sntp # sntp應用
│ ├── telnetd # telnetd應用
│ └── tftp # tftp應用
├── core # LwIP協(xié)議棧核心模塊,IPv4/IPv6/TCP/UDP等協(xié)議實現(xiàn)
├── include # 頭文件
├── netif # 網(wǎng)卡錫相關
└── port # 移植對接
依賴組件
無
常用配置
系統(tǒng)中相關配置已有默認值,如需修改配置,統(tǒng)一在YAML中def_config節(jié)點修改,具體如下:
使能TCPIP是1,不使能TCPIP是0,默認是1,可修改YAML配置如
def_config:
CONFIG_TCPIP: 1
使用AOS的LwIP是1, 不實用AOS的LwIP是0,默認是1,可修改YAML配置如:
def_config:
CONFIG_AOS_LWIP: 1
使能LwIP數(shù)據(jù)包打印功能是1, 不使能是0,默認1,可修改YAML配置如:
def_config:
WITH_LWIP_PKTPRINT: 1
API說明
創(chuàng)建socket
int socket(int domain, int type, int protocol);
args | description |
domain | 協(xié)議域 |
type | 類型 |
protocol | 傳輸協(xié)議 |
綁定地址端口
int bind(int s, const struct sockaddr *addr, socklen_t namelen)
args | description |
s | 要綁定的 socket描述符 |
addr | 一個指向含有本機 IP 地址和端口號等信息的 sockaddr 結(jié)構(gòu)的指針 |
namelen | sockaddr 結(jié)構(gòu)的長度 |
將套接字設為監(jiān)聽模式,并在套接字指定的端口上開始監(jiān)聽,以便對到達的服務請求進行處理
int listen(int s, int backlog)
args | description |
s | 要綁定的 socket描述符 |
backlog | 連接請求隊列可以容納的最大數(shù)目 |
從完全建立的連接的隊列中接受一個連接
int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
args | description |
s | socket描述符 |
backlog | 連接請求隊列可以容納的最大數(shù)目 |
與服務器建立一個 TCP 連接
int connect(int s, const struct sockaddr *name, socklen_t namelen)
args | description |
s | socket描述符 |
name | 指向 sockaddr 結(jié)構(gòu)的指針,存放要連接的服務器的 IP 地址和端口號等信息 |
namelen | sockaddr 結(jié)構(gòu)體的長度 |
面向連接的數(shù)據(jù)流 socket 模式下發(fā)送數(shù)據(jù)
int send(int s, const void *dataptr, size_t size, int flags)
args | description |
s | socket描述符 |
dataptr | 指向所要發(fā)送的數(shù)據(jù)區(qū)的指針 |
size | 要發(fā)送的字節(jié)數(shù) |
flags | 控制選項,通常為 0 |
面向連接的數(shù)據(jù)流 socket 模式下接收數(shù)據(jù)
int recv(int s, void *mem, size_t len, int flags)
args | description |
s | socket描述符 |
mem | 指向存儲數(shù)據(jù)的內(nèi)存緩存區(qū)的指針 |
len | 緩沖區(qū)的長度 |
flags | 控制選項,通常為 0 |
在無連接的數(shù)據(jù)報 socket 模式下發(fā)送數(shù)據(jù)
int sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
args | description |
s | socket描述符 |
size | 要發(fā)送的字節(jié)數(shù) |
flags | 控制選項,通常為 0 |
to | 指向 sockaddr 結(jié)構(gòu)體的指針,存放目的主機的 IP 和端口號 |
tolen | sockaddr 結(jié)構(gòu)體的長度 |
在無連接的數(shù)據(jù)報 socket 模式下接收數(shù)據(jù)
int recvfrom(int s, void*mem, size_t size, int flags, struct sockaddr *from, socklen_t *fromlen)
args | description |
s | socket描述符 |
mem | 指向存儲數(shù)據(jù)的內(nèi)存緩存區(qū)的指針 |
size | 緩沖區(qū)的長度 |
flags | 控制選項,通常為 0 |
from | 指向 sockaddr 結(jié)構(gòu)體的指針,存放源主機的 IP 和端口號 |
fromlen | 指向 sockaddr 結(jié)構(gòu)體的長度的指針 |
查詢一個或者多個socket的可讀性、可寫性及錯誤狀態(tài)信息
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
struct timeval *timeout)
args | description |
maxfdp1 | 最大的文件描述符 |
readset | 讀文件描述符 |
writeset | 寫文件描述符 |
exceptset | 異常的文件描述符 |
timeout | 超時時間 |
傳輸完數(shù)據(jù)之后關閉 socket 并釋放資源
int closesocket(int s)
args | description |
s | socket 描述符 |
允許進行單向的關閉操作,或是全部禁止掉
int shutdown(int s, int how)
args | description |
s | socket 描述符 |
how | 控制選項 |
通過域名來獲取主機的 IP 地址等信息
struct hostent* gethostbyname(const char*name)
args | description |
name | 主機域名 |
獲取本地主機的信息
int getsockname(int s, struct sockaddr *name, socklen_t *namelen)
args | description |
s | socket 描述符 |
name | sockaddr 結(jié)構(gòu)體指針,用來存儲得到的主機信息 |
namelen | 指向 sockaddr 結(jié)構(gòu)體的長度的指針 |
得到與本地主機連接的遠程主機的信息
int getpeername(int s, struct sockaddr *name, socklen_t *namelen)
args | description |
s | socket 描述符 |
name | sockaddr 結(jié)構(gòu)體指針,用來存儲得到的主機信息 |
namelen | 指向 sockaddr 結(jié)構(gòu)體的長度的指針 |
設置套接字控制模式
int ioctlsocket(int s, long cmd, void *argp)
args | description |
s | socket 描述符 |
cmd | 套接字操作命令 |
argp | 操作命令所帶參數(shù) |
獲取套接字控制模式
int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
args | description |
s | socket 描述符 |
level | 選項定義的層次;目前支持SOL_SOCKET, SOL_PACKET, IPPROTO_IP和IPPROTO_TCP |
optname | 需設置的選項 |
optval | 指向option屬性的指針 |
optlen | 指向option屬性長度的指針 |
設置套接字控制模式
int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
args | description |
s | socket 描述符 |
level | 選項定義的層次;目前支持SOL_SOCKET, SOL_PACKET, IPPROTO_IP和IPPROTO_TCP |
optname | 需設置的選項 |
optval | 指向option屬性的指針 |
optlen | option屬性的長度 |
使用示例
組件使用示例相關的代碼下載、編譯和固件燒錄均依賴AliOS Things配套的開發(fā)工具,所以首先需要參考《AliOS Things集成開發(fā)環(huán)境使用說明之搭建開發(fā)環(huán)境》,下載安裝。 待開發(fā)環(huán)境搭建完成后,可以按照以下步驟進行示例的測試。
步驟1 創(chuàng)建或打開工程
打開已有工程
如果用于測試的案例工程已存在,可參考《AliOS Things集成開發(fā)環(huán)境使用說明之打開工程》打開已有工程。
創(chuàng)建新的工程
組件的示例代碼可以通過編譯鏈接到AliOS Things的任意案例(solution)來運行,這里選擇helloworld_demo案例。helloworld_demo案例相關的源代碼下載可參考《AliOS Things集成開發(fā)環(huán)境使用說明之創(chuàng)建工程》。
步驟2 添加組件
案例下載完成后,需要在helloworld_demo組件的package.yaml中添加對組件的依賴:
depends:
- netmgr:dev_aos # 添加netmgr依賴,使用netmgr連接wifi
- lwip:dev_aos # helloworld_demo中引入lwip組件
步驟3 下載組件
在已安裝了的開發(fā)環(huán)境工具欄中,選擇Terminal -> New Terminal啟動終端,并且默認工作路徑為當前工程的workspace,此時在終端命令行中輸入:
aos install lwip
上述命令執(zhí)行成功后,組件源碼則被下載到了./components/lwip路徑中。
步驟5 編譯固件
在示例代碼已經(jīng)添加至組件的配置文件,并且helloworld_demo已添加了對該組件的依賴后,就可以編譯helloworld_demo案例來生成固件了,具體編譯方法可參考《AliOS Things集成開發(fā)環(huán)境使用說明之編譯固件》。
步驟6 燒錄固件
helloworld_demo案例的固件生成后,可參考《AliOS Things集成開發(fā)環(huán)境使用說明之燒錄固件》來燒錄固件。
步驟7 打開串口
固件燒錄完成后,可以通過串口查看示例的運行結(jié)果,打開串口的具體方法可參考《AliOS Things集成開發(fā)環(huán)境使用說明之查看日志》。
當串口終端打開成功后,可在串口中輸入help來查看已添加的測試命令。
步驟8 測試示例
CLI命令行輸入netmgr相關命令進行聯(lián)網(wǎng)操作:
netmgr_example # 啟動netmgr組件
netmgr -t wifi -c wifissid wifipassword # 輸入ssid和密碼
CLI命令行輸入udp 測試命令:
test_udp
關鍵日志
輸入聯(lián)網(wǎng)命令后的WIFI聯(lián)網(wǎng)成功日志:
Got IP
啟動test_udp之后的數(shù)據(jù)接收打印:
test_udp
(cli-uart)# hello world! count 15
recv: hello UDP
hello world! count 16
recv: hello UDP
hello world! count 17
recv: hello UDP
hello world! count 18
recv: hello UDP
hello world! count 19
recv: hello UDP
注意事項
使用lwip前,請先確定已經(jīng)聯(lián)網(wǎng)
測試示例
CLI命令行輸入ping測試命令
ping -c count(發(fā)包的數(shù)量) -i interval(發(fā)包的時間間隔ms) -s packetsize(指定發(fā)包的字節(jié)數(shù)) -w timeout(指定超時時間ms) destination(指定目標地址)
CLI命令行輸入查看設備網(wǎng)絡接口的配置信息命令
ifconfig
CLI命令行輸入tftp向服務器獲取文件命令
tftp server <start|stop>
tftp get server_ip(服務器ip) server_port(服務器端口) server_src_path(服務器文件路徑) device_dest_path(設備目標文件路徑) file_type(文件類型)
示例:tftp get 192.168.0.101 69 1.txt /data/1.txt text
CLI命令行輸入iperf測試網(wǎng)絡性能
Iperf TCP Server: iperf -s
Iperf UDP Server: iperf -s -u
Iperf TCP Client: iperf -c ip(服務器ip地址) -w window size(TCP窗口大小) -t duration(傳輸時間,默認10s) -p port(服務器端口號)
示例:iperf -c 192.168.0.101 -w 65535 -t 10 -p 5001
Iperf UDP Client: iperf -c ip(目標ip地址) -u -l datagram size(數(shù)據(jù)包大小) -t duration(傳輸時間,默認10s) -p port(服務器端口號)
示例:iperf -c 192.168.0.101 -u -l 1500 -t 10 -p 5001
關鍵日志
ping成功收到數(shù)據(jù)包日志
LwIP_recv
ifconfig成功查看設備網(wǎng)絡接口的配置信息日志
en1 up, address:192.168.0.102 gateway:192.168.0.1 netmask:255.255.255.0
lo0 up, address:127.0.0.1 gateway:127.0.0.1 netmask:255.0.0.0
tftp成功獲取文件日志
tftp received len:92 done
iperf測試日志
TCP Server Bandwidth: 8 Mbits 716 Kbits 848 bits/sec
UDP Server Bandwidth: 10 Mbits 60 Kbits 344 bits/sec
TCP Client Bandwidth: 5 Mbits 1023 Kbits 928 bits/sec
UDP Client Bandwidth: 22 Mbits 907 Kbits 160 bits/sec