1# 小凌派-RK2206开发板基础外设开发——wifi-udp通信 2 3本示例将演示如何在小凌派-RK2206开发板上使用wifi进行udp通信 4 5 6 7## WiFi ssid 和密码设置 8 9修改文件 ``device/soc/rockchip/rk2206/sdk_liteos/platform/network/config_network.c`` 中的SSID WiFi名称,PASSWORD WiFi密码 连接到与pc同一网络 10 11```c 12#define SSID "凌智电子" 13#define PASSWORD "88888888" 14``` 15 16确认main文件 ``device/soc/rockchip/rk2206/sdk_liteos/platform/main/main.c`` wifi功能已开启 17 18```c 19ExternalTaskConfigNetwork(); 20``` 21 22### 查看小凌派获取到的IP地址和网关 23 24图如下所示: 25 26 27### 确认pc与小凌派在同一局域网,查看PC的IP地址和网关 28 29在控制台输入 ``ipconfig`` 30图如下所示: 31 32网关都是 ``192.168.2.1``表示在同一局域网 33 34修改wifi_udp例程中 服务地址及端口号后重新编译烧录程序 35 36```c 37#define OC_SERVER_IP "192.168.2.49" //pc IP地址 此地址为上一步查询到的地址每个人的地址可能不一样需要根据自己的修改 38#define SERVER_PORT 6666 //端口号 39#define CLIENT_LOCAL_PORT 8888 40``` 41 42pc上打开两个网络调试工具一个客户端一个服务端,并设置IP地址和端口号 43 44 45用网络调试助手点击启动客户端和服务端 46 47 48查看log 等待小凌派的udp客户端和服务端任务启动 49 50 51修改网络调试工具字符集编码 52 53 54然后就可以通过网络调试工具与小凌派通信了 55 56 57## 程序设计 58 59### API分析 60 61#### 头文件 62 63```c 64#include "lz_hardware.h" 65#include "config_network.h" 66#include "lwip/tcp.h" 67#include "lwip/ip_addr.h" 68#include "lwip/priv/tcp_priv.h" 69#include "lwip/stats.h" 70#include "lwip/inet_chksum.h" 71``` 72 73#### socket() 74 75```c 76int socket(int domain, int type, int protocol); 77``` 78 79**描述:** 80 81创建套接字 82**参数:** 83 84| 名字 | 描述 | 85| :------- | :------------------------------------------------ | 86| domai | 协议类型,一般为AF_INET | 87| type | socket类型 | 88| protocol | 用来指定socket所使用的传输协议编号,通常设为0即可 | 89 90**返回值:** 91 92返回大于0为成功,反之为失败 93 94#### bind() 95 96```c 97int bind(int sockfd, struct sockaddr *my_addr, int addrlen); 98``` 99 100**描述:** 101 102绑定地址端口号 103 104**参数:** 105 106| 名字 | 描述 | 107| :------ | :----------------------------------------------------------- | 108| sockfd | socket描述符 | 109| my_addr | 是一个指向包含有本机ip地址和端口号等信息的sockaddr类型的指针 | 110| addrlen | 常被设为sizeof(struct sockaddr) | 111 112**返回值:** 113 114返回大于0为成功,反之为失败 115 116#### connect() 117 118```c 119int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 120``` 121 122**描述:** 123 124仅仅用于表示确定了另一方的地址 125 126**参数:** 127 128| 名字 | 描述 | 129| :-------- | :------------------------------- | 130| sockfd | 目的服务器的socket描述符 | 131| serv_addr | 包含目的机器ip地址和端口号的指针 | 132| addrlen | sizeof(struct sockaddr) | 133 134**返回值:** 135 136返回大于0为成功,反之为失败 137 138#### sendto() 139 140```c 141int sendto(int sockfd, const void *msg, int len, int flags, struct sockaddr * to int *tolen); 142``` 143 144**描述:** 145 146发送消息 147 148**参数:** 149 150| 名字 | 描述 | 151| :----- | :------------------------- | 152| sockfd | 用来传输数据的socket描述符 | 153| msg | 要发送数据的指针 | 154| len | 要发送的数据长度(字节) | 155| flags | 0 | 156| to | 目的socket描述符 | 157| tolen | 目的socket描述符长度 | 158 159**返回值:** 160 161发送成功返回发送字节数,失败返回值小于0 162 163#### recvfrom() 164 165```c 166int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr * from int *fromlen); 167``` 168 169**描述:** 170 171接收消息 172 173**参数:** 174 175| 名字 | 描述 | 176| :------ | :--------------------- | 177| sockfd | 接收数据的socket描述符 | 178| buf | 存放数据的缓冲区 | 179| len | 缓冲的长度(字节) | 180| flags | 0 | 181| from | 来自socket描述符 | 182| fromlen | 来自socket描述符长度 | 183 184**返回值:** 185 186接收成功返回大于0,失败返回值小于0 187 188#### lwip_close() 189 190```c 191int lwip_close(int sockfd); 192``` 193 194**描述:** 195 196关闭套接字 197 198**参数:** 199 200| 名字 | 描述 | 201| :----- | :------------- | 202| sockfd | 要关闭的套接字 | 203 204**返回值:** 205 206发送成功返回发送字节数,失败返回值小于0 207 208### 主要代码分析 209 210创建客户端任务 socket-->connect-->send-->recv-->lwip_close 211 212```c 213int wifi_udp_client(void) 214{ 215 int client_fd, ret; 216 struct sockaddr_in serv_addr, local_addr; 217 218 while(1) 219 { 220 client_fd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET:IPV4;SOCK_DGRAM:UDP 221 if (client_fd < 0) 222 { 223 printf("create socket fail!\n"); 224 return -1; 225 } 226 227 /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历TIME_WAIT的过程。*/ 228 int flag = 1; 229 ret = setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); 230 if (ret != 0) { 231 printf("[CommInitUdpServer]setsockopt fail, ret[%d]!\n", ret); 232 } 233 234 memset(&local_addr, 0, sizeof(local_addr)); 235 local_addr.sin_family = AF_INET; 236 local_addr.sin_addr.s_addr = wifiinfo.ipAddress; 237 local_addr.sin_port = htons(CLIENT_LOCAL_PORT); 238 //绑定本地ip端口号 239 ret = bind(client_fd, (struct sockaddr*)&local_addr, sizeof(local_addr)); 240 241 memset(&serv_addr, 0, sizeof(serv_addr)); 242 serv_addr.sin_family = AF_INET; 243 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 244 // serv_addr.sin_addr.s_addr = inet_addr(OC_SERVER_IP); //指定ip接收 245 serv_addr.sin_port = htons(SERVER_PORT); 246 247 udp_client_msg_handle(client_fd, (struct sockaddr*)&serv_addr); 248 249 LOS_Msleep(1000); 250 } 251 252 return 0; 253} 254``` 255 256连接服务端,并发送消息和接收消息 257 258```c 259void udp_client_msg_handle(int fd, struct sockaddr* dst) 260{ 261 socklen_t len = sizeof(*dst); 262 263 struct sockaddr_in client_addr; 264 int cnt = 0,count = 0; 265 printf("[udp client] remote addr:%s port:%u\n", inet_ntoa(((struct sockaddr_in*)dst)->sin_addr), ntohs(((struct sockaddr_in*)dst)->sin_port)); 266 connect(fd, dst, len); 267 getsockname(fd, (struct sockaddr*)&client_addr,&len); 268 printf("[udp client] local addr:%s port:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 269 270 while (1) 271 { 272 char buf[BUFF_LEN]; 273 printf("[udp client]------------------------------------------------\n"); 274 printf("[udp client] waitting server message!!!\n"); 275 // count = recv(fd, buf, BUFF_LEN, 0); //接收来自server的信息 276 count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&client_addr, &len); //recvfrom是阻塞函数,没有数据就一直阻塞 277 if(count == -1) 278 { 279 printf("[udp client] No server message!!!\n"); 280 } 281 else 282 { 283 printf("[udp client] remote addr:%s port:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 284 printf("[udp client] rev:%s\n", buf); 285 } 286 memset(buf, 0, BUFF_LEN); 287 sprintf(buf, "UDP TEST cilent send:%d", ++cnt); 288 // count = send(fd, buf, strlen(buf), 0); //发送数据给server 289 count = sendto(fd, buf, strlen(buf), 0, (struct sockaddr*)&client_addr, len); //发送信息给client 290 printf("[udp client] send:%s\n", buf); 291 printf("[udp client] client sendto msg to server %dbyte,waitting server respond msg!!!\n", count); 292 293 LOS_Msleep(100); 294 } 295 lwip_close(fd); 296} 297``` 298 299创建服务端任务 socket-->bind-->listen-->accept-->recv-->send-->close 300 301```c 302int wifi_udp_server(void) 303{ 304 int server_fd, ret; 305 306 while(1) 307 { 308 server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP 309 if (server_fd < 0) 310 { 311 printf("create socket fail!\n"); 312 return -1; 313 } 314 315 /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历TIME_WAIT的过程。*/ 316 int flag = 1; 317 ret = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); 318 if (ret != 0) { 319 printf("[CommInitUdpServer]setsockopt fail, ret[%d]!\n", ret); 320 } 321 322 struct sockaddr_in serv_addr = {0}; 323 serv_addr.sin_family = AF_INET; 324 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 325 // serv_addr.sin_addr.s_addr = wifiinfo.ipAddress; 326 serv_addr.sin_port = htons(SERVER_PORT); //端口号,需要网络序转换 327 /* 绑定服务器地址结构 */ 328 ret = bind(server_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 329 if (ret < 0) 330 { 331 printf("socket bind fail!\n"); 332 lwip_close(server_fd); 333 return -1; 334 } 335 printf("[udp server] local addr:%s,port:%u\n", inet_ntoa(wifiinfo.ipAddress), ntohs(serv_addr.sin_port)); 336 337 udp_server_msg_handle(server_fd); //处理接收到的数据 338 LOS_Msleep(1000); 339 } 340} 341``` 342 343连接客户端,并发送消息和接收消息 344 345```c 346void udp_server_msg_handle(int fd) 347{ 348 char buf[BUFF_LEN]; //接收缓冲区 349 socklen_t len; 350 int cnt = 0, count; 351 struct sockaddr_in client_addr = {0}; 352 while (1) 353 { 354 memset(buf, 0, BUFF_LEN); 355 len = sizeof(client_addr); 356 printf("[udp server]------------------------------------------------\n"); 357 printf("[udp server] waitting client msg\n"); 358 count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&client_addr, &len); //recvfrom是阻塞函数,没有数据就一直阻塞 359 if (count == -1) 360 { 361 printf("[udp server] recieve data fail!\n"); 362 LOS_Msleep(3000); 363 break; 364 } 365 printf("[udp server] remote addr:%s port:%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 366 printf("[udp server] rev client msg:%s\n", buf); 367 memset(buf, 0, BUFF_LEN); 368 sprintf(buf, "I have recieved %d bytes data! recieved cnt:%d", count, ++cnt); 369 printf("[udp server] send msg:%s\n", buf); 370 sendto(fd, buf, strlen(buf), 0, (struct sockaddr*)&client_addr, len); //发送信息给client 371 } 372 lwip_close(fd); 373} 374``` 375 376## 编译调试 377 378### 修改 BUILD.gn 文件 379 380修改 `vendor/lockzhiner/lingpi/sample` 路径下 BUILD.gn 文件,指定 `b8_wifi_udp` 参与编译。 381 382```r 383"b8_wifi_udp", 384``` 385 386在主目录下输入编译命令。 387 388```shell 389hb build -f 390``` 391 392### 运行结果 393 394示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,串口显示如下: 395 396```c 397[MAIN:D]Main: enter ... 398entering kernel init... 399hilog will init. 400[IOT:D]IotInit: start .... 401[MAIN:D]Main: LOS_Start ... 402Entering scheduler 403[config_network:D]rknetwork SetApModeOff start ... 404 405[config_network:D]rknetwork AP is inactive 406 407[config_network:D]rknetwork SetApModeOff end ... 408 409hiview init success.[FLASH:I]FlashInit: blockSize 4096, blockStart 0, blockEnd 8388608 410[config_network:D]rknetwork SetWifiModeOn 411 412wifi_udp_example start .... 413[config_network:D]rknetwork g_wificonfig.ssid 凌智电子 414 415[config_network:D]rknetwork g_wificonfig.psk 88888888 416 417[wifi_api:D]ip=192.168.2.10 gw=192.168.2.1 mask=255.255.255.0 418[wifi_api:D]HWADDR (10:dc:b6:90:00:00) 419[bcore_device:E]start bb ... 420[WIFI_DEVICE:E]GetLocalWifiIp: netif get fail 421 422[bcore_device:E]start bb done 423[wifi_api:D]netif setup ... 424[config_network:D]rknetwork EnableWifi done 425 426[config_network:D]rknetwork SetWifiScan after g_wificonfig.bssid: 427 428[wifi_api_internal:D]Connect to (SSID=凌智电子) 429[wifi_api_internal:D]derive psk ... 430[IOT:D]IotProcess: start .... 431[wifi_api_internal:D]derive psk done 432[wifi_api_internal:D]recovery process ... 433[wifi_api_internal:D]AP BSSID (30:5f:77:80:80:b0) 434[udp:D]rknetwork IP (192.168.2.48) 435[udp:D]network GW (192.168.2.1) 436[udp:D]network NETMASK (255.255.255.0) 437[WIFI_DEVICE:E]l o num:0 127.0.0.1 438[WIFI_DEVICE:E]w l num:1 192.168.2.48 439[udp:D]set network GW 440[udp:D]network GW (192.168.2.1) 441[udp:D]network NETMASK (255.255.255.0) 442[config_network:I]ConnectTo (凌智电子) done 443[config_network:D]rknetwork IP (192.168.2.48) 444[config_network:D]network GW (192.168.2.1) 445[config_network:D]network NETMASK (255.255.255.0) 446[WIFI_DEVICE:E]l o num:0 127.0.0.1 447[WIFI_DEVICE:E]w l num:1 192.168.2.48 448[config_network:D]set network GW 449[config_network:D]network GW (192.168.2.1) 450[config_network:D]network NETMASK (255.255.255.0) 451[udp client] remote addr:0.0.0.0 port:6666 452[udp client] local addr:192.168.2.48 port:8888 453[udp server] local addr:192.168.2.48,port:6666 454[udp client]------------------------------------------------ 455[udp server]------------------------------------------------ 456[udp client] waitting server message!!! 457[udp server] waitting client message!!! 458[udp client] remote addr:192.168.2.49 remote port:6666 459[udp client] rev:凌智电子udp连接客户端 460[udp client] send:UDP TEST cilent send:1 461[udp client] client sendto msg to server 22byte,waitting server respond msg!!! 462[udp client]------------------------------------------------ 463[udp client] waitting server message!!! 464[udp server] remote addr:192.168.2.49 port:8888 465[udp server] rev:凌智电子udp连接服务端 466[udp server] send:I have recieved 30 bytes data! recieved cnt:1 467[udp server]------------------------------------------------ 468[udp server] waitting client message!!! 469 470 471当log中出现以下信息表示小凌派的tcp客户端和服务端任务已启动 472```c 473[tcp client] connect:50<192.168.2.49:6666> 474[tcp server] listen:51<0.0.0.0:6666> 475``` 476 477此时用网络调试助手查看并收发消息。 478 479 480