Hi3861 OpenHarmony嵌入式应用入门--TCP Client

news2024/12/23 13:06:50

本篇使用的是lwip编写tcp客户端。需要提前准备好一个PARAM_HOTSPOT_SSID宏定义的热点,并且密码为PARAM_HOTSPOT_PSK。还需要准备一个tcp服务,服务ip为PARAM_SERVER_ADDR宏定义,端口为PARAM_SERVER_PORT宏定义。

修改网络参数

在Hi3861开发板上运行上述四个测试程序之前,需要根据你的无线路由、Linux系统IP修改 net_params.h文件的相关代码:

  • PARAM_HOTSPOT_SSID 修改为你的热点名称
  • PARAM_HOTSPOT_PSK 修改为你的热点密码;
  • PARAM_SERVER_ADDR 修改为你的服务器IP地址;
  • PARAM_SERVER_PORT 修改为你的服务器端口号;

LwIP Socket API编程tcp客户端主要步骤

创建Socket socket()

设置服务器地址和端口 sockaddr_in

连接到服务器 connect()

发送和接收数据 send() write() recv() read()

关闭Socket close()

代码编写

修改D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\BUILD.gn文件

# Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#    http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License. 

import("//build/lite/config/component/lite_component.gni")

lite_component("demo") {
  features = [
    #"base_00_helloworld:base_helloworld_example",
    #"base_01_led:base_led_example",
    #"base_02_loopkey:base_loopkey_example",
    #"base_03_irqkey:base_irqkey_example",
    #"base_04_adc:base_adc_example",
    #"base_05_pwm:base_pwm_example",
    #"base_06_ssd1306:base_ssd1306_example",
    #"kernel_01_task:kernel_task_example",
    #"kernel_02_timer:kernel_timer_example",
    #"kernel_03_event:kernel_event_example",
    #"kernel_04_mutex:kernel_mutex_example",
    #"kernel_05_semaphore_as_mutex:kernel_semaphore_as_mutex_example",
    #"kernel_06_semaphore_for_sync:kernel_semaphore_for_sync_example",
    #"kernel_07_semaphore_for_count:kernel_semaphore_for_count_example",
    #"kernel_08_message_queue:kernel_message_queue_example",
    #"wifi_09_hotspot:wifi_hotspot_example",
    #"wifi_10_sta:wifi_sta_example",
    #"tcp_11_server:tcp_server_example",
    "tcp_12_client:tcp_client_example",
  ]
}

创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\tcp_12_client文件夹

文件夹中创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\tcp_12_client\BUILD.gn文件

#Copyright (C) 2021 HiHope Open Source Organization .
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#
#limitations under the License.

static_library("tcp_client_example") {
    # uncomment one of following line, to enable one test:
    sources = ["tcp_client_example.c"]

    sources += ["wifi_connecter.c"]
    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/kal",
        "//foundation/communication/wifi_lite/interfaces/wifiservice",
    ]
}

添加了wifi_connecter.c文件的编译,这个文件中有链接wifi的函数。

文件夹中创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\tcp_12_client\net_common.h文件,文件主要引入一些头文件。

/*
 * Copyright (C) 2021 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */

#ifndef NET_COMMON_H
#define NET_COMMON_H

// __arm__ and __aarch64__ for HarmonyOS with liteos-a kernel
// __i386__ and __x86_64__ for Unix like OS
#if defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
#define HAVE_BSD_SOCKET 1
#else
#define HAVE_BSD_SOCKET 0
#endif

#if defined(__riscv) // for wifiiot(HarmonyOS on Hi3861 with liteos-m kernel)
#define HAVE_LWIP_SOCKET 1
#else
#define HAVE_LWIP_SOCKET 0
#endif

#if HAVE_BSD_SOCKET
#include <sys/types.h>  // for AF_INET SOCK_STREAM
#include <sys/socket.h> // for socket
#include <netinet/in.h> // for sockaddr_in
#include <arpa/inet.h> // for inet_pton
#elif HAVE_LWIP_SOCKET
#include "lwip/sockets.h"
#ifndef close
#define close(fd) lwip_close(fd)
#endif
#else
#error "Unknow platform!"
#endif

#endif  // NET_COMMON_H

文件夹中创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\tcp_12_client\wifi_connecter.h文件,该头文件包含wifi连接的宏。

/*
 * Copyright (C) 2021 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */

#ifndef WIFI_CONNECTER_H
#define WIFI_CONNECTER_H

#include "wifi_device.h"

#ifndef PARAM_HOTSPOT_SSID
#define PARAM_HOTSPOT_SSID "HarmonyOS"   // your AP SSID
#endif

#ifndef PARAM_HOTSPOT_PSK
#define PARAM_HOTSPOT_PSK  "1234567890"  // your AP PSK
#endif

#ifndef PARAM_HOTSPOT_TYPE
#define PARAM_HOTSPOT_TYPE WIFI_SEC_TYPE_PSK // defined in wifi_device_config.h
#endif

#ifndef PARAM_SERVER_ADDR
#define PARAM_SERVER_ADDR "192.168.137.1" // your PC IP address
#endif

#ifndef PARAM_SERVER_PORT
#define PARAM_SERVER_PORT 5678
#endif

int ConnectToHotspot(WifiDeviceConfig* apConfig);

void DisconnectWithHotspot(int netId);

#endif  // WIFI_CONNECTER_H

文件夹中创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\tcp_12_client\wifi_connecter.c文件,wifi连接的实现。

/*
 * Copyright (C) 2021 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */

#include "wifi_device.h"
#include "cmsis_os2.h"

#include "lwip/netifapi.h"
#include "lwip/api_shell.h"

#define IDX_0          0
#define IDX_1          1
#define IDX_2          2
#define IDX_3          3
#define IDX_4          4
#define IDX_5          5
#define DELAY_TICKS_10     (10)
#define DELAY_TICKS_100    (100)

static void PrintLinkedInfo(WifiLinkedInfo* info)
{
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[IDX_0], mac[IDX_1], mac[IDX_2], mac[IDX_3], mac[IDX_4], mac[IDX_5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}

static volatile int g_connected = 0;

static void OnWifiConnectionChanged(int state, WifiLinkedInfo* info)
{
    if (!info) return;

    printf("%s %d, state = %d, info = \r\n", __FUNCTION__, __LINE__, state);
    PrintLinkedInfo(info);

    if (state == WIFI_STATE_AVALIABLE) {
        g_connected = 1;
    } else {
        g_connected = 0;
    }
}

static void OnWifiScanStateChanged(int state, int size)
{
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);
}

static WifiEvent g_defaultWifiEventListener = {
    .OnWifiConnectionChanged = OnWifiConnectionChanged,
    .OnWifiScanStateChanged = OnWifiScanStateChanged
};

static struct netif* g_iface = NULL;

err_t netifapi_set_hostname(struct netif *netif, char *hostname, u8_t namelen);

int ConnectToHotspot(WifiDeviceConfig* apConfig)
{
    WifiErrorCode errCode;
    int netId = -1;

    errCode = RegisterWifiEvent(&g_defaultWifiEventListener);
    printf("RegisterWifiEvent: %d\r\n", errCode);

    errCode = EnableWifi();
    printf("EnableWifi: %d\r\n", errCode);

    errCode = AddDeviceConfig(apConfig, &netId);
    printf("AddDeviceConfig: %d\r\n", errCode);

    g_connected = 0;
    errCode = ConnectTo(netId);
    printf("ConnectTo(%d): %d\r\n", netId, errCode);

    while (!g_connected) { // wait until connect to AP
        osDelay(DELAY_TICKS_10);
    }
    printf("g_connected: %d\r\n", g_connected);

    g_iface = netifapi_netif_find("wlan0");
    if (g_iface) {
        err_t ret = 0;
        char* hostname = "rtplay";
        ret = netifapi_set_hostname(g_iface, hostname, strlen(hostname));
        printf("netifapi_set_hostname: %d\r\n", ret);

        ret = netifapi_dhcp_start(g_iface);
        printf("netifapi_dhcp_start: %d\r\n", ret);

        osDelay(DELAY_TICKS_100); // wait DHCP server give me IP
#if 1
        ret = netifapi_netif_common(g_iface, dhcp_clients_info_show, NULL);
        printf("netifapi_netif_common: %d\r\n", ret);
#else
        // 下面这种方式也可以打印 IP、网关、子网掩码信息
        ip4_addr_t ip = {0};
        ip4_addr_t netmask = {0};
        ip4_addr_t gw = {0};
        ret = netifapi_netif_get_addr(g_iface, &ip, &netmask, &gw);
        if (ret == ERR_OK) {
            printf("ip = %s\r\n", ip4addr_ntoa(&ip));
            printf("netmask = %s\r\n", ip4addr_ntoa(&netmask));
            printf("gw = %s\r\n", ip4addr_ntoa(&gw));
        }
        printf("netifapi_netif_get_addr: %d\r\n", ret);
#endif
    }
    return netId;
}

void DisconnectWithHotspot(int netId)
{
    if (g_iface) {
        err_t ret = netifapi_dhcp_stop(g_iface);
        printf("netifapi_dhcp_stop: %d\r\n", ret);
    }

    WifiErrorCode errCode = Disconnect(); // disconnect with your AP
    printf("Disconnect: %d\r\n", errCode);

    errCode = UnRegisterWifiEvent(&g_defaultWifiEventListener);
    printf("UnRegisterWifiEvent: %d\r\n", errCode);

    RemoveDevice(netId); // remove AP config
    printf("RemoveDevice: %d\r\n", errCode);

    errCode = DisableWifi();
    printf("DisableWifi: %d\r\n", errCode);
}

文件夹中创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\tcp_12_client\tcp_client_example.c文件

/*
 * Copyright (C) 2021 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */

#include <stdio.h>
// #include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"

#include "net_common.h"
#include "wifi_connecter.h"

static char request[] = "Hello";
static char response[128] = "";

#define DELAY_TICKS_10     (10)

void TcpClientTest(void)
{
    WifiDeviceConfig config = {0};

    // 准备AP的配置参数
    // strcpy(config.ssid, PARAM_HOTSPOT_SSID);
    // strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
    strcpy_s(config.ssid, WIFI_MAX_SSID_LEN, PARAM_HOTSPOT_SSID);
    strcpy_s(config.preSharedKey, WIFI_MAX_KEY_LEN, PARAM_HOTSPOT_PSK);
    config.securityType = PARAM_HOTSPOT_TYPE;

    osDelay(DELAY_TICKS_10);

    int netId = ConnectToHotspot(&config);

    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;    // AF_INET表示IPv4协议
    serverAddr.sin_port = htons(PARAM_SERVER_PORT);  // 端口号,从主机字节序转为网络字节序
    // 将主机IP地址从“点分十进制”字符串 转化为 标准格式(32位整数)
    if (inet_pton(AF_INET, PARAM_SERVER_ADDR, &serverAddr.sin_addr) <= 0) {
        printf("inet_pton failed!\r\n");
        goto do_cleanup;
    }

    // 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
        printf("connect failed!\r\n");
        goto do_cleanup;
    }
    printf("connect to server %s success!\r\n", PARAM_SERVER_ADDR);

    // 建立连接成功之后,这个TCP socket描述符 —— sockfd 就具有了 “连接状态”,
    // 发送、接收 对端都是 connect 参数指定的目标主机和端口
    retval = send(sockfd, request, sizeof(request), 0);
    if (retval < 0) {
        printf("send request failed!\r\n");
        goto do_cleanup;
    }
    printf("send request{%s} %ld to server done!\r\n", request, retval);

    retval = recv(sockfd, &response, sizeof(response), 0);
    if (retval <= 0) {
        printf("send response from server failed or done, %ld!\r\n", retval);
        goto do_cleanup;
    }
    response[retval] = '\0';
    printf("recv response{%s} %ld from server done!\r\n", response, retval);

do_cleanup:
    printf("do_cleanup...\r\n");
    close(sockfd);
    DisconnectWithHotspot(netId);
}

SYS_RUN(TcpClientTest);

使用build,编译成功后,使用upload进行烧录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1891382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[C++][设计模式][访问器]详细讲解

目录 1.动机2.模式定义3.要点总结4.代码感受1.代码一2.代码二 1.动机 在软件构件过程中&#xff0c;由于需求的变化&#xff0c;某些类层次结构中常常需要增加新的行为(方法)&#xff0c;如果直接在基类中做这样的更改&#xff0c; 将会给子类带来很繁重的变更负担&#xff0c…

zabbix小白入门:从SNMP配置到图形展示——以IBM服务器为例

作者 乐维社区&#xff08;forum.lwops.cn&#xff09;许远 在运维实践中&#xff0c;Zabbix作为一款强大的开源监控工具&#xff0c;被广泛应用于服务器、网络设备和应用程序的监控&#xff0c;成为保障业务连续性和高效运行的关键。然而&#xff0c;对于Zabbix的初学者来说&a…

法国工程师IMT联盟 密码学及其应用 2023年期末考试题

1 在 Unix 下的安全性 (30 分钟) 1.1 问题 1 1.1.1 问题 我们注意constat到通过 SMTP 服务器发送“假”电子邮件&#xff08;垃圾邮件&#xff09;相对容易。越来越常见的做法是在 SMTP 连接之上部署dployer TLS 协议protocole&#xff08;即 SMTPS&#xff09;。这解决了垃圾…

【IDEA配置一个maven项目(详细操作流程)】

目录 一、安装Maven 1、官网下载maven链接地址&#xff1a;Maven – Download Apache Maven 2、下载完成后&#xff0c;解压到某一路径下。E:\JavaTools\apache-maven-3.9.8为例&#xff0c;实际配置环境变量时以自己安装的路径为准。 二、配置环境变量 1、右键此电脑–&g…

MybatisPlus实现AES加密解密,实现yml配置文件中数据库连接信息如用户名,密码等信息加密解密

1 生成秘钥&#xff0c;使用AES工具生成一个随机秘钥&#xff0c;然后对用户名&#xff0c;密码加密 //数据库用户名和密码加密工具测试类 public class MpDemoApplicationTests {Testvoid contextLoads() {// 数据库用户名和密码String dbUsername"改成你的数据库连接用…

LabVIEW汽车转向器测试系统

绍了一种基于LabVIEW的汽车转向器测试系统。该系统集成了数据采集、控制和分析功能&#xff0c;能够对转向器进行高效、准确的测试。通过LabVIEW平台&#xff0c;实现了对转向器性能参数的实时监测和分析&#xff0c;提升了测试效率和数据精度&#xff0c;为汽车转向器的研发和…

Ubuntu查看opencv版本c++

✗命令行中直接输入&#xff1a; pkg-config --modversion opencv✔命令行中直接输入&#xff1a; pkg-config --modversion opencv4注解&#xff1a;附上在markdown中打勾&#xff0c;对号和打叉。使用时将&和#之间的空格去掉&#xff0c;这里只是为了不让CSDN自动转换才…

UE5 04-重新加载当前场景

给关卡加一个淡出的效果 给关卡加一个淡入的效果, 这个最好放置在Player 上,这样切关卡依然有这个效果

金斗云 HKMP智慧商业软件 任意用户创建漏洞复现

0x01 产品简介 金斗云智慧商业软件是一款功能强大、易于使用的智慧管理系统,通过智能化的管理工具,帮助企业实现高效经营、优化流程、降低成本,并提升客户体验。无论是珠宝门店、4S店还是其他零售、服务行业,金斗云都能提供量身定制的解决方案,助力企业实现数字化转型和智…

【系统架构设计师】计算机组成与体系结构 ⑨ ( 磁盘管理 | “ 磁盘 “ 单缓冲区 与 双缓冲区 | “ 磁盘 “ 单缓冲区 与 双缓冲区案例 )

文章目录 一、" 磁盘 " 单缓冲区 与 双缓冲区1、" 磁盘 " 单缓冲区2、" 磁盘 " 双缓冲区 二、" 磁盘 " 单缓冲区 与 双缓冲区案例1、案例描述2、磁盘单缓冲区 - 流水线分析3、磁盘双缓冲区 - 流水线分析 一、" 磁盘 " 单缓冲…

c++习题08-计算星期几

目录 一&#xff0c;问题 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;问题 二&#xff0c;思路 首先&#xff0c;需要注意到的是3^2000这个数值很大&#xff0c;已经远远超过了long long 数据类型能够表示的范围&#xff0c;如果想要使用指定的数据类型来保存…

介绍一些好玩且实用的开源的AI工具

介绍一些好玩且实用的开源的AI工具 随着人工智能技术的迅猛发展&#xff0c;开源社区涌现出了许多关于AI的项目&#xff0c;这些项目不仅展示了技术的创新力&#xff0c;也为开发者提供了丰富的工具和资源。本文将介绍几个既有趣又实用的开源人工智能工具&#xff0c;它们不仅…

【C++】 解决 C++ 语言报错:Use of Uninitialized Variable

文章目录 引言 使用未初始化的变量&#xff08;Use of Uninitialized Variable&#xff09;是 C 编程中常见且危险的错误之一。它通常在程序试图使用尚未赋值的变量时发生&#xff0c;导致程序行为不可预测&#xff0c;可能引发运行时错误、数据损坏&#xff0c;甚至安全漏洞。…

【机器学习】机器学习与电商推荐系统的融合应用与性能优化新探索

文章目录 引言第一章&#xff1a;机器学习在电商推荐系统中的应用1.1 数据预处理1.1.1 数据清洗1.1.2 数据归一化1.1.3 特征工程 1.2 模型选择1.2.1 协同过滤1.2.2 矩阵分解1.2.3 基于内容的推荐1.2.4 混合推荐 1.3 模型训练1.3.1 梯度下降1.3.2 随机梯度下降1.3.3 Adam优化器 …

Kubernetes 离线安装的坑我采了

Kubernetes 离线安装的坑我采了 一、Error from server: Get "https://xx.xx.xx.xx:10250/containerLogs/kube-system/calico-node-8dnvs/calico-node": tls: failed to verify certificate: x509: certificate signed by unknown authority二、calico 或 pod 启动正…

目标检测入门:2.使用预训练的卷积神经网络

目录 源码下载 一、ResNet&#xff08;Deep Residual Network&#xff0c;深度残差网络&#xff09; 1.残差结构 ​编辑 2.ResNet网络结构 3.pytorch搭建ResNet 二、CIFAR-10分类&#xff1a;ResNet预训练权重的迁移学习实践 1.CIFAR-10数据集 2.ResNet18实现CIFAR-10分…

该文件没有与之关联的程序来执行该操作,请安装应用,若已经安装应用,请在‘默认应用设置’页面中创建关联。

作为一个喜欢折腾桌面外观的人,我发现桌面上的快捷方式图标都有一个小箭头。于是,我按照网上的方法在注册表中删除了 IsShortcut 键。结果,重启后任务栏上的图标点击时出现了提示:“该文件没有与之关联的程序来执行该操作,请安装应用,若已经安装应用,请在‘默认应用设置…

Markdown+VSCODE实现最完美流畅写作体验

​下载VSCODE软件 安装插件 Markdown All in One &#xff1a;支持markdown的语言的&#xff1b; Markdown Preview Enhanced &#xff1a;观看写出来文档的效果&#xff1b; Paste IMage :添加图片的 Code Spell Checker检查英文单词错误&#xff1b; 基础语法 标题 #一个…

windows USB 设备驱动开发-USB描述符

配置描述符 USB 设备以一系列称为 USB 配置的接口的形式公开其功能。 每个接口由一个或多个备用设置组成&#xff0c;每个备用设置由一组端点组成。 配置描述符中描述了 USB 配置。 配置描述符包含有关配置及其接口、备用设置及其端点的信息。 每个接口描述符或备用设置均在 …

如何使用python网络爬虫批量获取公共资源数据教程?

原文链接&#xff1a;如何使用python网络爬虫批量获取公共资源数据教程&#xff1f;https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608240&idx4&snef281f66727afabfaae2066c6e92f792&chksmfa826657cdf5ef41571115328a09b9d34367d8b11415d5a5781dc4c…