• Home
Name Date Size #Lines LOC

..--

BUILD.gnD12-May-2024841 2319

README_zh.mdD12-May-20248.7 KiB279205

udp_test.cD12-May-20243.5 KiB11895

README_zh.md

1# Niobe407开发板UDP联网演示
2
3本案例程序将演示怎么在拓维Niobe407开发板上编写一个连接udp服务器的业务程序,实现开发板联网上报数据到服务器。
4
5## 简述
6UDP是用户数据包协议(UDP,User Datagram Protocol), 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 768 描述了 UDP。
7
8Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的是 TCP,该协议几乎做了所有的事情
9
10##  UDP客户端编程步骤
11  1、创建一个socket,用函数socket();
12  2、设置socket属性,用函数setsockopt();* 可选
13  3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
14  4、设置对方的IP地址和端口等属性;
15  5、循环接收/发送数据,用函数recvfrom()/sendto();
16  6、关闭网络连接;
17
18## 特点
191、UDP是无连接的,即发送数据之前不需要建立连接;
202、UDP使用尽最大努力交付,即不保证可靠交付;
213、UDP是面向报文的;
224、UDP支持一对一、一对多、多对一和多对多的交互通信等。
23
24## 结构体详解
25
26```
27struct sockaddr_in {
28	sa_family_t sin_family;
29	in_port_t sin_port;
30	struct in_addr sin_addr;
31	uint8_t sin_zero[8];
32};
33```
34
35**描述:**
36
37地址和端口信息
38
39**参数:**
40
41| 名字   | 描述      |
42| ------ | -------- |
43|sin_family|	指代协议族,在socket编程中只能是AF_INET|
44|sin_port|	存储端口号(使用网络字节顺序)|
45|sin_addr|	存储IP地址,使用in_addr这个数据结构|
46|sin_zero|	为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节|
47
48**示例代码如下:**
49
50```
51	struct sockaddr_in server_addr;
52	bzero(&server_addr,sizeof(server_addr)); // 初始化服务器地址
53	server_addr.sin_family = AF_INET;
54	server_addr.sin_port = htons(_PROT_);
55	//server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
56	inet_pton(AF_INET, _SERVER_IP_, &server_addr.sin_addr);
57	int sin_size = sizeof(struct sockaddr_in);
58```
59--------------------------------------------
60```
61struct sockaddr {
62	sa_family_t sa_family;
63	char sa_data[14];
64};
65```
66**描述:**
67
68通用的套接字地址,与sockaddr_in类似
69
70**参数**
71
72| 名字   | 描述      |
73| ------ | -------- |
74|sa_family|	地址族|
75|sa_data|14字节,包含套接字中的目标地址和端口信息 |
76
77------------------------------------
78
79## 函数详解
80
81### void udp_test_example(void)
82
83    调用此函数初始化ETH接口,并注册eth_enable_state_callBack回调函数
84
85    函数原型:
86
87        void tcp_client_example(void)
88        {
89            ethernet_enable(eth_enable_state_callBack); //有线网络使能
90        }
91
92
93### static void eth_enable_state_callBack(EthLinkState state)
94
95    此函数为ETH状态回调函数,在ETH初始化的时候被注册。
96
97    state:当前ETH连接状态
98
99    函数原型:
100
101        static void eth_enable_state_callBack(EthLinkState state)
102        {
103            static int net_init_finish = 0;
104            /* ETH连接断开*/
105            if(state == STATE_UPDATE_LINK_DOWN){
106                printf("ETH LINK STATE: DisConnected!\r\n");
107            }
108            /* ETH连接成功*/
109            else if(state == STATE_UPDATE_LINK_UP){
110                printf("ETH LINK STATE: Connected!\r\n");
111                if(net_init_finish == 0)
112                {
113                    osThreadAttr_t attr;
114                    attr.name = "udp_test";
115                    attr.attr_bits = 0U;
116                    attr.cb_mem = NULL;
117                    attr.cb_size = 0U;
118                    attr.stack_mem = NULL;
119                    attr.stack_size = 1024 * 4;
120                    attr.priority = 25;
121                    udp_test_id = osThreadNew((osThreadFunc_t)udp_test, NULL, &attr);
122                    if (udp_test_id == NULL)
123                    {
124                        printf("Failed to create udp_test thread!\n");
125                    }
126                    net_init_finish = 1;
127                }
128            }
129        }
130
131    函数实现功能: 当ETH连接状态发生改变时,回调此函数。
132
133    当state == STATE_UPDATE_LINK_UP时,表示连接成功,此时创建1个UDP线程, 且将net_init_finish = 1。 如此, 当ETH状态断开再连接时,将不会再次创建udp线程
134
135    当state == STATE_UPDATE_LINK_DOWN时,表示连接断开
136
137
138### void udp_test(void *arg)
139
140   此函数为UDP初始化函数
141
142   arg:线程传入参数,这里未使用
143
144   实现功能: 实现UDP数据接收后,原数据返回的功能
145
146   函数原型:
147
148        void udp_test(void *arg)
149        {
150            (void)arg;
151            ip_addr_t serverIP;
152            err_t err;
153            ipaddr_aton(DESTINATION_IP, &serverIP);//目标IP地址
154            upcb = udp_new();
155            if (upcb != NULL)
156            {
157                /* 配置本地端口 */
158                upcb->local_port = LOCAL_PORT;  //开发板端口
159
160                /* 配置目标IP和端口 */
161                err = udp_connect(upcb, &serverIP, DESTINATION_PORT);  //目标端口号
162                if (err == ERR_OK)
163                {
164                    /* 注册接收回调函数 */
165                    udp_recv(upcb, udp_receive_callback, NULL);
166                    printf("udp client connected\r\n");
167                }
168                else
169                {
170                    udp_remove(upcb);
171                    printf("can not connect udp pcb.\r\n");
172                }
173            }
174            while(!udp_rcv_flag)
175            {
176                printf("wait recv udp data...\n");
177                osDelay(1000);
178            }
179        }
180
181        其中:
182             LOCAL_PORT 表示本机端口号
183
184             DESTINATION_PORT 表示远端端口号
185
186             DESTINATION_IP: 表示远端IP地址
187
188### void udp_client_send(char *pData)
189
190    此函数为UDP数据发送函数
191
192    pData: 发送的数据缓冲区BUF地址
193
194
195### void udp_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
196
197    此函数为UDP数据接收回调函数,当UDP接收到数据时会回调此函数
198
199    arg: 函数入参,这里未使用
200
201    upcb: UDP句柄
202
203    p: 收到的数据
204
205    addr: 收到的IP地址
206
207    port: 收到的端口号
208
209    功能: 接收到数据,将数据信息打印出来。并且返回原样数据...
210
211    函数原型:
212
213        void udp_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
214        {
215            char *recdata = 0;
216            if(p != NULL)
217            {
218                recdata=(char *)malloc(p->len*sizeof(char)+1);
219                if(recdata != NULL)
220                {
221                    if(udp_rcv_flag != 1)
222                        udp_rcv_flag = 1;
223                    memcpy_s(recdata, p->len, p->payload, p->len);
224                    recdata[p->len] = '\0';
225                    printf("udp recv from[%d.%d.%d.%d:%d]: %s\n", *((uint8_t *)&addr->addr), *((uint8_t *)&addr->addr + 1),
226                                    *((uint8_t *)&addr->addr + 2), *((uint8_t *)&addr->addr + 3), port, recdata);
227                }
228                free(recdata);
229                udp_send(upcb, p);
230                /* Free receive pbuf */
231                pbuf_free(p);
232            }
233        }
234
235## 编译调试
236- 进入//kernel/liteos_m目录, 在menuconfig配置中进入如下选项:
237
238     `(Top) → Platform → Board Selection → select board niobe407 → use talkweb niobe407 application → niobe407 application choose`
239
240- 选择 `303_network_udptest`
241
242- 回到sdk根目录,执行`hb build -f`脚本进行编译。
243
244### 运行结果
245
246示例代码编译烧录代码后,按下开发板的RESET按键,使用电脑udp连接设备。
247
248电脑端udp发送消息:
249    "hello,this is device udp test!"
250
251设备端udp接收消息:
252
253    ETH Init Success!
254    ETH LINK STATE: Connected!
255    udp client connected
256    wait recv udp data...
257    wait recv udp data...
258    wait recv udp data...
259    wait recv udp data...
260    wait recv udp data...
261    wait recv udp data...
262    wait recv udp data...
263    wait recv udp data...
264    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
265
266    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
267
268    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
269
270    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
271
272    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
273
274    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
275
276    udp recv from[192.168.8.119:5678]: hello,this is device udp test!
277
278
279