[Linux] 进程间通信——匿名管道命名管道
标题:[Linux] 进程间通信——匿名管道&&命名管道
@水墨不写bug
(图片来源于网络)
目录
一、进程间通信
二、进程间通信的方案——匿名管道
(1)匿名管道的原理
(2)使用匿名管道
三、进程间通信的方案——命名管道
(1)认识管道文件
(2)使用命名管道
正文开始:
一、进程间通信
当你参加场竞赛,你一定需要与你的队友密切配合,这样才能高效的完成任务。然而,配合的前提是你们知道彼此现在的状况,就是说,你们需要尽可能的共享信息,而这一过程不就是通信吗?于是,得出结论:
配合的前提是通信。
一台计算机,是被操作系统管理着(操作系统是软硬件资源的管理者),而进程间由于具有独立性,体现为每个进程都有自己的进程地址空间,这就意味着多个进程之间相互的数据不可见(所有的数据,不论局部或者全局),于是想要实现进程间的相互通信,通常是比较困难的(成本比较高)。
图1(进程间具有独立性)
进程间通信的前提是让不同的进程看到同一份资源,这份资源(称为 "共享资源"),不是属于某一个进程,而是操作系统这个中间人提供的资源(本质就是一段内存)。
由于操作系统不相信任何人,于是操作系统提供了一系列的系统调用,用来创建共享资源。这同时也意味着:操作系统提供了很多接口,调用不同的接口,会创建不同类型的共享资源。这些不同的共享资源就有:
管道(包括匿名管道、命名管道)、SystemV IPC的共享内存、消息队列、信号量。
本文要讲解的就是头一种进程间通信的方式:管道。
二、进程间通信的方案——匿名管道
(1)匿名管道的原理
进程打开文件时,发生了什么?
当进程以读或者的方式打开一个文件的时候,操作系统会在内存中创建一个结构体——struct file,这个结构体用来维护被打开的文件:
标准输入,标准输出,标准错误被默认打开(文件结构体数组——fd数组的0,1,2被默认的三个“文件”占用):
图2(进程与被打开的文件对应创建的结构体)
这时,如果进程B以读的方式打开一个文件:比如调用了C的fopen函数以r的方式打开,具体结果就会成为这样:
此时,再以w方式打开同一个文件:
(以读方式打开文件后,再次以写方式打开,会创建一个专门用于write的structfile,但文件的内核级数据会沿用read structfile的同一份)——这是匿名管道的基本原理条件。
此时fork创建子进程,子进程会“共享”父进程的代码和数据(包括fd_array),于是,可以表示为:
如果让父进程关闭r,子进程关闭w,那么: 这样,不酒满足两个进程看到同一份内核级缓冲区了吗?
这就是匿名管道的原理。
(2)使用匿名管道
头文件:<unistd.h>
函数原型:
使用:
调用pipe时,传入一个数组类型int [2],将带出两个文件fd,一个是读fd ,下标为[0],一个是写fd,下标为[1]。这两个fd就是匿名管道内核级缓冲区的fd,由于匿名管道没有文件路径和文件名,所以称为“匿名管道”。
注意:
匿名管道只能用于进行具有血缘关系的进程之间进行通信,常用于父子进程之间进行通信。
管道内部,自带进程之间的同步机制。
管道文件的生命周期随进程。
管道文件在通信的时候,是面向字节流的,write次数和read次数不是一一匹配的。
管道的通信模式,是特殊的半双工模式。
使用时,四种特殊情况:
管道文件为空 && write fd没有关闭,读条件不具备,读进程被阻塞,直到pipe内有数据。
管道文件被写满 && read fd 不读但是没有关闭,管道已满,写进程被阻塞,直到pipe内有空间。
管道一直在读 && 写 fd被关闭,读fd读到0,表示读到了文件结尾。
read fd关闭 ,write fd没有关闭,若再写入数据,write会被OS以SIGPIPE信号终止。
三、进程间通信的方案——命名管道
由于匿名管道的缺陷是只能让两个具有血缘关系的进程通信,命名管道就是为了解决这样的问题而设计的。
(1)认识管道文件
通过指令 mkfifo + 文件名 可以创建管道文件,文件类型为p:
这就是管道文件,这样的文件具有确定的路径和文件名,所以就称为“命名管道”。这个文件对应匿名管道的内核级缓冲区。这就意味着,原理虽然和匿名管道不完全相同,但是思路完全一致,这里不再赘述。
(2)使用命名管道
创建管道文件,两种方法:
1.指令mkfifo + 管道文件名称
2.使用系统封装后的接口:
头文件:
函数原型:
返回值就是命名管道的fd;如果创建失败,返回-1,错误吗被设置。
删除管道文件,两种方法:
1.指令方法
rm + 文件名 / unlink + 文件名
2.使用系统封装的接口
到这里,你或许对管道的使用还有一些迷惑,通过下面的这一个小项目,或许你会对进程间通信的方案——管道有一个更深入的理解:
项目:简单的sever和client之间的通信,通给C++的封装来尽量简化代码的逻辑,尽可能规范:
namedPipe.h:
#pragma once#include<iostream> #include<unistd.h> #include<string> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h>using std::cout; using std::endl;const std::string comPath = "./myNamedPipe";enum WHO {//文件操作符的默认值defaultFd = -1,//标识调用者的身份sever = 0,client = 1,//读取namedPipe的一次读入数据的大小:bytesBaseSize = 4096 };//管理命名管道的类,不同的身份的人调用会产生不同的效果 //serer管理命名管道的生命周期,client只负责使用管道 class NamedPipe { private:bool OpenNamedPipe(int openstyle){//把得到的fd交给成员变量_fd即可_fd = open(comPath.c_str(),openstyle);if(_fd < 0){perror("open namedpipe fail!");exit(1);}return true;} public:NamedPipe(const std::string& path,int who):_pipePath(path),_who(who),_fd(defaultFd){//sever需要创建命名管道//cilent则什么都不需要做if(who == sever){int res = mkfifo(comPath.c_str(),0666);if(res < 0){perror("sever mkfifo fail!");exit(1);}cout<<"sever mkfifo success!"<<endl;}}bool OpenForRead(){return OpenNamedPipe(O_RDONLY);}bool OpenForWrite(){return OpenNamedPipe(O_WRONLY);}//通过stl的string为载体来写入,s为输入型参数int Write(const std::string &s){int res = write(_fd,s.c_str(),s.size());//如果出错,打印错误信息,终止进程//如果正确,返回写入数据的字节数if(res < 0){perror("read fail!");exit(1);}return res;}//通过stl的string为载体来输出,s为输出型参数int Read(std::string *s){char buf[BaseSize] = {0};int res = read(_fd,buf,BaseSize);*s = buf;//如果出错,打印错误信息,终止进程//如果正确,返回读取的数据的字节数if(res < 0){perror("read fail!");exit(1);}return res;}~NamedPipe(){if(_who == sever){int res = unlink(comPath.c_str());if(res < 0){perror("unlink fail!");exit(1);}if(_fd != defaultFd){close(_fd);}}}private:const std::string _pipePath;//命名管道的路径,便于不同进程找到命名管道int _who;//身份int _fd;//namedpipe的文件描述符 };
sever.cc:
#include "namePipe.hpp"// 一般可以看着namePipe的头文件来使用头文件内部的接口 // 也就是说 // sever等的enum常量的声明是可以被看到的,所以sever的直接使用并不突兀 // 但是namePipe被写为 hpp = .h + .cc// 服务端,读取数据,管理namedPipe int main() {// 通过类来管理namePipe,出作用域自动析构NamedPipe fifo(comPath.c_str(), sever);if (fifo.OpenForRead()){while (true){std::string s;int n = fifo.Read(&s);cout << n << ":" << s.c_str() << endl;}}return 0; }
client.cc:
#include "namePipe.hpp"// 客户端,写入数据 int main() {NamedPipe fifo(comPath.c_str(), client);if (fifo.OpenForWrite()){std::string s("I am process A");while (true){sleep(1);int n = fifo.Write(s);cout<<n<<" bytes writen "<<endl;}}return 0; }
makefile:
.PHONY:all all:sever client sever:sever.ccg++ -g -o $@ $^ -std=c++11 client:client.ccg++ -g -o $@ $^ -std=c++11.PHONY:clean clean:rm -rf sever client
完~
未经作者同意禁止转载
相关文章:
[Linux] 进程间通信——匿名管道命名管道
标题:[Linux] 进程间通信——匿名管道&&命名管道 水墨不写bug (图片来源于网络) 目录 一、进程间通信 二、进程间通信的方案——匿名管道 (1)匿名管道的原理 (2)使用匿名管道 三、进…...
人机交互中的状态交互、趋势交互
在人机交互中, 状态交互 和 趋势交互 是两种重要的交互方式,它们分别涉及到用户与系统之间不同的交互模型和机制。 1. 状态交互 状态交互主要聚焦于用户与系统之间的状态转换及其反馈机制。在这种交互模式下,系统会根据用户的输入或行为发生状…...
基于Java Springboot房屋租赁App且微信小程序
一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 微信…...
golang的wails框架在macos下的问题
1、前言 之前练手写了格调用ollama api的web应用,想找个容器打包下,于是找到wails来打包,windows下都是很正常的,因为就是普通的http调用,也没遇到cors跨域问题,但是到了macos下使用wails dev命令启动的客户…...
编程设计模式助记顺口溜
1、顺口溜 创建型,工厂多,单例建对象,抽象工厂做。建造者分步做,原型克隆最不愁。 结构型,适配器,桥接组合都不错,装饰外观飞享元,代理再添一把火。 行为型,责任链&…...
java网络通信(三):TCP通信、实现客户端-服务端消息通信
目录 1、什么是 TCP协议? 2、代码实现TCP协议的一发一收 2.1、客户端 2.2、服务端 2.3 结果演示 3、代码实现TCP协议的多发多收 3.1 客户端 3.2 服务端 3.3 结果演示 简介:本文章主要是演示如何用java代码以及TCP协议实现网络通信,实…...
mybatis-plus 对于属性为null字段不更新
MyBatis-Plus 默认情况下会根据字段的值是否为 null 来决定是否生成对应的 UPDATE 语句。这是由 更新策略 决定的,默认的行为是 忽略 null 值,即如果字段值为 null,该字段将不会出现在 UPDATE 语句中。 默认行为分析 MyBatis-Plus 默认的 Fi…...
GAGAvatar: Generalizable and Animatable Gaussian Head Avatar 学习笔记
1 Overall GAGAvatar(Generalizable and Animatable Gaussian Avatar),一种面向单张图片驱动的可动画化头部头像重建的方法,解决了现有方法在渲染效率和泛化能力上的局限。 旋转参数 现有方法的局限性: 基于NeRF的方…...
《数据挖掘:概念、模型、方法与算法(第三版)》
嘿,数据挖掘的小伙伴们!今天我要给你们介绍一本超级实用的书——《数据挖掘:概念、模型、方法与算法》第三版。这本书是数据挖掘领域的经典之作,由该领域的知名专家编写,系统性地介绍了在高维数据空间中分析和提取大量…...
springboot vue 开源 会员收银系统 (12)购物车关联服务人员 订单计算提成
前言 完整版演示 http://120.26.95.195/ 开发版演示 http://120.26.95.195:8889/ 在之前的开发进程中,我们完成订单的挂单和取单功能,今天我们完成购物车关联服务人员,用户计算门店服务人员的提成。 1.商品关联服务人员 服务人员可以选择 一…...
lua闭包Upvalue
闭包 lua任何函数都是闭包,闭包至少带1个upValue; CClosure是使用Lua提供的lua_pushcclosure这个C-Api加入到虚拟栈中的C函数,它是对LClosure的一种C模拟 如string.gmatch就是cclosure 定义: #define ClosureHeader \CommonH…...
下载maven 3.6.3并校验文件做md5或SHA512校验
一、下载Apache Maven 3.6.3 Apache Maven 3.6.3 官方下载链接: 二进制压缩包(推荐): ZIP格式: https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zipTAR.GZ格式: https://archive.apache.org/dist/…...
深入探索Flax:一个用于构建神经网络的灵活和高效库
深入探索Flax:一个用于构建神经网络的灵活和高效库 在深度学习领域,TensorFlow 和 PyTorch 作为主流的框架,已被广泛使用。不过,Flax 作为一个较新的库,近年来得到了越来越多的关注。Flax 是一个由Google Research团队…...
vue项目中单独文件的js不存在this.$store?.state怎么办
在Vue项目中,如果你在单独的文件(比如插件、工具函数等)中遇到this.$store不存在的情况,这通常是因为this上下文不指向Vue实例,或者Vuex store没有被正确地注入到Vue实例中。以下是几种可能的解决方案: 确保…...
物联网客户端在线服务中心(客服功能/私聊/群聊/下发指令等功能)
一、界面 私聊功能(下发通知类,一对多)群聊(点对点)发送指令(配合使用客户端,基于cefsharp做的物联网浏览器客户端)修改远程参数配置(直接保存到本地)&#…...
AI开发:逻辑回归 - 实战演练- 垃圾邮件的识别(二)
接上一篇AI开发:逻辑回归 - 实战演练- 垃圾邮件的识别(一) new_email 无论为什么文本,识别结果几乎都是垃圾邮件,因此我们需要对源码的逻辑进行梳理一下: 在代码中,new_email 无论赋值为何内容都被识别为…...
hint: Updates were rejected because the tip of your current branch is behind!
问题 本地仓库往远段仓库推代码时候提示: error: failed to push some refs to 192.168.2.1:java-base/java-cloud.git hint: Updates were rejected because the tip of your current branch is behind! refs/heads/master:refs/heads/master [rejected] (…...
Vue的数据驱动原理
文章目录 什么是数据驱动那么vuejs是如何实现这种数据驱动的呢?对getter/setter的理解?一个简单的演示例子vue数据驱动原理是:采用数据劫持结合发布者和订阅者模式,通过“object.defineproperty()”来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发相应…...
【Db First】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...
数据分析-52-时间序列分解之变分模态分解VMD
文章目录 1 时间序列模态分解1.1 模态分解的概念1.2 模态分解的作用1.3 常用的模态分解方法1.4 模态分解的常用库2 变分模态分解VMD2.1 VMD的流程2.2 加载数据集2.2.1 数据重采样2.2.2 原始数据可视化2.3 VMD变分模态分解3 参考附录1 时间序列模态分解 1.1 模态分解的概念 时…...
做异端中的异端 -- Emacs裸奔之路4: 你不需要IDE
确切地说,你不需要在IDE里面编写或者阅读代码。 IDE用于Render资源文件比较合适,但处理文本,并不划算。 这的文本文件,包括源代码,配置文件,文档等非二进制文件。 先说说IDE带的便利: 函数或者变量的自动…...
redhat 7.9配置阿里云yum源
1、mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ 2、添加dns vim/etc/resolv.conf nameserver 8.8.8.8 nameserver 8.8.4.4 nameserver 114.114.114.114 #配置完先检查下通不通 3、vi /etc/yum/pluginconf.d/subscription-manager.conf # 将 “enabled1” 改为 “ena…...
简单快速的上手python
前言 python是一门可以快速上手的语言,原因是它语法简单,api容易使用自由灵活 当我们需要安装任何的三方库时,只需要执行 pip install XX 之后在代码里面import xxx就可以使用python啦。 并且python的代码自由灵活,使用缩进区…...
PHP和GD如何给图片添加模糊边缘效果
在PHP中,使用GD库给图片添加模糊边缘效果通常涉及几个步骤,包括加载图片、创建模糊效果、应用边缘处理以及保存结果图片。然而,GD库本身并不直接提供边缘模糊的函数,但你可以通过一些技巧来实现类似的效果。 以下是一个简化的步骤…...
PowerShell:查找并关闭打开的文件
Get-SmbOpenFile 打开 Windows PowerShell 并运行 Get-SmbOpenFile | Format-List 若要仅显示特定文件共享的连接,请使用 Where-Object 运行 Get-SmbOpenFile。 Get-SmbOpenFile | Where-Object Path -eq "C:\Data\" | Format-List Get-SmbSession 显…...
SQL进阶技巧:非等值连接--单向近距离匹配
目录 0 场景描述 1 数据准备 2 问题分析 编辑 编辑 3 小结 数字化建设通关指南 0 场景描述 表 t_1 和表 t_2 通过 a 和 b 关联时,有相等的取相等的值匹配,不相等时每一 个 a 的值在 b 中找差值最小的来匹。 表 t_1:a 中无重复值 表 t_1:a 中无重复值 a 1 2 4 …...
【golang】单元测试,以及出现undefined时的解决方案
单元测试 要对某一方法进行测试时,例如如下这一简单减法函数,选中函数名后右键->转到->测试 1)Empty test file 就是一个空文件,我们可以自己写测试的逻辑 但是直接点绿色箭头运行会出问题: 找不到包。我们要在…...
代理IP地址的含义与设置指南
在数字化时代,互联网已经成为我们日常生活不可或缺的一部分。然而,在享受互联网带来的便利的同时,我们也面临着隐私泄露、访问限制等问题。代理IP地址作为一种有效的网络工具,能够帮助我们解决这些问题。本文将详细介绍代理IP地址…...
Qt 2D绘图之三:绘制文字、路径、图像、复合模式
参考文章链接: Qt 2D绘图之三:绘制文字、路径、图像、复合模式 绘制文字 除了绘制图形以外,还可以使用QPainter::darwText()函数来绘制文字,也可以使用QPainter::setFont()设置文字所使用的字体,使用QPainter::fontInfo()函数可以获取字体的信息,它返回QFontInfo类对象…...
el-table 纵向 横向 多级表头
<el-table :data"tableData" class"diaTable":span-method"handleSpanMethod"border:header-cell-style"{background:#292929,color:#fff}"><!-- 纵向表头 --><el-table-column label"纵向表头" width"…...
linux perf安装问题解决
WARNING: perf not found for kernel 4.15.0-39 perf安装问题 perf是一个功能强大的linux性能分析工具,其功能依赖于内核,安装perf工具的版本必须与内核版本保持一致。 perf安装问题 使用apt 安装 perf包,运行时提示要安装与内核版本相一致…...
嵌入式Linux无窗口系统下搭建 Qt 开发环境
嵌入式Linux无窗口系统下搭建 Qt 开发环境 本文将介绍如何在树莓派的嵌入式 Linux 环境下,搭建 Qt 开发环境,实现无窗口系统模式(framebuffer)下的图形程序开发。 1. 安装 Qt 环境 接下来,安装核心 Qt 开发库以及与 …...
JSON vs 表单格式:两种常见请求格式的区别与应用
搞iOS UI 自动化的同时涉及到了给后端发送请求,请求数据的格式常用的有json格式和表单格式,这两种格式如何区分,如何使用,特此总结了一下。 表单格式(Form Data) 传统的 HTML 表单使用的请求体格式&#…...
通过torch.utils.data.DataLoader可提高深度学习的10倍运行的速度?
引言 在深度学习的训练过程中,数据加载是一个关键步骤,它直接影响到模型训练的效率。为了提高运行速度,我们通常会采用多种方法,比如数据预处理、多线程加载、缓存策略等。然而,有一个经常被忽视的优化点——调整torc…...
【QT】背景,安装和介绍
TOC 目录 背景 GUI技术 QT的安装 使用流程 QT程序介绍 main.cpp编辑 Wiget.h Widget.cpp form file .pro文件 临时文件 C作为一门比较古老的语言,在人们的认知里始终是以底层,复杂和高性能著称,所以在很多高性能需求的场景之下…...
计算机网络:IP协议详细讲解
目录 前言 一、IP网段划分 二、IP报头 三、解决IP地址不足-->NAT技术 前言 在之前,我们学习了传输层中的TCP和UDP,重点是TCP协议,他帮我们解决具体到主机的哪个应用(端口)、传输的可靠(序列号、校验和…...
Python中使用pip换源的详细指南
在Python开发过程中,我们经常需要安装各种第三方库。pip是Python的包管理工具,用于安装和管理Python库。然而,由于网络原因,有时访问默认的Python包索引(PyPI)可能会比较慢。这时,我们可以通过更…...
【Unity】WebGL全屏问题
1 前言 WebGL项目打包时不可避免的需要面对全屏化问题,或者说是占满网页的问题。这里讨论一下此问题。 2 全屏化 2.1 打包模板 WebGL在打包时可以选择不同的打包模板,其会影响最终打包好的项目在网页中的展现形式。可以在“Project Setting/Player/Set…...
基于大数据python 电商数据分析及推荐可视化系统(源码+LW+部署讲解+数据库+ppt)
!!!!!!!!! 很对人不知道选题怎么选 不清楚自己适合做哪块内容 都可以免费来问我 避免后期給自己答辩找麻烦 增加难度(部分学校只有一次答辩机会 没弄好就延迟…...
基于大数据python 热门微博数据分析可视化系统(源码+LW+部署讲解+数据库+ppt)
!!!!!!!!! 很对人不知道选题怎么选 不清楚自己适合做哪块内容 都可以免费来问我 避免后期給自己答辩找麻烦 增加难度(部分学校只有一次答辩机会 没弄好就延迟…...
MATLAB R2024b软件下载安装教程
软件版本: MATLAB R2024b 软件大小:24G 安装环境:Windows 10/11(64位) 界面语言:简体中文 软件下载:https://pan.xunlei.com/s/VOCut9-UJcX7k3AO7IGXobAiA1?pwdkqkr# 软件参考安装教程 1、使用网盘…...
机器学习算法(六)---逻辑回归
常见的十大机器学习算法: 机器学习算法(一)—决策树 机器学习算法(二)—支持向量机SVM 机器学习算法(三)—K近邻 机器学习算法(四)—集成算法 机器学习算法(五…...
Pareidoscope - 语言结构关联工具
文章目录 关于 Pareidoscope安装使用方法输入格式语料库查询 将语料库转换为 SQLite3 数据库两种语言结构之间的关联简单词素分析关联共现和伴随词素分析相关的更大结构可视化关联结构 关于 Pareidoscope Pareidoscope 是一组 用于确定任意语言结构之间 关联的工具,…...
Java中 HttpURLConnection 和 HttpClient 详解(初学者友好)
Java中HttpURLConnection和HttpClient详解(初学者友好) 在Java开发中,向服务器发送HTTP请求是常见的需求,比如调用API接口或获取远程数据。在JDK中,主要有两种方式实现HTTP通信: 使用 HttpURLConnection&…...
vulnhub-LUPINONE-靶场复盘-题解
靶机的下载连接https://download.vulnhub.com./empire/01-Empire-Lupin-One.zip 下载镜像后解压,然后导入到vmware中,使用的是nat模式 kali的ip地址:10.10.1.128 靶机ip地址:10.10.1.135 1.扫描靶机ip地址 命令:n…...
diff算法
vue的diff算法详解 vue: diff 算法是一种通过同层的树节点进行比较的高效算法 其有两个特点: 比较只会在同层级进行, 不会跨层级比较 在diff比较的过程中,循环从两边向中间比较 diff 算法在很多场景下都有应用,在 vue 中&…...
通过异步使用消息队列优化秒杀
通过异步使用消息队列优化秒杀 同步秒杀流程异步优化秒杀异步秒杀流程基于lua脚本保证Redis操作原子性代码实现阻塞队列的缺点 同步秒杀流程 public Result seckillVoucher(Long voucherId) throws InterruptedException {SeckillVoucher seckillVoucher iSeckillVoucherServi…...
项目整合logback日志打印线程id
项目打印日志能帮助我们解决很多的问题,提示我们出现的问题,通过日志我们可以准确的定位问题快速找到问题点解决问题。 <?xml version"1.0" encoding"UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO &l…...
WEB开发: 丢掉包袱,拥抱ASP.NET CORE!
今天的 Web 开发可以说进入了一个全新的时代,前后端分离、云原生、微服务等等一系列现代技术架构应运而生。在这个背景下,作为开发者,你一定希望找到一个高效、灵活、易于扩展且具有良好性能的框架。那么,ASP.NET Core 显然是一个…...
爬虫专栏第一篇:深入探索爬虫世界:基础原理、类型特点与规范要点全解析
本专栏会对爬虫进行从0开始的讲解,每一步都十分的细致,如果你感兴趣希望多多点赞收藏关注支持 简介:文章对爬虫展开多方面剖析。起始于爬虫的基本概念,即依特定规则在网络抓取信息的程序或脚本,在搜索引擎信息提取上作…...