1@page lwip lwip
2
3[更正文档](https://gitee.com/alios-things/lwip/edit/master/README.md)      [贡献说明](https://help.aliyun.com/document_detail/302301.html)
4
5# 概述
6LwIP(Light Weight Internet Protoco1)是瑞士计算机科学院(Swedish Institute of Computer Science)AdamDunkels等人开发的一套用于嵌入式系统的开放源代码TCP/IP协议栈。LWIP的含义是Light Weight(轻型)IP协议。LWIP可以移植到操作系统上,也可以在无操作系统的情况下独立运行。LWIP TCP/IP实现的重点是在保持TCP协议主要功能的基础上减少对RAM的占用。一般它只需要几十KB的RAM和40 KB左右的ROM就可以运行,这使LWIP协议栈适合在小型嵌入式系统中使用。
7官网:https://savannah.nongnu.org/projects/lwip/
8将LwIP协议栈分成四层:
91.应用层
102.传输层
113.网络层
124.网卡层
13本文将2,3,4统称为协议层
14应用层支持:
15arp, dhcpd, dns, httpd, ifconfig, iperf, lsfd, mdns, netbiosns, ping, sendfile, snmp, sntp, telnetd, tftp
16
17协议层支持:
18IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over
19    multiple network interfaces
20ICMP (Internet Control Message Protocol) for network maintenance and debugging
21IGMP (Internet Group Management Protocol) for multicast traffic management
22MLD (Multicast listener discovery for IPv6). Aims to be compliant with
23    RFC 2710. No support for MLDv2
24ND (Neighbor discovery and stateless address autoconfiguration for IPv6).
25    Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
26    (Address autoconfiguration)
27UDP (User Datagram Protocol) including experimental UDP-lite extensions
28TCP (Transmission Control Protocol) with congestion control, RTT estimation
29    and fast recovery/fast retransmit
30raw/native API for enhanced performance
31Optional Berkeley-like socket API
32DNS (Domain names resolver)
33
34## 版权信息
35> Apache license v2.0
36
37## 目录结构
38```tree
39├── api
40│   ├── api_lib.c  # 库
41│   ├── api_msg.c  # 消息机制
42│   ├── err.c      # 异常api
43│   ├── netbuf.c   # 网络缓存api
44│   ├── netdb.c    # dns实现
45│   ├── netifapi.c # 网卡api
46│   ├── sockets.c  # 套接字api
47│   └── tcpip.c    # tcpip任务实现
48├── apps           # LwIP 应用
49│   ├── arp        # arp应用
50│   ├── dhcpd      # dhcpd应用
51│   ├── dns        # dns应用
52│   ├── httpd      # httpd应用
53│   ├── ifconfig   # ifconfig应用
54│   ├── iperf      # iperf应用
55│   ├── lsfd       # lsfd应用
56│   ├── mdns       # mdns应用
57│   ├── netbiosns  # netbiosns应用
58│   ├── ping       # ping应用
59│   ├── sendfile   # sendfile应用
60│   ├── snmp       # snmp应用
61│   ├── sntp       # sntp应用
62│   ├── telnetd    # telnetd应用
63│   └── tftp       # tftp应用
64├── core           # LwIP协议栈核心模块,IPv4/IPv6/TCP/UDP等协议实现
65├── include        # 头文件
66├── netif          # 网卡锡相关
67└── port           # 移植对接
68```
69
70## 依赖组件
71
72# 常用配置
73系统中相关配置已有默认值,如需修改配置,统一在yaml中**def_config**节点修改,具体如下:
74> 使能TCPIP是1,不使能TCPIP是0,默认是1,可修改yaml配置如
75```yaml
76def_config:
77  CONFIG_TCPIP: 1
78```
79> 使用AOS的LwIP是1, 不实用AOS的LwIP是0,默认是1,可修改yaml配置如:
80```yaml
81def_config:
82  CONFIG_AOS_LWIP: 1
83```
84> 使能LwIP数据包打印功能是1, 不使能是0,默认1,可修改yaml配置如:
85```yaml
86def_config:
87  WITH_LWIP_PKTPRINT: 1
88```
89
90# API说明
91
92## 创建socket
93```C
94int socket(int domain, int type, int protocol);
95```
96
97|args                                    |description|
98|:-----                                  |:----|
99|domain                                  |协议域|
100|type                                    |类型|
101|protocol                                |传输协议|
102
103## 绑定地址端口
104```C
105int bind(int s, const struct sockaddr *addr, socklen_t namelen)
106```
107
108|args                                    |description|
109|:-----                                  |:----|
110|s                                       |要绑定的 socket描述符|
111|addr                                    |一个指向含有本机 IP 地址和端口号等信息的 sockaddr 结构的指针|
112|namelen                                 |sockaddr 结构的长度|
113
114## 将套接字设为监听模式,并在套接字指定的端口上开始监听,以便对到达的服务请求进行处理
115```C
116int listen(int s, int backlog)
117```
118
119|args                                    |description|
120|:-----                                  |:----|
121|s                                       |要绑定的 socket描述符|
122|backlog                                 |连接请求队列可以容纳的最大数目|
123
124## 从完全建立的连接的队列中接受一个连接
125```C
126int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
127```
128
129|args                                    |description|
130|:-----                                  |:----|
131|s                                       |socket描述符|
132|backlog                                 |连接请求队列可以容纳的最大数目|
133
134## 与服务器建立一个 TCP 连接
135```C
136int connect(int s, const struct sockaddr *name, socklen_t namelen)
137```
138
139|args                                    |description|
140|:-----                                  |:----|
141|s                                       |socket描述符|
142|name                                    |指向 sockaddr 结构的指针,存放要连接的服务器的 IP 地址和端口号等信息|
143|namelen                                 |sockaddr 结构体的长度|
144
145## 面向连接的数据流 socket 模式下发送数据
146```C
147int send(int s, const void *dataptr, size_t size, int flags)
148```
149
150|args                                    |description|
151|:-----                                  |:----|
152|s                                       |socket描述符|
153|dataptr                                 |指向所要发送的数据区的指针|
154|size                                    |要发送的字节数|
155|flags                                   |控制选项,通常为 0|
156
157## 面向连接的数据流 socket 模式下接收数据
158```C
159int recv(int s, void *mem, size_t len, int flags)
160```
161
162|args                                    |description|
163|:-----                                  |:----|
164|s                                       |socket描述符|
165|mem                                     |指向存储数据的内存缓存区的指针|
166|len                                     |缓冲区的长度|
167|flags                                   |控制选项,通常为 0|
168
169## 在无连接的数据报 socket 模式下发送数据
170```C
171int sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
172```
173
174|args                                    |description|
175|:-----                                  |:----|
176|s                                       |socket描述符|
177|size                                    |要发送的字节数|
178|flags                                   |控制选项,通常为 0|
179|to                                      |指向 sockaddr 结构体的指针,存放目的主机的 IP 和端口号|
180|tolen                                   |sockaddr 结构体的长度|
181
182## 在无连接的数据报 socket 模式下接收数据
183```C
184int recvfrom(int s, void*mem, size_t size, int flags, struct sockaddr *from, socklen_t *fromlen)
185```
186
187|args                                    |description|
188|:-----                                  |:----|
189|s                                       |socket描述符|
190|mem                                     |指向存储数据的内存缓存区的指针|
191|size                                    |缓冲区的长度|
192|flags                                   |控制选项,通常为 0|
193|from                                    |指向 sockaddr 结构体的指针,存放源主机的 IP 和端口号|
194|fromlen                                 |指向 sockaddr 结构体的长度的指针|
195
196## 查询一个或者多个socket的可读性、可写性及错误状态信息
197```C
198int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
199                struct timeval *timeout)
200```
201
202|args                                    |description|
203|:-----                                  |:----|
204|maxfdp1	                               |最大的文件描述符|
205|readset                                 |读文件描述符|
206|writeset                                |写文件描述符|
207|exceptset                               |异常的文件描述符|
208|timeout                                 |超时时间|
209
210## 传输完数据之后关闭 socket 并释放资源
211```C
212int closesocket(int s)
213```
214
215|args                                    |description|
216|:-----                                  |:----|
217|s                                       |socket 描述符|
218
219## 允许进行单向的关闭操作,或是全部禁止掉
220```C
221int shutdown(int s, int how)
222```
223
224|args                                    |description|
225|:-----                                  |:----|
226|s                                       |socket 描述符|
227|how                                     |控制选项|
228
229## 通过域名来获取主机的 IP 地址等信息
230```C
231struct hostent* gethostbyname(const char*name)
232```
233
234|args                                    |description|
235|:-----                                  |:----|
236|name	                                   |主机域名|
237
238## 获取本地主机的信息
239```C
240int getsockname(int s, struct sockaddr *name, socklen_t *namelen)
241```
242
243|args                                    |description|
244|:-----                                  |:----|
245|s	                                     |socket 描述符|
246|name	                                   |sockaddr 结构体指针,用来存储得到的主机信息|
247|namelen	                               |指向 sockaddr 结构体的长度的指针|
248
249## 得到与本地主机连接的远程主机的信息
250```C
251int getpeername(int s, struct sockaddr *name, socklen_t *namelen)
252```
253
254|args                                    |description|
255|:-----                                  |:----|
256|s	                                     |socket 描述符|
257|name	                                   |sockaddr 结构体指针,用来存储得到的主机信息|
258|namelen	                               |指向 sockaddr 结构体的长度的指针|
259
260## 设置套接字控制模式
261```C
262int ioctlsocket(int s, long cmd, void *argp)
263```
264
265|args                                    |description|
266|:-----                                  |:----|
267|s	                                     |socket 描述符|
268|cmd	                                   |套接字操作命令|
269|argp   	                               |操作命令所带参数|
270
271## 获取套接字控制模式
272```C
273int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
274```
275
276|args                                    |description|
277|:-----                                  |:----|
278|s	                                     |socket 描述符|
279|level	                                 |选项定义的层次;目前支持SOL_SOCKET, SOL_PACKET, IPPROTO_IP和IPPROTO_TCP|
280|optname	                               |需设置的选项|
281|optval	                                 |指向option属性的指针|
282|optlen	                                 |指向option属性长度的指针|
283
284## 设置套接字控制模式
285```C
286int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
287```
288
289|args                                    |description|
290|:-----                                  |:----|
291|s	                                     |socket 描述符|
292|level	                                 |选项定义的层次;目前支持SOL_SOCKET, SOL_PACKET, IPPROTO_IP和IPPROTO_TCP|
293|optname	                               |需设置的选项|
294|optval	                                 |指向option属性的指针|
295|optlen	                                 |option属性的长度|
296
297# 使用示例
298
299组件使用示例相关的代码下载、编译和固件烧录均依赖AliOS Things配套的开发工具,所以首先需要参考[《AliOS Things集成开发环境使用说明之搭建开发环境》](https://help.aliyun.com/document_detail/302378.html),下载安装。
300待开发环境搭建完成后,可以按照以下步骤进行示例的测试。
301
302## 步骤1 创建或打开工程
303
304**打开已有工程**
305
306如果用于测试的案例工程已存在,可参考[《AliOS Things集成开发环境使用说明之打开工程》](https://help.aliyun.com/document_detail/302381.html)打开已有工程。
307
308**创建新的工程**
309
310组件的示例代码可以通过编译链接到AliOS Things的任意案例(solution)来运行,这里选择helloworld_demo案例。helloworld_demo案例相关的源代码下载可参考[《AliOS Things集成开发环境使用说明之创建工程》](https://help.aliyun.com/document_detail/302379.html)311
312## 步骤2 添加组件
313
314案例下载完成后,需要在helloworld_demo组件的package.yaml中添加对组件的依赖:
315
316```yaml
317depends:
318  - netmgr:master     # 添加netmgr依赖,使用netmgr连接wifi
319  - lwip:master       # helloworld_demo中引入lwip组件
320```
321
322## 步骤3 下载组件
323
324在已安装了  的开发环境工具栏中,选择Terminal -> New Terminal启动终端,并且默认工作路径为当前工程的workspace,此时在终端命令行中输入:
325
326```shell
327
328aos install lwip
329
330```
331
332上述命令执行成功后,组件源码则被下载到了./components/lwip路径中。
333
334## 步骤4 添加示例
335
336在lwip组件的package.yaml中添加[example示例代码](https://gitee.com/alios-things/lwip/tree/master/example)337
338```yaml
339source_file:
340  - example/*.c
341```
342## 步骤5 编译固件
343
344在示例代码已经添加至组件的配置文件,并且helloworld_demo已添加了对该组件的依赖后,就可以编译helloworld_demo案例来生成固件了,具体编译方法可参考[《AliOS Things集成开发环境使用说明之编译固件》](https://help.aliyun.com/document_detail/302384.html)345
346## 步骤6 烧录固件
347
348helloworld_demo案例的固件生成后,可参考[《AliOS Things集成开发环境使用说明之烧录固件》](https://help.aliyun.com/document_detail/302383.html)来烧录固件。
349
350## 步骤7 打开串口
351
352固件烧录完成后,可以通过串口查看示例的运行结果,打开串口的具体方法可参考[《AliOS Things集成开发环境使用说明之查看日志》](https://help.aliyun.com/document_detail/302382.html)353
354当串口终端打开成功后,可在串口中输入help来查看已添加的测试命令。
355
356## 步骤8 测试示例
357
358> CLI命令行输入netmgr相关命令进行联网操作:
359```sh
360netmgr_example                           # 启动netmgr组件
361netmgr -t wifi -c wifissid wifipassword  # 输入ssid和密码
362```
363> CLI命令行输入udp 测试命令:
364```sh
365test_udp
366```
367**关键日志**
368> 输入联网命令后的WIFI联网成功日志:
369```sh
370Got IP
371```
372> 启动test_udp之后的数据接收打印:
373```sh
374test_udp
375
376(cli-uart)# hello world! count 15
377recv: hello UDP
378hello world! count 16
379recv: hello UDP
380hello world! count 17
381recv: hello UDP
382hello world! count 18
383recv: hello UDP
384hello world! count 19
385recv: hello UDP
386```
387# 注意事项
388* 使用lwip前,请先确定已经联网
389
390# 测试示例
391> CLI命令行输入ping测试命令
392```sh
393ping -c count(发包的数量) -i interval(发包的时间间隔ms) -s packetsize(指定发包的字节数) -w timeout(指定超时时间ms) destination(指定目标地址)
394```
395> CLI命令行输入查看设备网络接口的配置信息命令
396```sh
397ifconfig
398```
399> CLI命令行输入tftp向服务器获取文件命令
400```sh
401tftp server <start|stop>
402tftp get server_ip(服务器ip) server_port(服务器端口) server_src_path(服务器文件路径) device_dest_path(设备目标文件路径) file_type(文件类型)
403示例:tftp get 192.168.0.101 69 1.txt /data/1.txt text
404```
405> CLI命令行输入iperf测试网络性能
406```sh
407Iperf TCP Server: iperf -s
408Iperf UDP Server: iperf -s -u
409Iperf TCP Client: iperf -c ip(服务器ip地址) -w window size(TCP窗口大小) -t duration(传输时间,默认10s) -p port(服务器端口号)
410示例:iperf -c 192.168.0.101 -w 65535 -t 10 -p 5001
411Iperf UDP Client: iperf -c ip(目标ip地址) -u -l datagram size(数据包大小) -t duration(传输时间,默认10s) -p port(服务器端口号)
412示例:iperf -c 192.168.0.101 -u -l 1500 -t 10 -p 5001
413```
414**关键日志**
415> ping成功收到数据包日志
416```sh
417 LwIP_recv
418```
419> ifconfig成功查看设备网络接口的配置信息日志
420```sh
421 en1 up, address:192.168.0.102 gateway:192.168.0.1 netmask:255.255.255.0
422 lo0 up, address:127.0.0.1 gateway:127.0.0.1 netmask:255.0.0.0
423```
424> tftp成功获取文件日志
425```sh
426tftp received len:92 done
427```
428> iperf测试日志
429```sh
430TCP Server Bandwidth: 8 Mbits 716 Kbits 848 bits/sec
431UDP Server Bandwidth: 10 Mbits 60 Kbits 344 bits/sec
432TCP Client Bandwidth: 5 Mbits 1023 Kbits 928 bits/sec
433UDP Client Bandwidth: 22 Mbits 907 Kbits 160 bits/sec
434```
435# FAQ
436NA
437