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

Day05 linux高级系统设计 - 管道

复制文件描述符

dup函数

作用:

文件描述符复制

语法:

        #include <unistd.h>

        int dup (int oldfd);

参数:

        所需复制得文件描述符

返回值:

        复制到的文件描述符

功能:

        从文件描述符表中,找一个最小可能的文件描述符(通过返回值返回)作为oldfd复制

示例1:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{int newpd = dup(1);write(newpd,"hello world\n",12);return 0;
}

dup2函数(推荐)

函数:

#include <unistd.h>

int dup2(int oldfd,int newfd);

参数:

oldfd:原文件描述符

newfd:指定复制到的文件描述符,如果该文件描述符已存在,那将已存在的关闭

示例:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{int fd = open("huange.txt",O_WRONLY | O_CREAT | O_APPEND,0666);int pd = dup2(fd,1);printf("娶你明年\n");return 0;
}

无名管道

概述

又名管道 (pipe)
无名管道是一种特殊类型的文件,在应用层体现为两个打开的文件描述符 ,1 个描述符写 fd[1], 1 个描述符读 fd[0]
核心:0读1写
特点
1.管道不是普通的文件,不属于某个文件管理系统,存在于内存中
2.半双工:数据在同一时间只能在单向传输
补充:
单工:指数据只能在单向传输数据
双工:指在两台通讯设备之间,允许有双向的数据传输
全双工:允许两台通讯设备之间同时进行双向数据传输。一般的电话,手机就是全双工系统,因为在讲话的同时也能听到对方的声音。
半双工:允许两台通讯设备之间进行双向数据传输,但不能同时进行。因此同一时间只允许一个设备进行传输数据,若另一设备需要传输数据,则需要等待上一个传输数据的设备传输结束后,才可以传输数据。
3.数据只允许从管道的一端写入,从管道的另一端读取
4.写入管道中的数据遵循先入先出的原则        
5.管道所传输的数据是无格式的,这要求管道的读出方和写入放提前商量好一个文件的格式,如多少字节算一则消息
6.管道在内存中对应一个缓冲区。不通的系统所对应的大小不一样。
7.数据从管道中读取是一次性操作,管道中数据一旦被读取,管道就会抛弃该数据,以便于释放空间来写入其它数据
8.管道没有名字,只能在具有公共祖先的进程中使用
补充: 管道可以用于任意两个或更多相关进程之间的通信,只要在创建子进程 的系列调用之前通过一个共同的祖先进程创建管道即可。
        如管道可用于一个进程和其子孙进程之间的通信。第一个进程创建管道,然后创建子进程,接着子进程再创建第一个进程的孙子进程。
        管道通常用于两个兄弟进程之间的通信—— 它们的父进程创建了管道,并创建两个子进程。

pipe函数

作用:用于创建无名管道

语法:

#include <unistd.h>

int fd[] ;

pipe(fd);

参数:

fd为int型数据的首元素地址,其存放了管道的文件描述符反对fd[0],fd[1]

f[0]为读而打开管道,f[1]为写而打开

返回值:

        成功:0

        失败:-1

int fd[2];

pipe(fd);

示例:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char const *argv[])
{int fd[2];pipe(fd);int i = 0;for(i = 0;i < 2;i++){int pid = fork();if(pid == 0){break;}}if(i == 0){close (fd[0]);char buf[] = "hello to2";write(fd[1],buf,sizeof(buf));close(fd[1]);_exit(0);}else if(i == 1){close (fd[1]);char buf[60] = {0};read(fd[0],buf,sizeof(buf));close(fd[0]);printf("%s\n",buf);_exit(0);}else if(i == 2){while(1){int pid = waitpid(-1,NULL,WNOHANG);if(pid == 0){break;}}}return 0;
}

读写特点

1.默认用read函数从管道中读取数据时是阻塞的

2.调用write函数写入时,当管道的缓冲区已满时,也会发生阻塞,管道的缓冲区大小时65kb

3.通信过程中,读端口全部关闭后,写进程向管道内写数据时,写进程会(收到SIGPIPE 信号)退出。

4.从管道中读取数据的特点  编程时可通过fcntl函数设置文件的阻塞特性。设置为阻塞:fcntl(fd,FSETFL,O_NONBLOCK);

示例一:缓冲区已满时 write 也会阻塞。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{int fd[2] ;pipe(fd);int pid = fork();if(pid == 0){close(fd[1]);sleep(2);close(fd[0]);_exit(0);}else if(pid > 0){close(fd[0]);//关闭读int count = 0;for(int i = 0;i < 10000;i++){int buf[1024] = {0};printf("buf=%ld\n",sizeof(buf)/sizeof(buf[0]));write(fd[1],buf,1024);count += 1024;printf("i=%d\ncount%d\n",i,count);}  close(fd[1]);wait(NULL);}return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{//证明:调用 write 函数向管道里写数据,当缓冲区已满时 write 也会阻塞int fd[2];pipe(fd);for (int i = 0; i < 1000; i++){char buf[1024] = {0};write(fd[1],buf,1024);printf("i = %d\n",i);}printf("OVER\n");return 0;
}

示例二:通信过程中,写端关闭,读端将解阻塞

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{int fd[2];pipe(fd);int pid = fork();if(pid == 0){close(fd[1]);int buf[100] = {0};printf("开始读取\n");read(fd[0],buf,100);close(fd[0]);printf("读取结束\n");_exit(0);}else if(pid > 0){close(fd[0]);sleep(2);close(fd[1]);sleep(5);_exit(0);}return 0;
}

示例三:通信过程中 读端关闭 写端将收到SIGPIPE信号 退出写端进程

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{int fd[2];pipe(fd);int pid = fork();if (pid == 0){close(fd[1]);while (1){int i = 0;char buf[128] = "";int len = read(fd[0], buf, sizeof(buf) / sizeof(buf[0]));i++;printf("len=%d\n", len);if (i == 5){break;}}}else if (pid > 0){close(fd[0]);while(1){printf("给父进程%u写数据\n",getpid());write(fd[1],"hello pipe",10);sleep(1);}close(fd[1]);wait(NULL);}return 0;
}

综合案例

要求 : 使用代码实现 ps -A | grep bash
示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{int pd[2];pipe(pd);int pid = fork();if(pid < 0){printf("输入有误\n");return 0;}else if(pid  == 0){close(pd[1]);dup2(pd[0],0);execl("/bin/grep","/bin/grep","bash",NULL);_exit(-1);}else if(pid > 0){close(pd[0]);dup2(pd[1],1);execl("/bin/ps","ps","-A",NULL);wait(NULL);}return 0;
}

有名管道

概述:

又名命名管道(FIFO)

特点 :
1 、半双工,数据在同一时刻只能在一个方向上流动。
2 、写入 FIFO 中的数据遵循先入先出的规则。
3 FIFO 所传送的数据是无格式的,这要求 FIFO 的读出方与写入方必须事先约定好数据的格式,如多少字节算一个消息等。
4 FIFO 在文件系统中作为一个特殊的文件而存在,但 FIFO 中的内容却存放在内存中。
5 、管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
6 、从 FIFO 读数据是一次性操作,数据一旦被读,它就从 FIFO 中被抛弃,释放空间以便写更多的数据。
7 、当使用 FIFO 的进程退出后, FIFO 文件将继续保存在文件系统中以便以后使用。
8 FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。

概述

mkfifo函数

作用:创建有名管道

语法:

        #include <sys/types.h>

        #include <sys/stat.h>

int mkfifo(const char *pathname,mode_t mode);

参数:

        pathname:文件名

mode:文件操作模式,一般使用0666(所有用户可读可写)

返回值

        成功:0

        失败:-1 一般失败是因为有与pathname名相同的文件

读写特点

1 open 打开管道 不指定 O_NONBLOCK ( 阻塞 )
1 open 以只读方式打开 FIFO 时,要阻塞到某个进程为写而打开此 FIFO
2 open 以只写方式打开 FIFO 时,要阻塞到某个进程为读而打开此 FIFO
3 open 以只读、只写方式打开 FIFO 时会阻塞,调用 read 函数从 FIFO 里读数据
read 也会阻塞。
4 、通信过程中若写进程先退出了,则调用 read 函数从 FIFO 里读数据时不阻塞;若写进程又重新运行,则调用 read 函数从 FIFO 里读数据时又恢复阻塞。
5 、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到 SIGPIPE 信号)退出。
6 、调用 write 函数向 FIFO 里写数据,当缓冲区已满时 write 也会阻塞。
2 open 打开管道 指定 O_NONBLOCK ( 非阻塞 )
1 、先以只读方式打开:如果没有进程 , 已经为写而打开一个 FIFO, 只读 open 成功,并且 open 不阻塞。
2 、先以只写方 式打开:如果没有进程 , 已经为读而打开一个 FIFO ,只写 open 将出错返回-1
3 read write 读写命名管道中读数据时不阻塞。
4 、通信过程中,读进程退出后, 写进程向命名管道内写数据时,写进程也会(收到SIGPIPE 信号)退出。
3 、 注意: open 函数以可读可写方式打开 FIFO 文件时的特点:
1 open 不阻塞。
2 、调用 read 函数从 FIFO 里读数据时 read 会阻塞。
3 、调用 write 函数向 FIFO 里写数据 , 当缓冲区已满时 write 也会阻塞

综合案例

09_demoA.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char const *argv[])
{int i = 0;for(i = 0;i < 2;i++){int pid = fork();if(pid == 0){break;}}if(i == 0){mkfifo("./zjrtozl",0666);//张晋若发送消息int fd = open("./zjrtozl",O_WRONLY);while(1){char buf[100] = {0};fgets(buf,100,stdin);                                        printf("张晋若:%s\n",buf);write(fd,buf,strlen(buf));buf[strlen(buf)-1] = 0;if(strcmp("886",buf) == 0){break;}}close(fd);_exit(0);}else if(i == 1){mkfifo("./zltozjr",0666);//张立接收消息int fd = open("./zltozjr",O_RDONLY);while(1){char buf[100] = {0};read(fd,buf,sizeof(buf));printf("张立:%s\n",buf);buf[strlen(buf)-1] = 0;if(strcmp("886",buf) == 0){break;}}close(fd);_exit(0);}else if(i == 2){while(1){int pid = waitpid(-1,NULL,WNOHANG);if(pid == -1){break;//子进程已经回收完毕}}}return 0;
}

09_demoB.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char const *argv[])
{int i = 0;for(i=0;i < 2;i++){int pid = fork();if(pid == 0){break;}}if(i == 0){mkfifo("./zltozjr",0666);//张立发消息int fd = open("./zltozjr",O_WRONLY);while(1){char buf[120] = {0};fgets(buf,120,stdin);printf("张立:%s\n",buf);write(fd,buf,strlen(buf));buf[strlen(buf)-1] = 0;if(strcmp("886",buf) ==0){break;}}close(fd);_exit(0);}else if(i == 1){mkfifo("./zjrtozl",0666);//张晋若接收消息int fd =open("./zjrtozl",O_RDONLY);while(1){char buf[] = {0};read(fd,buf,sizeof(buf));printf("张晋若:%s\n",buf);buf[strlen(buf)-1] = 0;if(strcmp("886",buf)==0){break;}}close(fd);_exit(0);}else if(i == 2){while(1){int pid = waitpid(-1,NULL,WNOHANG);if(pid == -1){break;//子进程回收完毕}}}return 0;
}

总结

无名管道与有名管道的使用场景

1.无名管道应用于有血缘关系的进程中

2.有名管道应用于没有血缘关系的进程中

有名管道与无名管道的区别

1.无名管道是基于内存的,无需文件管理系统

2.有名管道是基于文件和内存的,需要文件管理系统

dup

作用;复制文件描述符

意义:可以通过dup函数实现文件的重定向

相关文章:

Day05 linux高级系统设计 - 管道

复制文件描述符 dup函数 作用&#xff1a; 文件描述符复制 语法&#xff1a; #include <unistd.h> int dup (int oldfd); 参数&#xff1a; 所需复制得文件描述符 返回值&#xff1a; 复制到的文件描述符 功能&#xff1a; 从文件描述符表中&#xff0c;找一个最小…...

低代码:美味膳食或垃圾食品?

一、什么是低代码 低代码是一种开发方法&#xff0c;通过可视化界面和少量的编码&#xff0c;使开发者能够快速构建应用程序。它的目标是提高开发效率、降低开发成本&#xff0c;并支持快速迭代和敏捷开发。 二、低代码的优缺点 低代码开发具有以下优点&#xff1a; 快速开…...

免费网页抓取工具大全【附下载和工具使用教程】

在当今信息爆炸的时代&#xff0c;获取准确而丰富的数据对于企业决策和个人研究至关重要。而网页抓取工具作为一种高效获取互联网数据的方式&#xff0c;正逐渐成为大家解决数据需求的得力助手。本文将深入探讨网页抓取工具的种类&#xff0c;并为大家提供简单实用的页面采集教…...

Leetcode 39 组合总和

题意理解&#xff1a; 一个 无重复元素 的整数数组 candidates 和一个目标整数 target 从candidates 取数字&#xff0c;使其和 target &#xff0c;有多少种组合&#xff08;candidates 中的 同一个 数字可以 无限制重复被选取&#xff09; 这道题和之前一道组合的区别&am…...

Windows下使用AndroidStudio及CMake编译Android可执行程序或静态库动态库

Windows下使用AndroidStudio及CMake编译Android可执行程序或静态库动态库 文章目录 Windows下使用AndroidStudio及CMake编译Android可执行程序或静态库动态库一、前言二、编译环境三、示例C/CPP程序1、总体工程结构2、示例代码3、CMakeLists.txt&#xff08;重要&#xff09;4、…...

MySQL七 | 存储引擎

目录 存储引擎 存储引擎特点 存储引擎选择 Innodb与MyISAM区别 存储引擎 默认存储引擎:InnoDB show engines;#展示当前数据库支持的存储引擎 存储引擎特点 特点InnoDBMyISAMMemory存储限制64TB有有事务安全支持--锁机制行锁表锁表锁Btree锁支持支持 支持 Hash索引--支…...

网上下载的pdf文件,为什么不能复制文字?

不知道大家有没有到过这种情况&#xff1f;在网上下载的PDF文件打开之后&#xff0c;发现选中文字之后无法复制。甚至其他功能也都无法使用&#xff0c;这是怎么回事&#xff1f;该怎么办&#xff1f; 当我们发现文件打开之后&#xff0c;编辑功能无法使用&#xff0c;很可能是…...

Linux下apisix离线安装教程

Linux下apisix离线安装教程 一、首先需要安装etcd&#xff1a;二、通过rpm离线安装apisix三、启动apisix四、安装apisix-dashboard1、安装2、更改dashboard登录账号名和密码3、运行 一、首先需要安装etcd&#xff1a; 解压缩etcd后执行以下命令&#xff1a; tar -xvf etcd-v3.…...

基于STM32 + DMA介绍,应用和步骤详解(ADC多通道)

前言 本篇博客主要学习了解DMA的工作原理和部分寄存器解析&#xff0c;针对ADC多通道来对代码部分&#xff0c;应用部分作详细讲解&#xff0c;掌握代码编程原理。本篇博客大部分是自己收集和整理&#xff0c;如有侵权请联系我删除。 本次博客开发板使用的是正点原子精英版&am…...

openGauss学习笔记-144 openGauss 数据库运维-例行维护-慢sql诊断

文章目录 openGauss学习笔记-144 openGauss 数据库运维-例行维护-慢sql诊断144.1 背景信息144.2 前提条件 openGauss学习笔记-144 openGauss 数据库运维-例行维护-慢sql诊断 144.1 背景信息 在SQL语句执行性能不符合预期时&#xff0c;可以查看SQL语句执行信息&#xff0c;便…...

计算机毕业设计springboot+ssm停车场车位预约系统java

管理员不可以注册账号 停车位包括车位所在楼层、车位编号、车位类型(全时间开放/高峰期开放)、预定状态等 用户预约时要求支付预约时间段的停车费用 违规行为&#xff1a;1.停车超过预约时间段 2.预约未使用 于系统的基本要求 &#xff08;1&#xff09;功能要求&am…...

打破常规思维:Scrapy处理豆瓣视频下载的方式

概述 Scrapy是一个强大的Python爬虫框架&#xff0c;它可以帮助我们快速地开发和部署各种类型的爬虫项目。Scrapy提供了许多方便的功能&#xff0c;例如请求调度、数据提取、数据存储、中间件、管道、信号等&#xff0c;让我们可以专注于业务逻辑&#xff0c;而不用担心底层的…...

系列学习前端之第 2 章:一文精通 HTML

全套学习 HTMLCSSJavaScript 代码和笔记请下载网盘的资料&#xff1a; 链接: https://pan.baidu.com/s/1-vY2anBdrsBSwDZfALZ6FQ 提取码: 6666 HTML 全称&#xff1a;HyperText Markup Language&#xff08;超文本标记语言&#xff09; 1、 HTML 标签 1. 标签又称元素&#…...

SCSS Module 这样处理配置和使用太赞了

SCSS Module 只是Scss和Css Module结合&#xff0c;可以利用SCSS对代码静态处理的能力&#xff0c;使得样式处理更强大一些&#xff0c;并不是什么新的东西&#xff0c;对比css-in-js和scoped&#xff0c;个人偏向喜欢Scss Module做样式隔离&#xff0c;先说一下优点&#xff1…...

【Unity动画】Unity 2D动画创建流程

本文以2D为案例&#xff0c;讲解Unity 播放动画的流程 准备和导入2D动画资源 外部导入序列帧生成的 Unity内部制作的 外部导入的3D动画 2.创建动画过程 打开时间轴Ctrl6 选中场景中的一个未来需要播放动画的物体 回到时间轴点击Create一个新动画片段 拖动2D动画资源放入…...

【算法每日一练]-图论(保姆级教程篇12 tarjan篇)#POJ3352道路建设 #POJ2553图的底部 #POJ1236校园网络 #缩点

目录&#xff1a; 今天知识点 加边使得无向图图变成双连通图 找出度为0的强连通分量 加边使得有向图变成强连通图 将有向图转成DAG图进行dp POJ3352&#xff1a;道路建设 思路&#xff1a; POJ2553&#xff1a;图的底部 思路&#xff1a; POJ1236校园网络 思路&#x…...

Python数据科学视频讲解:数据挖掘与建模的注意事项

1.7 数据挖掘与建模的注意事项 视频为《Python数据科学应用从入门到精通》张甜 杨维忠 清华大学出版社一书的随书赠送视频讲解1.7节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。内容涵盖数据科学应用的全流程&#xff0c;包括…...

unity | 动画模块之循环滚动选项框

一、作者的话 评论区有人问&#xff0c;有没有竖排循环轮播选项框&#xff0c;我就写了一个 二、效果动画 如果不是你们想要的&#xff0c;就省的你们继续往下看了 三、制作思路 把移动分成里面的方块&#xff0c;还有背景&#xff08;父物体&#xff09;&#xff0c;方块自…...

TinyMPC - CMU (卡耐基梅隆大学)开源的机器人 MPC 控制器

系列文章目录 CasADi - 最优控制开源 Python/MATLAB 库 文章目录 系列文章目录前言一、机器人硬件对比1.1 Teensy 上的微控制器基准测试1.2 机器人硬件1.3 BibTeX 二、求解器三、功能&#xff08;预期&#xff09;3.1 高效3.2 鲁棒3.3 可嵌入式3.4 最小依赖性3.5 高效热启动3.…...

C++ 对象的初始化和清理:构造函数和析构函数

目录 构造函数和析构函数 构造函数 析构函数 构造函数的分类及调用 括号法 显示法 隐式转换法 拷贝构造函数的调用时机 使用一个已经创建完毕的对象来初始化一个新对象 值传递的方式给函数参数传值 以值方式返回局部对象 构造函数调用规则 初始化列表 类对象作…...

Appium Android自动化环境四段链路深度验证指南

1. 这不是装几个软件就能跑起来的事&#xff1a;为什么90%的人卡在环境搭建第一步 “PythonAndroidAppium App自动化测试环境搭建”——光看标题&#xff0c;很多人第一反应是&#xff1a;不就是装Python、配JDK、下Android SDK、跑个appium命令&#xff1f;我试过三次&#x…...

随机森林与保形预测:构建可解释、可信赖的通胀预测模型

1. 项目概述&#xff1a;当机器学习遇见通胀预测通胀预测一直是宏观经济分析和货币政策制定的核心挑战。传统的计量经济学模型&#xff0c;如基于菲利普斯曲线的线性回归&#xff0c;在处理复杂、非线性的经济关系时常常力不从心&#xff0c;尤其是在经济结构发生转变或面临外部…...

ARM SME指令集与UMLSL指令深度解析

1. ARM SME指令集与向量处理概述在现代处理器架构中&#xff0c;向量处理技术已成为提升计算性能的关键手段。作为ARMv9架构的重要扩展&#xff0c;SME&#xff08;Scalable Matrix Extension&#xff09;指令集引入了革命性的矩阵运算能力&#xff0c;特别针对机器学习、数字信…...

告别手动拼图!用Unity TileMap的Fill Box和Picker工具,5分钟搞定复杂地形

告别手动拼图&#xff01;用Unity TileMap的Fill Box和Picker工具高效构建复杂地形在2D游戏开发中&#xff0c;地形设计往往是耗时又繁琐的环节。想象一下&#xff0c;你需要手动放置数百个草地、水域或砖块瓦片来构建游戏世界&#xff0c;这不仅容易出错&#xff0c;还会消耗大…...

保姆级教程:用阿里云镜像加速Unity Android依赖下载,搞定MAX+Admob集成

深度优化Unity安卓依赖下载&#xff1a;阿里云镜像加速MAX与AdMob集成实战国内Unity开发者在集成海外广告SDK时&#xff0c;最头疼的莫过于Gradle依赖下载缓慢甚至失败的问题。本文将手把手教你如何通过阿里云镜像仓库彻底解决这一痛点&#xff0c;同时串联Gradle版本管理、mai…...

ESPIM架构:稀疏计算与存内计算融合,突破边缘AI推理内存墙

1. 项目概述&#xff1a;当稀疏计算遇上存内计算在边缘设备上部署大型语言模型&#xff08;LLaMA、GPT等&#xff09;进行推理&#xff0c;正成为一个越来越普遍的需求。无论是出于隐私保护&#xff0c;还是为了应对有限的无线带宽&#xff0c;本地化推理都展现出巨大吸引力。然…...

避坑指南:在银河麒麟V10 ARM服务器安装JDK8,我踩过的那些雷(附Oracle账号问题解决)

银河麒麟V10 ARM服务器JDK8安装实战&#xff1a;从踩坑到精通的完整指南 第一次在银河麒麟V10 ARM架构服务器上安装JDK8的经历&#xff0c;让我深刻体会到什么叫做"理想很丰满&#xff0c;现实很骨感"。本以为和x86环境差不多的流程&#xff0c;却接连遭遇Oracle账号…...

AI agent案例汇总:基于 LangGraph 的智能对话 Agent 实现

实现了一个具备记忆功能和工具调用能力的智能对话 Agent&#xff0c;基于 LangChain 框架构建&#xff0c;可实现天气查询、数学运算两大核心功能&#xff0c;同时支持多轮对话记忆。代码中初始化了大模型并配置相关参数&#xff0c;通过装饰器定义工具函数&#xff0c;让 Agen…...

Windows关机修复机制:漏洞补丁静默安装原理与实操

1. 这不是“一键修复”&#xff0c;而是系统级补丁调度机制的落地实践很多人看到“360安全卫士漏洞修复全新升级”这个标题&#xff0c;第一反应是&#xff1a;又一个弹窗广告式功能更新。但如果你真点开设置页、翻过日志、对比过前后两次关机流程的系统行为&#xff0c;就会发…...

OpenClaw强势推出V2026.5.20版本地部署最新教程来啦!3分钟一键安装中文版可视化操作指南

凌晨两点&#xff0c;我刚把 OpenClaw 跑通。看着屏幕上终于亮起来的 WebChat 界面&#xff0c;心里那叫一个舒坦。说实话&#xff0c;之前装了几次都没成功&#xff0c;不是端口冲突就是 API Key 配置不对&#xff0c;折腾了大半天。后来静下心来把文档从头到尾看了一遍&#…...