Socket网络通讯原理及TCP、UDP开发

前言

网络通讯是嵌入式开发、物联网设备开发的核心基础能力,而Socket套接字作为TCP/IP协议簇的核心通讯单元,是实现跨设备、跨主机进程双向数据传输的核心载体。日常网络浏览、即时通讯、音视频传输、设备物联网数据上报等绝大多数网络服务,均基于Socket通讯机制实现。

在嵌入式鸿蒙设备开发场景中,熟练掌握Socket通讯原理,区分TCP、UDP协议的核心特性与适用场景,能够独立完成客户端、服务端及广播通讯的开发调试,是物联网设备联网交互开发的必备技能。本文将从核心通讯原理入手,详细讲解Socket、TCP、UDP的基础概念与核心区别,并结合实际开发案例,完整演示TCP点对点通讯、UDP点对点通讯、UDP广播通讯的开发流程、代码实现与调试校验方式,为嵌入式网络通讯开发提供完整的实战参考。

一、核心通讯基础原理

Socket通讯

socket(简称 套接字) ,是支持TCP/IP网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

编辑

它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的

例如我们每天浏览网页、QQ 聊天、收发 email 等等

TCP协议

TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

TCP通信需要经过创建连接、数据传送、终止连接三个步骤。

编辑

TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,"打电话""

编辑

编辑

TCP的特点:

  1. 面向连接。
    1. 通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。
    2. 双方间的数据传输都可以通过这一个连接进行。
    3. 完成数据交换后,双方必须断开此连接,以释放系统资源。
  1. 传输可靠
    1. TCP采用发送应答机制。
    2. 超时重传。发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。
    3. 错误校验。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
    4. 流量控制和阻塞管理。流量控制用来避免主机发送得过快而使接收方来不及完全收下。

UDP协议

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。

UDP传输的每个数据包被限制在64K以内(数据包大小由一个16位的无符号整数记录)。

编辑

UDP (User Datagram Protocol )不提供复杂的控制机制, 如果传输过程中出现丢包, UDP 也不负责重发. 甚至当出现包到达顺序乱掉时候也没有纠正的功能. 由于 UDP 面向无连接, 它可以随时发送数据. 再加上 UDP 本身的处理既简单又高效, 因此常用于以下几个方面:

  • 包总量较少的通信(DNS).
  • 视频、音频等多媒体通信(即时通信).
  • 限定于 LAN 等特定网络中的应用通信.
  • 广播通信(广播、多播)

UDP的特点:

  • 需要资源少
  • 不保证接收
  • 无连接

UDP和TCP的区别

UDP TCP
面向无连接 面向有连接
支持一对一、一对多、多对一、和多对多的通信 只能有两个端点,实现一对一的通信
不保证数据传输的可靠性 传输数据无差错,不丢失,不重复,且按时序到达
占用资源较 占用资源较

TCP编程

开发流程图

编辑

客户端开发

需求说明
  1. 确保设备能够连接网络
  2. 当前开发的是客户端,需要有一个服务端配合,实现两者通讯
  3. 确保服务端和客户端在同一个网络环境中(在同一个局域网)
  4. 客户端循环给服务端发送消息
开发流程

来到应用开发的根目录。

我们编写代码的根目录device/board/itcast/genkipi/app

  1. 根目录 下新建tcp_client文件夹,此为项目目录
  2. 项目目录 下新建main.c文件
  3. 项目目录 下新建BUILD.gn文件
  4. 修改根目录 下的BUILD.gn文件
代码部分
ini 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_sta.h"

#include "lwip/sockets.h"

#define SSID        "xq"
#define PASSWORD    "qwer1234"
#define HOSTNAME    "itcast"

#define SERVER_IP   "192.168.137.1"
#define SERVER_PORT 8080


static void start_tcp_client(void) {
    int sock_fd;
    int ret;
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0) {
        perror("[actuator_service]sock_fd create error\r\n");
        return;
    }

    // receive addr config
    struct sockaddr_in server_addr;
    socklen_t server_addr_len = sizeof(server_addr);

    memset((void *) &server_addr, 0, server_addr_len);
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    server_addr.sin_port = htons(SERVER_PORT);

    ret = connect(sock_fd, (struct sockaddr *) &server_addr, server_addr_len);
    if (ret == -1) {
        perror("connect error\r\n");
        return;
    }

    char msg[1024];
    int cnt = 0;
    while (1) {
        sprintf(msg, "hello %d\r\n", cnt++);
        ret = send(sock_fd, msg, strlen(msg), 0);

        if (ret == -1) {
            perror("send error\r\n");
            break;
        }

        usleep(1 * 1000 * 1000);
    }
}

static void startSta(void)
{
    wifi_sta_connect(SSID, PASSWORD, HOSTNAME);
    start_tcp_client();
}

static void main(void)
{
    osThreadAttr_t attr;

    attr.name = "tcp_client";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 25;

    // Create the Thread1 task
    if (osThreadNew((osThreadFunc_t)startSta, NULL, &attr) == NULL) {
        printf("Failed to create say hello Thread!\n");
    }
}

APP_FEATURE_INIT(main);
ini 复制代码
static_library("tcp_client") {
  sources = [ "main.c" ]

  include_dirs = [
    "//base/iothardware/peripheral/interfaces/inner_api",
    "../../services/wifi/include",
  ]
  deps = [
    "../../services:genkipi_services",
  ]
}
javascript 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
  features = [
    "tcp_client"
  ]
}
校验方式

打开网络调试助手,当前编写的代码为tcp 客户端,那么我们需要将调试助手配置为tcp 服务端。配置如图:

编辑

观察输出结果:

编辑

服务端开发

需求说明
  1. 确保设备能够连接网络
  2. 当前开发的是服务端 ,需要有一个客户端配合,实现两者通讯
  3. 确保服务端和客户端在同一个网络环境中(在同一个局域网)
  4. 服务端等待客户端发送消息
开发流程

来到应用开发的根目录。

我们编写代码的根目录device/board/itcast/genkipi/app

  1. 根目录 下新建tcp_server文件夹,此为项目目录
  2. 项目目录 下新建main.c文件
  3. 项目目录 下新建BUILD.gn文件
  4. 修改根目录 下的BUILD.gn文件
代码部分
ini 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_sta.h"

#include "lwip/sockets.h"

#define SSID        "xq"
#define PASSWORD    "qwer1234"
#define HOSTNAME    "itcast"

#define SERVER_PORT 8080


static void start_tcp_server(void) {
    int sock_fd;
    int ret;
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0) {
        perror("[actuator_service]sock_fd create error\r\n");
        return;
    }
    // config receive addr
    struct sockaddr_in recvfrom_addr;
    socklen_t recvfrom_addr_len = sizeof(recvfrom_addr);

    memset((void *) &recvfrom_addr, 0, recvfrom_addr_len);
    recvfrom_addr.sin_family = AF_INET;
    recvfrom_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    recvfrom_addr.sin_port = htons(SERVER_PORT);
    // bind
    ret = bind(sock_fd, (struct sockaddr *) &recvfrom_addr, recvfrom_addr_len);
    if (ret == -1) {
        perror("bind error\r\n");
        return;
    }

    // listen, just listen 1 connect
    ret = listen(sock_fd, 1);
    if (ret == -1) {
        perror("[actuator_service]listen error\r\n");
        return;
    }

    while (1) {
        int client_fd;
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);

        client_fd = accept(sock_fd, (struct sockaddr *) &client_addr, &client_addr_len);
        if (client_fd < 0) {
            perror("accept client error\r\n");
            continue;
        }
        
        printf("client connect: %s\r\n", inet_ntoa(((struct sockaddr_in*)(&client_addr))->sin_addr));
        char recv_buf[1024];
        int recv_len;
        while (1) {
            recv_len = recv(client_fd, recv_buf, sizeof(recv_buf), 0);
            if (recv_len <= 0) {
                break;
            }
            char recv_data[recv_len];
            memcpy(recv_data, recv_buf, recv_len);
            recv_data[recv_len] = '\0';
            printf("len: %d data: %s\r\n", recv_len, recv_data);
        }
    }
}

static void startSta(void)
{
    wifi_sta_connect(SSID, PASSWORD, HOSTNAME);
    start_tcp_server();
}

static void main(void)
{
    osThreadAttr_t attr;

    attr.name = "tcp_server";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 25;

    // Create the Thread1 task
    if (osThreadNew((osThreadFunc_t)startSta, NULL, &attr) == NULL) {
        printf("Failed to create say hello Thread!\n");
    }
}

APP_FEATURE_INIT(main);
ini 复制代码
static_library("tcp_server") {
  sources = [ "main.c" ]

  include_dirs = [
    "//base/iothardware/peripheral/interfaces/inner_api",
    "../../services/wifi/include",
  ]
  deps = [
    "../../services:genkipi_services",
  ]
}
javascript 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
  features = [
    "tcp_server"
  ]
}
校验方式

打开网络调试助手,当前编写的代码为tcp 服务端,那么我们需要将调试助手配置为tcp 客户端。配置如图:

编辑

服务器IP的获取方式需要通过路由器获得,我使用的是PC机作为热点,可以通过热点中进行设备ip的查询:

编辑

点击连接网络,查看串口打印:

编辑

客户端已经连接到自己编写的服务器上了。

在网络调试工具中输入要发送的内容,点击发送,查看服务端的打印结果:

编辑

编辑

UDP编程

编辑

客户端开发

需求说明
  1. 确保设备能够连接网络
  2. 当前开发的是客户端,需要有一个服务端配合,实现两者通讯
  3. 确保服务端和客户端在同一个网络环境中(在同一个局域网)
  4. 客户端循环给服务端发送消息
开发流程

来到应用开发的根目录。

我们编写代码的根目录device/board/itcast/genkipi/app

  1. 根目录 下新建udp_client文件夹,此为项目目录
  2. 项目目录 下新建main.c文件
  3. 项目目录 下新建BUILD.gn文件
  4. 修改根目录 下的BUILD.gn文件
代码部分
arduino 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_sta.h"

#include "lwip/sockets.h"

#define SSID        "xq"
#define PASSWORD    "qwer1234"
#define HOSTNAME    "itcast"

#define SERVER_IP   "192.168.137.1"
#define SERVER_PORT 8080

static void start_udp_client(void) {
    // 创建udp
    int sock_fd;
    int ret;
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_fd < 0) {
        perror("sock_fd create error\r\n");
        return;
    }

    // config send addr
    struct sockaddr_in send_addr;
    socklen_t send_addr_len = sizeof(send_addr);
    // 初始化发送地址
    memset((void *) &send_addr, 0, send_addr_len);
    send_addr.sin_family = AF_INET;
    //这个位置是否是inet_addr_t
    send_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    send_addr.sin_port = htons(SERVER_PORT);

    char msg[1024];
    int cnt = 0;
    while (1) {
        sprintf(msg, "hello %d\r\n", cnt++);
        ret = sendto(sock_fd, msg, strlen(msg), 0, (struct sockaddr *) &send_addr, send_addr_len);

        usleep(1 * 1000 * 1000);
    }
}

static void startSta(void)
{
    wifi_sta_connect(SSID, PASSWORD, HOSTNAME);
    start_udp_client();
}

static void main(void)
{
    osThreadAttr_t attr;

    attr.name = "udp_client";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 25;

    // Create the Thread1 task
    if (osThreadNew((osThreadFunc_t)startSta, NULL, &attr) == NULL) {
        printf("Failed to create say hello Thread!\n");
    }
}

APP_FEATURE_INIT(main);
ini 复制代码
static_library("udp_client") {
  sources = [ "main.c" ]

  include_dirs = [
    "//base/iothardware/peripheral/interfaces/inner_api",
    "../../services/wifi/include",
  ]
  deps = [
    "../../services:genkipi_services",
  ]
}
javascript 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
  features = [
    "udp_client"
  ]
}
校验方式

打开网络调试助手,当前编写的代码为udp客户端,那么我们需要将调试助手配置为UDP服务端。配置如图:

编辑

服务器IP也是本机IP地址,我们可以通过命令行查询本机的IP:

复制代码
ipconfig

结果如图:

编辑

我查看的是无线局域网适配器,因为我的PC作为热点和我们的开发板进行连接的。查询结果有两个,两个都可以使用。

点击连接网络后,观察输出结果:

编辑

服务端开发

需求说明
  1. 确保设备能够连接网络
  2. 当前开发的是服务端 ,需要有一个客户端配合,实现两者通讯
  3. 确保服务端和客户端在同一个网络环境中(在同一个局域网)
  4. 服务端等待客户端发送消息
开发流程

来到应用开发的根目录。

我们编写代码的根目录device/board/itcast/genkipi/app

  1. 根目录 下新建udp_server文件夹,此为项目目录
  2. 项目目录 下新建main.c文件
  3. 项目目录 下新建BUILD.gn文件
  4. 修改根目录 下的BUILD.gn文件
代码部分
c 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_sta.h"

#include "lwip/sockets.h"

#define SSID        "xq"
#define PASSWORD    "qwer1234"
#define HOSTNAME    "itcast"

#define SERVER_PORT 8080


static void start_udp_server(void) {
     // udp create
    int sock_fd;
    int ret;
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_fd < 0) {
        perror("sock_fd create error\r\n");
        return;
    }

    // config receive addr
    struct sockaddr_in recvfrom_addr;
    socklen_t recvfrom_addr_len = sizeof(recvfrom_addr);

    memset((void *) &recvfrom_addr, 0, recvfrom_addr_len);
    recvfrom_addr.sin_family = AF_INET;
    recvfrom_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    recvfrom_addr.sin_port = htons(SERVER_PORT);

    // bind receive addr
    // bind
    ret = bind(sock_fd, (struct sockaddr *) &recvfrom_addr, recvfrom_addr_len);
    if (ret == -1) {
        perror("bind error\r\n");
        return;
    }

    char recv_buf[1024];
    int recv_len;
    while (1) {
        struct sockaddr_in sender_addr;
        int sender_addr_len;

        recv_len = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *) &sender_addr,
                            sender_addr_len);

        if (recv_len <= 0) {
            continue;
        }

        char recv_data[recv_len];
        memcpy(recv_data, recv_buf, recv_len);
        printf("len: %d data: %s\r\n", recv_len, recv_data);
    }
}

static void startSta(void)
{
    wifi_sta_connect(SSID, PASSWORD, HOSTNAME);
    start_udp_server();
}

static void main(void)
{
    osThreadAttr_t attr;

    attr.name = "udp_server";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 25;

    // Create the Thread1 task
    if (osThreadNew((osThreadFunc_t)startSta, NULL, &attr) == NULL) {
        printf("Failed to create say hello Thread!\n");
    }
}

APP_FEATURE_INIT(main);
ini 复制代码
static_library("tcp_server") {
  sources = [ "main.c" ]

  include_dirs = [
    "//base/iothardware/peripheral/interfaces/inner_api",
    "../../services/wifi/include",
  ]
  deps = [
    "../../services:genkipi_services",
  ]
}
javascript 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
  features = [
    "tcp_server"
  ]
}
校验方式

打开网络调试助手,当前编写的代码为tcp 服务端,那么我们需要将调试助手配置为tcp 客户端。配置如图:

编辑

服务器IP的获取方式需要通过路由器获得,我使用的是PC机作为热点,可以通过热点中进行设备ip的查询:

编辑

点击连接网络,查看串口打印:

编辑

广播开发

需求说明
  1. 确保设备能够连接网络
  2. 当前开发的是广播端,需要多个接收端配合,实现一对多通讯
  3. 确保服务端和客户端在同一个网络环境中(在同一个局域网)
  4. 广播端循环给接收端发送消息
开发流程

来到应用开发的根目录。

我们编写代码的根目录device/board/itcast/genkipi/app

  1. 根目录 下新建udp_broadcast文件夹,此为项目目录
  2. 项目目录 下新建main.c文件
  3. 项目目录 下新建BUILD.gn文件
  4. 修改根目录 下的BUILD.gn文件
代码部分
ini 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_sta.h"

#include "lwip/sockets.h"

#define SSID        "xq"
#define PASSWORD    "qwer1234"
#define HOSTNAME    "itcast"

#define SERVER_PORT 8080


static void start_udp_broadcast(void) {
       // udp create
    int sock_fd;
    int ret;
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_fd < 0) {
        perror("sock_fd create error\r\n");
        return;
    }

    // set broadcast mode
    int yes = 1;
    ret = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *) &yes, sizeof(yes));
    if (ret == -1) {
        perror("setsockopt error\r\n");
        return;
    }

    // config broadcast addr
    struct sockaddr_in broadcast_addr;
    socklen_t broadcast_addr_len = sizeof(broadcast_addr);

    memset((void *) &broadcast_addr, 0, broadcast_addr_len);
    broadcast_addr.sin_family = AF_INET;
    broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    broadcast_addr.sin_port = htons(SERVER_PORT);

    char msg[1024];
    int cnt = 0;
    while (1) {
        sprintf(msg, "hello %d\r\n", cnt++);
        ret = sendto(sock_fd, msg, strlen(msg), 0, (struct sockaddr *) &broadcast_addr, broadcast_addr_len);

        usleep(1 * 1000 * 1000);
    }
}

static void startSta(void)
{
    wifi_sta_connect(SSID, PASSWORD, HOSTNAME);

    start_udp_broadcast();
}

static void main(void)
{
    osThreadAttr_t attr;

    attr.name = "tcp_client";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 25;

    // Create the Thread1 task
    if (osThreadNew((osThreadFunc_t)startSta, NULL, &attr) == NULL) {
        printf("Failed to create say hello Thread!\n");
    }
}

APP_FEATURE_INIT(main);
ini 复制代码
static_library("udp_broadcast") {
  sources = [ "main.c" ]

  include_dirs = [
    "//base/iothardware/peripheral/interfaces/inner_api",
    "../../services/wifi/include",
  ]
  deps = [
    "../../services:genkipi_services",
  ]
}
javascript 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
  features = [
    "udp_broadcast"
  ]
}
校验方式

打开网络调试助手,当前编写的代码为UDP广播端,那么我们需要将调试助手配置为UDP接收端,而且不止一个UDP接收端,这个时候我们需要多台电脑,每台电脑都打开网络调试助手。网络调试助手配置如图:

编辑

点击连接网络,观察打印输出结果。

编辑

在这里需要特别强调的是,多台接收电脑和广播端必须在同一个局域网内。

总结

本文系统阐述了Socket通讯的核心原理,清晰对比了TCP与UDP两大传输协议的特性、区别与适用场景,并基于鸿蒙嵌入式设备,完整实现了TCP点对点通讯、UDP点对点通讯、UDP局域网广播通讯三大核心开发案例。

TCP协议凭借面向连接、可靠传输的特性,适用于文件传输、指令交互、数据上报等对完整性、有序性要求高的场景;而UDP协议凭借无连接、低延迟、低资源消耗的优势,广泛应用于音视频传输、实时广播、轻量化数据交互场景,其中UDP广播更是实现局域网一对多通讯的核心方案。

本次所有案例均包含完整的项目搭建、代码编写、编译配置与调试校验流程,可直接落地应用。熟练掌握以上开发内容,能够满足嵌入式物联网设备基础网络通讯的开发需求,为后续复杂网络交互、多设备组网、物联网数据传输等进阶开发奠定坚实的技术基础。

相关推荐
ZHW_AI课题组16 小时前
使用高斯混合模型对鸢尾花数据集进行聚类分析
人工智能·机器学习·支持向量机
L_cl17 小时前
大模型应用开发 10.DeepSpeed
机器学习
m沐沐17 小时前
机器学习零基础吃透混淆矩阵!准确率 / 精确率 / 召回率 / F1 分数
人工智能·深度学习·机器学习·矩阵·pycharm
极光代码工作室18 小时前
基于NLP的论文智能分析系统
深度学习·机器学习·ai·自然语言处理·系统设计
MediaTea18 小时前
人工智能通识课:深度学习框架 PyTorch
人工智能·pytorch·python·深度学习·机器学习
Narv工程师1 天前
嵌入式机器人控制器算力评估:从DMIPS到WCET的完整指南
人工智能·算法·机器学习
AI医影跨模态组学1 天前
J Thorac Oncol(IF=20.8)广东省人民医院钟文昭教授团队:基于影像组学的支持向量机区分驱动肺腺癌进展的分子事件
人工智能·深度学习·机器学习·论文·医学·医学影像·影像组学
徐安安ye2 天前
FlashAttention长程依赖建模:局部+全局的Hybrid Spiral结构设计
python·深度学习·机器学习