当前位置: 首页 > news >正文

【计算机网络】网络编程接口 Socket API 解读(7)

         Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。

        本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。


send

send()           遵循 POSIX.1 - 2008

MSG_CONFIRM 是 Linux 扩展

1.库

标准 c 库,libc, -lc

2.头文件

<sys/socket.h>

3.接口定义

       ssize_t send(int sockfd, const void buf[.len], size_t len, int flags);ssize_t sendto(int sockfd, const void buf[.len], size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

4.接口描述

        send()、sendto()、sendmsg() 调用用来向另一个套接字发送消息。

        send() 通常只能用在连接状态(即接收者已知)的套接字上,send() 和 write(2) 的唯一不同是 send() 存在 flags 标记。当标记为 0 时,send() 和 write(2) 等效。同样的,下面的两个调用也是等效的。

           send(sockfd, buf, len, flags);
           sendto(sockfd, buf, len, flags, NULL, 0);

         sockfd 参数是 发送套接字的文件描述符。

        如果sendto() 用在连接模式(SOCK_STREAM、SOCK_SEQPACKET)的套接字上,那么参数 dest_addr 和 addrlen 将被忽略(当它们不是 NULL 或者 0时,会返回 EISCON 错误),并且当套接字没有连接时,会返回 ENOTCONN 错误。否则需要给定 addrlen 指定长度的 dest_addr 目标地址,目标地址由 msg.msg_name 给定,长度是 msg.msg_namelen 指定。

        对于 send() 和 sendto(),发送的消息放在 len 长度的 buf 中。对于 sendmsg(),消息由 msg.msg_iov 数组元素指定,sendmsg() 调用同时允许发送一些辅助数据(也称为控制信息)。

        如果消息太大以至于不能自动的透传给底层协议,调用会返回  EMSGSIZE 错误,该消息不会被发送。

        send() 调用没有显示的关于传输失败的指示,在内部检测到这类错误时也只会返回 -1。

        当消息不能装进套接字的发送缓冲区时,send() 正常会阻塞,除非套接字放进了非阻塞 I/O 模式,这种情况在非阻塞模式下会报告 EAGAIN 或者 EWOULDBLOCK 错误。这时可以使用 select(2) 来检测什么时候可以发送更多数据。

flags 参数

        flags 参数可以是下面值的位或:

        MSG_CONFIRM(Linux 2.3.15 后)

        告诉链路层有进展发生:从对端收到了一个成功的回复。如果链路层没有收到这个,那么它通常会在骚扰邻居(通过 ARP 单播)。这个标记只在IPv4/IPv6 的 SOCK_DGRAM 和 SOCK_RAW 套接字中可用,详细信息可以参考 arp(7)。

        MSG_DONTROUTE

        不要使用向网关发送我们的数据包,只发给和我们直接连接的主机。这个通常只有诊断或者路由程序使用。这个只用于支持路由的协议家族,packet 套接字不支持。

        MSG_DONTWAIT(Linux 2.2 后)

        开启非阻塞操作。如果操作想要阻塞,那么就会返回 EAGAIN 或者 EWOULDBLOCK 错误。这个行为和设置 O_NONBLOCK 标记(通过 fcntl(2) F_SETFL 操作)行为类似,但是 MSG_DONTWAIT 只对当前调用生效,而 O_NONBLOCK 是设置到打开文件描述上(参考 open(2)),这会影响调用进程中的所有线程以及其他持有指向该打开文件描述的文件描述符的进程。

        MSG_EOR(Linux 2.2 后)

        结束一个记录(当支持该语义时,用于 SOCK_SEQPACKET 类型的套接字)

        MSG_MORE(Linux 2.4.4 后)

        调用者有更多数据要发送。这个标记用在 TCP 套接字中来获得和 TCP_CORK 套接字选项意向的效果,区别是这个标记只对当前调用生效。

        MSG_NOSIGNAL(Linux 2.2 后)

        如果对端关闭了流套接字,不要生成 SIGPIPE 信号,不过仍然会返回 EPIPE 错误。这和使用 sigaction(2) 来忽略 SIGPIPE 效果差不多,还是 MSG_NONSIGNAL 只对当前调用生效,并且忽略 SIGPIPE 设置的是进程属性,会影响进程中的所有线程。

        MSG_OOB

        在支持该带外数据的套接字(比如 SOCK_STREAM)上发送带外数据。 底层协议必须也支持带外数据传输。

         MSG_FASTOPEN(Linux 3.7 后)

        尝试 TCP 快速打开(RFC7413)并发送在 SYN 中发送数据,就像 connect(2) 和 write(2) 合并一样,进行了隐式的 connect(2) 操作。它会一直阻塞知道数据被缓存并且握手结束。对于一个非阻塞套接字,它会返回缓存数据的大小并且发送一个 SYN 包。如果本地 cookie 不可用,它会返回 EINPROGRESS,并自动发送一个 SYN 带着快速打开 cookie 请求。调用者需要在新连接的套接字上重新发送数据。发生错误时,它会在握手失败时设置和 connect(2) 相同的 errno。这个标记需要 sysctl net.ipv4.tcp_fastopen 来开启 TCP 快速打开客户端支持。

        参考 tcp(7) TCP_FASTOPEN_CONNECT 套接字选项来查看一些可选的方法。

sendmsg()

        sendmsg() 使用的 msghdr 结构定义如下:

           struct msghdr {void         *msg_name;       /* Optional address */socklen_t     msg_namelen;    /* Size of address */struct iovec *msg_iov;        /* Scatter/gather array */size_t        msg_iovlen;     /* # elements in msg_iov */void         *msg_control;    /* Ancillary data, see below */size_t        msg_controllen; /* Ancillary data buffer len */int           msg_flags;      /* Flags (unused) */};

        msg_name 字段用来指定非连接数据包类型套接字的目标地址,它指向一个包含地址的缓冲区,msg_namelen 字段应该设置为地址的大小。对于连接套接字,这些字段应该对应的设置为 NULL 和 0。   

         msg_iov 和 msg_ivolen 字段指定了 scatter-gether 区域,和 writev(2) 类似。

        我们可以使用 msg_control 和 msg_controllen 成员发送控制信息(辅助数据),内核能够处理套接字最大的控制缓冲区大小由 /proc/sys/net/core/optmem_max 指定,参考 socket(7)。对于其他域套接字关于辅助数据的信息,可以参考 unix(7) 和 ip(7)。

        msg_flags 字段忽略。        

5.返回值

        调用成功时,返回已发送数据的字节数。

        发生错误时,返回 -1,并设置errno 来指示错误类型。

       下面这些标准错误值是由套接字层生成的,其他错误可能会由底层协议模块产生并返回,具体可以参考对应的手册页。

        错误值定义如下:

EACCESS(特定于由路径指定的 UNIX 域套接字)目的套接字写权限被拒绝,或者在目录前缀下的搜索权限被拒绝        
 EAGAIN/EWOULDBLOCK套接字被设置为非阻塞,但是请求操作打算阻塞。POSIX.1-2021 允许随意哪个错误都可以,并且不假定两个值相等,所以移植程序应该对每个值都进行判断。
EAGAIN(网络域数据报套接字)sockfd 指定的套接字还没有绑定到地址,并且在尝试绑定到临时端口时,临时端口用尽了。可以看 /proc/sys/net/ipv4/ip_local_port_rang 的讨论
EALREADY另一个快速打开(Fast Open)正在进行中
EBADFsockfd 不是一个打开的文件描述
ECONNRESET对端重置了连接
EDESTADDRREQ套接字不是连接模式,并且没有设置对端地址
EFAULT参数中指定了用户空间不合法的地址
EINTR数据发送完成前有信号发生,参考 signal(7)
EINVAL参数不合法
EISCONN连接模式的套接字早已经连接过了,但是又指定了接收者。(目前要么返回这个错误,要么直接忽略掉接收者参数)
EMSGSIZE套接字类型要求消息自动发送,但是消息的大小却使得这个无法完成
ENOBUFS网络接口输出队列满了。这个通常指示接口已经停止发送,但可能导致传输堵塞。(正常情况下,这个不会在 Linux 上发生,当设备队列溢出时,数据包会偷偷的被丢掉。)
ENOMEM没有内存了
ENOTCONN套接字没连接,也没有指定目标地址
ENOTSOCKsockfd 文件描述符没有指向一个套接字
EOPNOTSUPPflags 里面有些位设置不正确
EPIPE面向连接的套接字在本地被关闭,这种情况下,进程也会收到 SIGPIP 信号,除非我们设置了 MSG_NOSIGNAL。

6.注意

       参考 sendmmsg(2) 来查阅更多 Linux 系统用于一次调用传输多个数据包的信息。

        Linux 系统可能返回 EPIPE 而不是 ENOTCONN。

7.代码

   Server program#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <sys/types.h>#include <unistd.h>#define BUF_SIZE 500intmain(int argc, char *argv[]){int                      sfd, s;char                     buf[BUF_SIZE];ssize_t                  nread;socklen_t                peer_addrlen;struct addrinfo          hints;struct addrinfo          *result, *rp;struct sockaddr_storage  peer_addr;if (argc != 2) {fprintf(stderr, "Usage: %s port\n", argv[0]);exit(EXIT_FAILURE);}memset(&hints, 0, sizeof(hints));hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */hints.ai_flags = AI_PASSIVE;    /* For wildcard IP address */hints.ai_protocol = 0;          /* Any protocol */hints.ai_canonname = NULL;hints.ai_addr = NULL;hints.ai_next = NULL;s = getaddrinfo(NULL, argv[1], &hints, &result);if (s != 0) {fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));exit(EXIT_FAILURE);}/* getaddrinfo() returns a list of address structures.Try each address until we successfully bind(2).If socket(2) (or bind(2)) fails, we (close the socketand) try the next address. */for (rp = result; rp != NULL; rp = rp->ai_next) {sfd = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);if (sfd == -1)continue;if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)break;                  /* Success */close(sfd);}freeaddrinfo(result);           /* No longer needed */if (rp == NULL) {               /* No address succeeded */fprintf(stderr, "Could not bind\n");exit(EXIT_FAILURE);}/* Read datagrams and echo them back to sender. */for (;;) {char host[NI_MAXHOST], service[NI_MAXSERV];peer_addrlen = sizeof(peer_addr);nread = recvfrom(sfd, buf, BUF_SIZE, 0,(struct sockaddr *) &peer_addr, &peer_addrlen);if (nread == -1)continue;               /* Ignore failed request */s = getnameinfo((struct sockaddr *) &peer_addr,peer_addrlen, host, NI_MAXHOST,service, NI_MAXSERV, NI_NUMERICSERV);if (s == 0)printf("Received %zd bytes from %s:%s\n",nread, host, service);elsefprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));if (sendto(sfd, buf, nread, 0, (struct sockaddr *) &peer_addr,peer_addrlen) != nread){fprintf(stderr, "Error sending response\n");}}}
   Client program#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <sys/types.h>#include <unistd.h>#define BUF_SIZE 500intmain(int argc, char *argv[]){int              sfd, s;char             buf[BUF_SIZE];size_t           len;ssize_t          nread;struct addrinfo  hints;struct addrinfo  *result, *rp;if (argc < 3) {fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);exit(EXIT_FAILURE);}/* Obtain address(es) matching host/port. */memset(&hints, 0, sizeof(hints));hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */hints.ai_flags = 0;hints.ai_protocol = 0;          /* Any protocol */s = getaddrinfo(argv[1], argv[2], &hints, &result);if (s != 0) {fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));exit(EXIT_FAILURE);}/* getaddrinfo() returns a list of address structures.Try each address until we successfully connect(2).If socket(2) (or connect(2)) fails, we (close the socketand) try the next address. */for (rp = result; rp != NULL; rp = rp->ai_next) {sfd = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);if (sfd == -1)continue;if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)break;                  /* Success */close(sfd);}freeaddrinfo(result);           /* No longer needed */if (rp == NULL) {               /* No address succeeded */fprintf(stderr, "Could not connect\n");exit(EXIT_FAILURE);}/* Send remaining command-line arguments as separatedatagrams, and read responses from server. */for (size_t j = 3; j < argc; j++) {len = strlen(argv[j]) + 1;/* +1 for terminating null byte */if (len > BUF_SIZE) {fprintf(stderr,"Ignoring long message in argument %zu\n", j);continue;}if (write(sfd, argv[j], len) != len) {fprintf(stderr, "partial/failed write\n");exit(EXIT_FAILURE);}nread = read(sfd, buf, BUF_SIZE);if (nread == -1) {perror("read");exit(EXIT_FAILURE);}printf("Received %zd bytes: %s\n", nread, buf);}exit(EXIT_SUCCESS);}

相关文章:

【计算机网络】网络编程接口 Socket API 解读(7)

Socket 是网络协议栈暴露给编程人员的 API&#xff0c;相比复杂的计算机网络协议&#xff0c;API 对关键操作和配置数据进行了抽象&#xff0c;简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍&#xff0c;从而更好的理解 socket 编程。…...

crypto++下载、安装(VS2017)及加解密使用

crpto 下载按个人喜好下载&#xff0c;我使用了图中框选的8.8.0 Release.解压 安装打开修改以适应本机配置整理至标准库 调用加解密使用 Crypto&#xff08;也称为Crypto Library或Crypto STL&#xff09;是一个C密码学库&#xff0c;它提供了各种密码学算法和安全编程工具&…...

R语言画图

简单记录一下 plot(lad_profile_relative$lad, lad_profile_relative$height, type"l", lwd1.5, xlabexpression(paste("LAD ", "(", m^2, m^-3, ")" )), ylab"Height (m)")X轴数据&#xff0c; Y轴数据 type, 标记类型 lw…...

redis 核心数据结构

一、简述 redis是一个开源的使用C语言编写的一个kv存储系统&#xff0c;是一个速度非常快的非关系远程内存数据库。它支持包括String、List、Set、Zset、hash五种数据结构。 除此之外&#xff0c;通过复制、持久化和客户端分片等特性&#xff0c;用户可以很方便地将redis扩展…...

RabbitMQ消息可靠性(一)-- 生产者消息确认

前言 在项目中&#xff0c;引入了RabbitMQ这一中间件&#xff0c;必然也需要在业务中增加对数据安全性的一层考虑&#xff0c;来保证RabbitMQ消息的可靠性&#xff0c;否则一个个消息丢失可能导致整个业务的数据出现不一致等问题&#xff0c;对系统带来巨大的影响&#xff0c;…...

9 种方法使用 Amazon CodeWhisperer 快速构建应用

Amazon CodeWhisperer 是一款很赞的生成式人工智能编程工具。自从在工作中使用了 CodeWhisperer&#xff0c;我发现不仅代码编译的效率有所提高&#xff0c;应用开发的工作也变得快乐起来。然而&#xff0c;任何生成式 AI 工具的有效学习都需要初学者要有接受新工作方式的心态和…...

性能测试-性能工程落地的4个阶段(21)

性能工程按照不同的内容和目的划分为4个阶段,分别是线下单系统压测分析阶段、线下全链路压测分析阶段、生产只读业务压测及容量评估阶段、生产读写业务全链路压测及容量评估阶段。(也可以理解为一个企业性能测试体系的发展阶段) 线下单系统压测分析阶段 针对单系统的性能…...

小程序 navigateBack 携带参数返回的三种方式(详细)

如果觉着主图好看,点个赞,你早晚也会看到这么好看的景色! 第一种方式 getCurrentPages 获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。不要尝试修改页面栈,会导致路由以及页面状态错误。不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page …...

通过内网穿透实现远程连接群晖Drive,轻松实现异地访问群晖NAS

文章目录 前言1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 前言 群晖作为专业的数据存储中心&…...

vue3 + vite常用工具

1. plop 1.1 安装 yarn add plop -D1.2 使用 1.2.1 package.json 配置脚本命令 "scripts": {"dev": "vite --mode dev","build": "vue-tsc --noEmit && vite build","serve": "vite preview"…...

Vue框架分享与总结

总结开发中最常用的vue语法&#xff0c;以及对特定语法的理解。vue官网 文章目录 一、创建vue项目1、使用开发工具创建2、使用命令行创建3、vue框架结构4、Vue文件结构 二、Vue 常用模板语法1、v-if、v-show2、v-for3、v-on4、v-bind5、v-model 三、组件通信1、父组件给子组件传…...

声音生成评价指标——使用声音分类模型评价生成声音质量(基于resnetish、VGGish、AlexNet)

文章目录 引言正文数据预处理将wav转成log-mel频谱图进行保存创建dataset类保存数据 模型定义模型训练过程训练代码定义loss为nan从AlexNet到ResNetloss上下剧烈波动——使用学习率衰减策略学习率调整——根据准确率来调整学习率数据处理问题 模型的测试 总结 引言 这篇文章主要…...

HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 六)

AppStorage&#xff1a;应用全局的UI状态存储 AppStorage是应用全局的UI状态存储&#xff0c;是和应用的进程绑定的&#xff0c;由UI框架在应用程序启动时创建&#xff0c;为应用程序UI状态属性提供中央存储。 和LocalStorage不同的是&#xff0c;LocalStorage是页面级的&…...

SPA首屏加载速度慢

什么是首屏加载 首屏时间&#xff08;First Contentful Paint&#xff09;&#xff0c;指的是浏览器从响应用户输入网址地址&#xff0c;到首屏内容渲染完成的时间&#xff0c;此时整个网页不一定要全部渲染完成&#xff0c;但需要展示当前视窗需要的内容 首屏加载可以说是用…...

JVM执行流程

一、Java为什么是一种跨平台的语言&#xff1f; 通常&#xff0c;我们编写的java源代码会被JDK的编译器编译成字节码文件&#xff0c;再由JVM将字节码文件翻译成计算机读的懂得机器码进行执行&#xff1b;因为不同平台使用的JVM不一样&#xff0c;所以不同的JVM会把相同的字节码…...

laravel 凌晨0点 导出数据库

一、创建导出模型 <?php namespace App\Models;use Illuminate\Support\Facades\DB;class DbBackup {private $table;public function __construct(){$this->table env(DB_DATABASE);}public function run($file ){$file !$file ? public_path($this->t…...

mysql MVCC多版本并发控制

mvcc的概念 mvcc 的实现依赖于&#xff1a; 隐藏字段 行格式&#xff08;row_id,trx_id,roll_ponter&#xff09;UndologRead view innodb 存储引擎的表来说&#xff0c;聚集索引记录中都包含两个必要的隐藏字段&#xff0c;row_id(如果没有聚集索引&#xff0c;才会创建的) …...

new/delete, malloc/free 内存泄漏如何检测

区别&#xff1a; 首先new/delete是运算符&#xff0c;malloc/free是库函数。malloc/free只开辟内存不初始化&#xff1b;new/delete及开辟内存也初始化。抛出异常的方式&#xff1a;new/delete开辟失败使用抛出bad_alloc&#xff1b;malloc/free通过返回值判断。malloc和new区…...

Java开发推荐关注的网站

一、开发者社区 阿里云开发者社区&#xff1a;https://developer.aliyun.com/腾讯云开发者社区&#xff1a;https://cloud.tencent.com/developer 二、开发规范 阿里巴巴Java开发规范 github地址&#xff1a;https://github.com/alibaba/p3c gitcode地址&#xff1a;https:/…...

OpenHarmony社区运营报告(2023年8月)

本月快讯 2023年8月3日&#xff0c;OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;发布了Beta2版本。OpenHarmony 4.0 Beta2在系统能力、应用框架、分布式通信、媒体功能、安全性等方面进行了全面升级。其中&#xff0c;ArkUI增强了界面组件能力&#x…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...