Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >鸿蒙之接收UDP消息

鸿蒙之接收UDP消息

作者头像
跋扈洋
发布于 2022-03-29 00:45:06
发布于 2022-03-29 00:45:06
1.5K00
代码可运行
举报
文章被收录于专栏:物联网知识物联网知识
运行总次数:0
代码可运行

开发环境

  1. VS Code
  2. HUAWEI DevEco Device Tool(HarmonyOS面向智能设备开发者提供的一站式集成开发环境)
  3. HiBurn(用于烧录)
  4. VMware
  5. Ubuntu(Linux系统)

使用的技术

UDP

Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。 Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的是 TCP,该协议几乎做了所有的事情。 UDP协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但即使在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。 方法 说明 Close 关闭 UDP 连接 Connect 建立与远程主机的连接 DropMulticastGroup 退出多路广播组 JoinMulticastGroup 将 UdpClient 添加到多路广播组 Receive 返回已由远程主机发送的 UDP 数据文报 Send 将 UDP 数据文报发送到远程主机

方法

说明

Close

关闭 UDP 连接

Connect

建立与远程主机的连接

DropMulticastGroup

退出多路广播组

JoinMulticastGroup

将 UdpClient 添加到多路广播组

Receive

返回已由远程主机发送的 UDP 数据文报

Send

将 UDP 数据文报发送到远程主机

JSON

JSON介绍

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

JSON 语法规则

JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名。 JSON是一个序列化的对象或数组。

  1. 六个构造字符: begin-array = ws %x5B ws ; [ 左方括号 begin-object = ws %x7B ws ; { 左大括号 end-array = ws %x5D ws ; ] 右方括号 end-object = ws %x7D ws ; } 右大括号 name-separator = ws %x3A ws ; : 冒号 value-separator = ws %x2C ws ; , 逗号
  2. 在这六个构造字符的前或后允许存在无意义的空白符(ws): ws = *(%x20 /; 空间 %x09 /; 水平标签 %x0A /; 换行或换行 %x0D); 回程
  3. JSON的值 JSON的构成: ws 值 ws [1] 值可以是对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个。值中的字面值中的英文必须使用小写。 对象由花括号括起来的逗号分割的成员构成,成员是字符串键和上文所述的值由逗号分割的键值对组成,如: 1

{“name”: “John Doe”, “age”: 18, “address”: {“country” : “china”, “zip-code”: “10000”}}

数组是由方括号括起来的一组值构成,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[3, 1, 4, 1, 5, 9, 2, 6]

字符串与C或者Java的字符串非常相似。字符串是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。 数字也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。 一些合法的JSON的实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{"a": 1, "b": [1, 2, 3]}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[1, 2, "3", {"a": 4}]
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
3.14
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"wulianwangzhishi"

具体设计

文件结构

先在./applications/sample/wifi-iot/app路径下新建一个目录(或一套目录结构),用于存放业务源码文件。 本例程:在app下新增业务led,其中hello_world.c为业务代码,BUILD.gn为编译脚本,具体规划目录结构如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
└── applications
    └── sample
        └── wifi-iot
            └── app
                │── led
                │  │── led.c
                │  └── BUILD.gn
                └── BUILD.gn

功能实现

新建./applications/sample/wifi-iot/app/led下的led.c文件,在led.c中新建业务入口函数led,并实现业务逻辑。并在代码最下方,使用HarmonyOS启动恢复模块接口SYS_RUN()启动业务。(SYS_RUN定义在ohos_init.h文件中)

BUILD.gn为编译脚本 led.c为业务逻辑代码所在文件

BUILD.gn(app/led/BUILD.gn)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static_library("bahuyang") {
    sources = [
        "led.c"
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/interfaces/kits/wifiiot_lite",
    ]
}
  1. “bahuyang”:是生成静态库名称,可随意更改
  2. “led.c”:代码文件

BUILD.gn(app\BUILD.gn)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        #"startup",
        "led:bahuyang"
    ]
}
  1. 将"startup"注释,运行我们自己的文件
  2. “led”:工程目录
  3. bahuyang:静态库文件

搭建的模块

  1. WiFi模块
  2. OLED显示屏
  3. 红绿黄三色交通灯

主要代码

sta联网

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define APP_INIT_VAP_NUM    2
#define APP_INIT_USR_NUM    2
volatile char start_wifi_connected_flg = 0;
static struct netif *g_lwip_netif = NULL;
void hi_sta_reset_addr(struct netif *pst_lwip_netif)
{
    ip4_addr_t st_gw;
    ip4_addr_t st_ipaddr;
    ip4_addr_t st_netmask;
    printf("%s %d \r\n", __FILE__, __LINE__);
    if (pst_lwip_netif == NULL) {
        printf("hisi_reset_addr::Null param of netdev\r\n");
        return;
    }
    IP4_ADDR(&st_gw, 0, 0, 0, 0);
    IP4_ADDR(&st_ipaddr, 0, 0, 0, 0);
    IP4_ADDR(&st_netmask, 0, 0, 0, 0);

    netifapi_netif_set_addr(pst_lwip_netif, &st_ipaddr, &st_netmask, &st_gw);
}

void wifi_wpa_event_cb(const hi_wifi_event *hisi_event)
{
    if (hisi_event == NULL)
        return;

    switch (hisi_event->event) {
        case HI_WIFI_EVT_SCAN_DONE:
            printf("WiFi: Scan results available\n");
            break;
        case HI_WIFI_EVT_CONNECTED:
            printf("WiFi: Connected\n");
            netifapi_dhcp_start(g_lwip_netif);

            start_wifi_connected_flg = 1;

            break;
        case HI_WIFI_EVT_DISCONNECTED:
            printf("WiFi: Disconnected\n");
            netifapi_dhcp_stop(g_lwip_netif);
            hi_sta_reset_addr(g_lwip_netif);
            break;
        case HI_WIFI_EVT_WPS_TIMEOUT:
            printf("WiFi: wps is timeout\n");
            break;
        default:
            break;
    }
}

int hi_wifi_start_connect(void)
{
    int ret;
    errno_t rc;
    hi_wifi_assoc_request assoc_req = {0};

    /* copy SSID to assoc_req */
    //热点名称
    rc = memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, "BAHUYANG", 8); /* 9:ssid length */
    if (rc != EOK) {
        printf("%s %d \r\n", __FILE__, __LINE__);
        return -1;
    }

    /*
     * OPEN mode
     * for WPA2-PSK mode:
     * set assoc_req.auth as HI_WIFI_SECURITY_WPA2PSK,
     * then memcpy(assoc_req.key, "12345678", 8).
     */
    //热点加密方式
    assoc_req.auth = HI_WIFI_SECURITY_WPA2PSK;

    /* 热点密码 */
    memcpy(assoc_req.key, "123456789", 9);


    ret = hi_wifi_sta_connect(&assoc_req);
    if (ret != HISI_OK) {
        printf("%s %d \r\n", __FILE__, __LINE__);
        return -1;
    }
    printf("%s %d \r\n", __FILE__, __LINE__);
    return 0;
}

int hi_wifi_start_sta(void)
{
    int ret;
    char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};
    int len = sizeof(ifname);
    const unsigned char wifi_vap_res_num = APP_INIT_VAP_NUM;
    const unsigned char wifi_user_res_num = APP_INIT_USR_NUM;

    printf("%s %d \r\n", __FILE__, __LINE__);

    ret = hi_wifi_init(wifi_vap_res_num, wifi_user_res_num);
    if (ret != HISI_OK) {
        printf("%s %d \r\n", __FILE__, __LINE__);
        //return -1;
    }

    printf("%s %d \r\n", __FILE__, __LINE__);
    ret = hi_wifi_sta_start(ifname, &len);
    if (ret != HISI_OK) {
        printf("%s %d \r\n", __FILE__, __LINE__);
        return -1;
    }

    /* register call back function to receive wifi event, etc scan results event,
     * connected event, disconnected event.
     */
    ret = hi_wifi_register_event_callback(wifi_wpa_event_cb);
    if (ret != HISI_OK) {
        printf("register wifi event callback failed\n");
    }

    /* acquire netif for IP operation */
    g_lwip_netif = netifapi_netif_find(ifname);
    if (g_lwip_netif == NULL) {
        printf("%s: get netif failed\n", __FUNCTION__);
        return -1;
    }

    /* if received scan results, select one SSID to connect */
    ret = hi_wifi_start_connect();
    if (ret != 0) {
        printf("%s %d \r\n", __FILE__, __LINE__);
        return -1;
    }


    return 0;
}

void hi_wifi_stop_sta(void)
{
    int ret;

    ret = hi_wifi_sta_stop();
    if (ret != HISI_OK) {
        printf("failed to stop sta\n");
    }

    ret = hi_wifi_deinit();
    if (ret != HISI_OK) {
        printf("failed to deinit wifi\n");
    }

    g_lwip_netif = NULL;

    
}



void mqtt_test_thread(void * argv)
{

    argv = argv;

    hi_wifi_start_sta();

    while(start_wifi_connected_flg == 0)
    {
        usleep(300000);
    }

    sleep(3);
    LED_test();

}


void led_off(void)
{
    GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_9, 1);
}

void led_on(void)
{
    GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_9, 0);
}


void StaExampleEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "wifi_config_thread";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 4096;
    attr.priority = 36;

    if (osThreadNew((osThreadFunc_t)mqtt_test_thread, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
}

SYS_RUN(StaExampleEntry);

接收UDP数据

程序流程如下:

  1. 创建一个UDP socket句柄,以及一个变量toAd的人,并设置服务器的IP地址和端口号
  2. 使用sendto()函数向服务器发送数据
  3. 使用recvfrom()函数从服务器接受消息
  4. 使用close()函数关闭此socket
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
char recvline[1024];
void udp_thread(void *pdata)
{
    int ret;
    struct sockaddr_in servaddr;
    cJSON *recvjson;
    pdata = pdata;
    int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
    //服务器 ip port
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(50001);
    printf("udp_thread \r\n");
    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    while(1)
    {
        struct sockaddr_in addrClient;
        int sizeClientAddr = sizeof(struct sockaddr_in);
        memset(recvline, sizeof(recvline), 0);
        ret = recvfrom(sockfd, recvline, 1024, 0, (struct sockaddr*)&addrClient,(socklen_t*)&sizeClientAddr);
        if(ret>0)
        {
            char *pClientIP =inet_ntoa(addrClient.sin_addr);
            printf("%s-%d(%d) says:%s\n",pClientIP,ntohs(addrClient.sin_port),addrClient.sin_port, recvline);
            //进行json解析
            recvjson = cJSON_Parse(recvline);
            if(recvjson != NULL)
            {
                if(cJSON_GetObjectItem(recvjson, "cmd")->valuestring != NULL)
                {
                    printf("cmd : %s\r\n", cJSON_GetObjectItem(recvjson, "cmd")->valuestring);
                    if(strcmp("RED", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        set_LED_status(LED_STATUS_RED);
                        printf("RED\r\n");
                    }
                    if(strcmp("YELLOW", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        set_LED_status(LED_STATUS_YELLOW);
                        printf("YELLOW\r\n");
                    }
                    if(strcmp("GREEN", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        set_LED_status(LED_STATUS_GREEN);
                        printf("GREEN\r\n");
                    }
                    if(strcmp("CLOSE", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0)
                    {
                        set_LED_status(LED_STATUS_CLOSE);
                        printf("CLOSE\r\n");
                    }
                }             
                cJSON_Delete(recvjson);
            }
    }
    }
}
void start_udp_thread(void)
{
    osThreadAttr_t attr;
    attr.name = "wifi_config_thread";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 2048;
    attr.priority = 36;
    if (osThreadNew((osThreadFunc_t)udp_thread, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 物联网知识 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python函数装饰器基础知识
函数装饰器是Python语言最优秀的设计之一,它以非常简洁的方式增强了函数的行为,让崎岖不平之路变得平坦顺畅。
dongfanger
2022/05/09
2730
Python函数装饰器基础知识
看完这篇文章还会不懂Python装饰器?掐死小编吧
1. 必备 #### 第一波 #### def foo(): print('foo') foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print('foo') foo = lambda x: x + 1 foo(1) # 执行下面的lambda表达式,而不再是原来的foo函数,因为函数 foo 被重新定义了 2. 需求来了 初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、r
崔庆才
2018/06/25
6080
理解Python 装饰器
装饰器应该是我学习Python时,第一个遇到的难题,当时看了很多教程,最终理解并在工作中使用,是stackoverflow这篇文章:stackoverflow装饰器
用户7886150
2020/12/19
3450
python基础-装饰器笔记
函数装饰器用于在源码中“标记”函数,以某种方式增加函数的行为。这是一项强大的功能,但是若想要掌握,必须理解闭包。
zx钟
2019/07/19
5650
Python 函数装饰器和闭包
创建一个装饰器工厂函数,把参数传给它,返回一个装饰器,然后再把它应用到要装饰的函数上。
为为为什么
2022/08/09
7200
Python 函数装饰器和闭包
【从零学习python 】32.装饰器的作用(一)
装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题。但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试问到了就挂了,因为装饰器是程序开发的基础知识,这个都不会,别跟人家说你会Python, 看了下面的文章,保证你学会装饰器。
全栈若城
2024/02/29
1270
Python 装饰器使用指南
装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二大特性是,装饰器在加载模块时立即执行。
goodspeed
2020/12/22
5490
Python 装饰器使用指南
深入了解Python中的装饰器
Python的装饰器是AOP编程的一种实现,其他很多语言也都支持装饰器模式。 注:AOP是指面向切面编程,详见 AOP概念
tunsuy
2022/10/27
3670
装饰器进阶
装饰带参数函数 def foo(func): # 接收的参数是一个函数名 def bar(x, y): # 这里需要定义和被装饰函数相同的参数 print("这里是新功能...") # 新功能 func(x, y) # 被装饰函数名和参数都有了,就能执行被装饰函数了 return bar # 定义一个需要两个参数的函数 @foo def f1(x, y): print("{}+{}={}".format(x, y, x+y)) # 调用
新人小试
2018/04/12
6240
python 装饰器
文章目录 1. 装饰器在导入的时候就会执行 2. functools.wraps 装饰器,保持 被装饰的函数的 `__name__` 的值不变 3. functools.lru_cache 实现备忘录 4. functools.singledispatch 处理多个不同的输入类型 5. 堆叠装饰器 6. 参数化装饰器 learn from 《流畅的python》 def deco(func): def inner(): print("running inner()") r
Michael阿明
2021/09/06
4340
开源图书《Python完全自学教程》7.3.4装饰器
函数 book() 是一个普通的函数,函数 p_decorate() 是嵌套函数,外层函数的参数 func 所引用的对象必须可执行,并且是 func(name) 形式,正好 book() 函数可以满足(其它满足要求的函数亦可,这里仅以 book() 为例)。根据对嵌套函数的理解,注释(17)得到了闭包,注释(18)执行写在 p_decorate() 函数里面的 wrapper() 函数对象。最后打印返回值。
老齐
2022/07/06
3940
一则小故事带你弄清Python装饰器
从上一文 深入浅出Python闭包 中,就知道函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过 函数名() 调用,如果 函数名 = xxx 被修改了,那么当在执行 函数名() 时,调用的就不知之前的那个函数了。
忆想不到的晖
2021/04/09
3150
一文读懂python装饰器由来(二)
上一篇文章主要以一步一步演进的方式介绍了装饰器的工作原理以及使用(没看的小伙伴可以关注一下 一文读懂Python装饰器由来(一)),其实只要认真学习上一篇文章,已经能够满足日常对装饰器的使用了。但是,若想真正理解装饰器,并进行更高阶的使用还要了解其他一些知识:
Python中文社区
2018/07/26
4730
流畅的 Python 第二版(GPT 重译)(五)
函数装饰器让我们在源代码中“标记”函数以增强其行为。这是强大的东西,但要掌握它需要理解闭包—当函数捕获在其体外定义的变量时,我们就得到了闭包。
ApacheCN_飞龙
2024/03/21
2340
流畅的 Python 第二版(GPT 重译)(五)
Python闭包、装饰器、语法糖
函数高级的用法,本文将使用案例来讲解Python闭包、装饰器、语法糖。 文章目录 函数高级 闭包 装饰器 语法糖 函数高级 我们前面已经学过了函数,我们知道当函数调用完,函数内定义的变量都销毁
北山啦
2022/10/31
2650
Python闭包、装饰器、语法糖
python——装饰器和语法糖效果
装饰器和闭包有很大的相关性,可以这么说,就是当外部函数后面的参数填入的是另一个函数的名称时(并且最多只能有一个参数),称之为装饰器,也可以说装饰器就是特殊的闭包。 可以用如下方法进行分析:
gzq大数据
2020/11/11
5890
Python入门之装饰器九步学习入门
第一步:最简单的函数,准备附加额外功能 '''示例1: 最简单的函数,表示调用了两次''' def myfunc(): print("myfunc() called.") myfunc() myfunc() 第二步:使用装饰函数在函数执行前和执行后分别附加额外功能 '''示例2: 替换函数(装饰) 装饰函数的参数是被装饰的函数对象,返回原函数对象 装饰的实质语句: myfunc = deco(myfunc)''' def deco(func): print("before myf
Jetpropelledsnake21
2018/05/03
5880
Python之@函数装饰器
装饰器的作用 —— 不想修改函数的调用方式 但是还想在原来的函数前后添加功能 原则: 开放封闭原则 开放 : 对扩展是开放的 封闭 : 对修改是封闭的
cuijianzhe
2022/06/14
4630
Python之@函数装饰器
python 中的装饰器及其原理
熟悉 Java 的程序员一定对 Java 中强大的注解有所了解,Python 在一定程度上受到了 Java 的影响,诞生了 Python 的装饰器特性。 Python 的装饰器是一个非常强大的功能,本文我们就来详细介绍一下 Python 的装饰器特性。 例如我们熟知的类静态方法在定义时就常常会使用 @staticmethod 与 @classmethod 装饰器:
用户3147702
2022/06/27
6460
python 中的装饰器及其原理
Python装饰器的详细解析
Python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。
用户8949263
2022/04/08
5970
相关推荐
Python函数装饰器基础知识
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验