【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)

目录

概述:

1. 阻塞IO (Blocking IO)

2. 非阻塞IO (Non-blocking IO)

3. IO多路复用 (I/O Multiplexing)

4. 信号驱动IO (Signal-driven IO)

阻塞式IO

非阻塞式IO

信号驱动IO(Signal-driven IO)

信号IO实例:

IO多路复用 (I/O Multiplexing)

头文件

声明

功能

参数

返回值

超时时间结构体

Select宏函数

基本流程

Select的特点与限制

规则

select实例:

Poll函数详解

特点

流程

声明与头文件

功能

参数

结构体pollfd

返回值

优势与局限

Poll 实例:

epoll:高效事件驱动的I/O模型

特点对比

epoll机制概览

epoll的使用步骤

函数接口

epoll_create

epoll_ctl

epoll_wait

注意事项

epoll 实例:

三者的特点以及区别

网络超时检测

使用网络超时事件检测的原因:

10.1 函数的参数可以设置超时

10.1.1 select 超时检测

10.1.2 poll超时检

10.1.3 epoll超时检测 -epoll也可以实现超时时间检测

10.2 setsockopt 设置套接字属性

10.2.1 socket属性

10.3.1 sigaction 修改信号的行为


概述:

在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:

1. 阻塞IO (Blocking IO)

阻塞IO是最传统的IO模型。当一个进程发起一个IO请求时,比如读或写操作,如果数据尚未准备好(例如在读操作中,数据尚未到达),那么这个进程会被挂起,直到数据准备好为止。这意味着进程在此期间不能做任何其他事情,直到IO操作完成。这是由于在内核态和用户态之间的切换,内核必须完成IO操作并将控制权交回给用户态的应用程序。

2. 非阻塞IO (Non-blocking IO)

非阻塞IO与阻塞IO的主要区别在于,当IO操作未完成时,进程不会被挂起。相反,如果数据尚未准备好,系统调用会立即返回一个错误。这允许应用程序检查错误并立即进行下一次尝试,而不是等待数据准备好。然而,这通常意味着应用程序需要不断轮询,直到数据可用,这可能会导致不必要的CPU使用。

3. IO多路复用 (I/O Multiplexing)

IO多路复用模型允许一个单一的进程同时监听多个文件描述符(如网络套接字)的IO事件。当其中一个文件描述符准备好进行IO操作时,应用程序会被通知。这通常通过select(), poll(), 或 epoll()等系统调用来实现。这些函数会阻塞,直到至少有一个文件描述符准备好,然后返回,允许应用程序处理那些已经准备好的描述符。这种方式大大提高了处理多个并发连接的效率。

4. 信号驱动IO (Signal-driven IO)

信号驱动IO是一种异步IO机制,它允许应用程序在数据准备好时通过信号通知来处理IO事件。这种模型特别适合于多路复用场景,尤其是当处理大量并发连接时。

阻塞式IO
  • 特点:最简单,最常用,但是效率低。
  • 当前学习函数
    • 读阻塞: readrecvrecvfrom
    • 写阻塞: writesendacceptconnect
    • TCP:  有链接  :  有发送缓存区,有接收缓存区
      UDP:  无连接  :  没有发送缓存区,但是有接受缓存区 (不会出现TCP粘包)
非阻塞式IO
  • 特点:避免了长时间等待,但可能频繁检查资源状态,浪费CPU资源。
fcntl函数
声明: int fcntl (int fd, int cmd,  ...arg);
头文件: #include<fcntl.h> #include<unistd.h>
功能:设置文件描述符的属性
参数:fd:文件描述符
         cmd: 操作功能选项 (可以定义个变量,通过vi -t F_GETFL 来找寻功能赋值 )
          F_GETFL:获取文件描述符的状态信息 
               //不需要第三个参数,返回值为获取到的属性
          F_SETFL:设置文件描述符的状态信息 - 需要填充第三个参数
             //需要填充第三个参数  O_RDONLY, O_RDWR ,O_WRONLY ,O_CREAT
                                                 O_NONBLOCK 非阻塞   O_APPEND追加
                                                  O_ASYNC 异步   O_SYNC  同步 
                                               O_NOATIME 读取文件时不更新文件访问时间
         arg:文件描述符的属性   如果需要设置文件描述符的状态,则需要该参数
返回值: 特殊选择:根据功能选择返回 (int 类型)   
            其他:  成功0   失败: -1;

使用:  int flag;
 // 1.获取该文件描述符0 (标准输入) 的原属性 :标准输入原本具有阻塞的功能  
int flag = fcntl(0, F_GETFL); //获取文件描述符原有信息后,保存在flag变量内
 // 2.修改对应的位nonblock(非阻塞)
int flag |= O_NONBLOCK;  ( flag = flag | O_NONBLOCK)
 // 3. 将修改好的属性写回去 (0 标准输入 -- 阻塞  改为  非阻塞)
 fcntl (0, F_SETFL, flag); //文件描述符   设置状态  添加的新属性
信号驱动IO(Signal-driven IO)
  • 特点异步通知模式, 需要底层驱动的支持
//1.设置将APP进程号提交给内核驱动
fcntl(fd,F_SETOWN,getpid());//F_SETOWN将进程号交给内核驱动  
                            //getgid 进程号
//2.设置异步通知
    int flags;
    flags = fcntl(fd, F_GETFL); //获取原属性
    flags |= O_ASYNC;       //设置异步   O_ASUNC 通知
    fcntl(fd, F_SETFL, flags);  //修改的属性设置进去
//3.signal捕捉SIGIO信号 --- SIGIO:信号驱动,自定义信号驱动
signal(SIGIO,handler);

头文件: #include <signal.h>
       typedef void (*sighandler_t)(int);
       sighandler_t   signal(int signum, sighandler_t handler)
功能:信号处理函数(注册信号)
参数: int signum:要处理的信号(要修改的信号)
      sighandler_t handler: 函数指针: void(*handler)(int) (修改的功能:)
      SIG_IGN:忽略该信号。
      SIG_DFL:采用系统默认方式处理信号。
      handler:------void handler(int num) 自定义的信号处理函数指针
返回值:成功:设置之前的信号处理方式
失败:SIG_ERR
信号IO实例:

操作鼠标设备,当有输入的时候获取输入数据,没有输入时循环输出hello world。

IO多路复用 (I/O Multiplexing)
头文件

C

#include<sys/select.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
声明

C

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);
功能

select函数用于监测一组文件描述符的IO事件,直到其中一个或多个描述符就绪或超时为止。

参数
  • nfds:最大的文件描述符加一,即监测的最大文件描述符数量。
  • readfds:读就绪描述符集。
  • writefds:写就绪描述符集(可为NULL)。
  • exceptfds:异常就绪描述符集(可为NULL)。
  • timeout:超时时间,为NULL则无限期阻塞等待。
返回值
  • <0:错误。
  • >0:有事件产生。
  • ==0:超时。
超时时间结构体

C

struct timeval {
   long tv_sec; // 秒
   long tv_usec; // 微秒
};
Select宏函数
  • FD_CLR(fd, set): 清除描述符fd在集合set中的状态。
  • FD_ISSET(fd, set): 判断fd是否在set集合中产生事件。
  • FD_SET(fd, set): 将fd加入到集合set中。
  • FD_ZERO(set): 清空集合set
基本流程
  1. 构建文件描述符集合。
  2. 清空集合。
  3. 添加关心的文件描述符。
  4. 调用select
  5. 检查产生事件的文件描述符。
  6. 执行相应的逻辑处理。
Select的特点与限制
  • 最多监听1024个文件描述符(千级别)。
  • 被唤醒后需重新轮询所有描述符,效率较低。
  • 每次调用select会清空描述符集合,需频繁拷贝用户空间到内核空间,效率低下。
规则
  • 监测范围通常为0至1023。
  • 标准输入、输出、错误分别占据0、1、2三个文件描述符。
  • 最大监测文件描述符数量为fd+1
  • 事件产生时,对应描述符在集合中会被置1,未产生事件的置0。
  • select调用后会清空集合,需在调用前备份集合以优化性能。
select实例:

同时检测键盘输入和sockfd事件 -TCP实现同时连接多个客户端

Poll函数详解

特点
  1. 动态文件描述符个数:根据poll函数的第一个参数确定,提供了比select更灵活的文件描述符数量控制。
  2. 轮询效率:虽然被唤醒后仍需遍历所有描述符,但无需像select那样每次调用都重建或清空文件描述符集合,仅需一次从用户空间到内核空间的数据拷贝,效率相对较高。
流程
  1. 创建pollfd结构体数组。
  2. 配置每个结构体的文件描述符及其关注的事件。
  3. 记录数组中最后一个有效元素的下标。
  4. 调用poll函数进行事件监测。
  5. 遍历数组,检查哪些文件描述符产生了事件。
  6. 根据触发的事件执行相应的处理逻辑。
声明与头文件

C

1int poll(struct pollfd *fds, nfds_t nfds, int timeout);
2#include <poll.h>
功能

poll函数用于监视并等待多个文件描述符的属性变化,直到其中一个或多个描述符就绪或超时为止。

参数
  • fds:关心的文件描述符数组。
  • nfds:数组中有效元素的数量。
  • timeout:超时时间(毫秒)。-1为无限期阻塞,0为非阻塞。
结构体pollfd

C

1struct pollfd {
2   int fd;         // 文件描述符
3   short events;   // 关注的事件类型
4   short revents;  // 实际发生的事件
5};
返回值
  • <0:错误。
  • >0:有事件产生。
  • ==0:超时时间已到。
优势与局限
  • 优势:不受1024文件描述符限制,无需每次调用都重设或清空集合,提高了处理大量描述符的效率。
  • 局限:被唤醒后仍需遍历所有描述符,可能在高并发场景下影响性能。
Poll 实例:

epoll:高效事件驱动的I/O模型

特点对比
  • select 和 poll:同步轮询模型,逐一检查所有文件描述符的就绪状态。
  • epoll:异步事件驱动模型,基于事件的触发机制,只处理真正就绪的文件描述符,极大提升了效率。
epoll机制概览
  1. 红黑树:用于高效管理大量文件描述符,每个节点是一个文件描述符及其相关属性。
  2. 链表:事件链表,当文件描述符上的事件发生时,通过回调机制将其添加到链表中,供后续处理。
epoll的使用步骤
  1. 创建epoll实例(红黑树的根节点)。
  2. 注册、修改或删除文件描述符及事件监听。
  3. 阻塞等待事件,一旦有事件产生,进行处理。
函数接口
epoll_create

C

1int epoll_create(int size);
  • 功能:创建epoll实例,即红黑树的根节点。
  • 返回值:成功返回epoll文件描述符,失败返回-1。
epoll_ctl

C

1int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 功能:控制epoll实例,包括添加、修改和删除文件描述符的监听事件。
  • 参数
    • epfd:epoll文件描述符。
    • op:操作类型。
    • fd:目标文件描述符。
    • event:事件结构体。
  • 返回值:成功返回0,失败返回-1。
epoll_wait

C

1int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • 功能:等待并获取就绪事件。
  • 参数
    • epfd:epoll文件描述符。
    • events:事件集合,用于接收就绪事件。
    • maxevents:单次调用最多返回的事件数量。
    • timeout:超时时间(毫秒)。
  • 返回值:成功返回实际发生的事件数量,失败返回-1。
注意事项
  • epoll的效率远高于select和poll,尤其在处理大量并发连接时。
  • epoll的文件描述符上限受系统限制,一般远大于1024,可达数十万。
  • epoll的事件处理机制使得它非常适合构建高并发的网络服务器。
epoll 实例:

三者的特点以及区别

网络超时检测

使用网络超时事件检测的原因:

  1)   避免进程在没有数据时无限制的阻塞。

        2)当设定的时间到, 进程从原操作进行返回,然后继续执行

10.1 函数的参数可以设置超时
10.1.1 select 超时检测
头文件:  #include<sys/select.h>   #include<sys/time.h>   
              #include<sys/types.h>   #include<unistd.h>

声明:    int select(int nfds, fd_set *readfds, fd_set *writefds,\
                                                             fd_set *exceptfds, struct timeval *timeout);

功能:监测是哪些文件描述符产生事件;,阻塞等待产生.

参数:nfds:    监测的最大文件描述个数(文件描述符从0开始,这里是个数,记得+1)
         readfds:  读事件集合;        // 键盘鼠标的输入,客户端连接都是读事件
         writefds: 写事件集合;        //NULL表示不关心
         exceptfds:异常事件集合;  //NULL 表示不关心
         timeout:   超时检测           //如果不做超时检测:传 NULL
超时时间检测: 当程序执行到该语句时,我们设定好时间,如果规定时间   内未完成函数功能, 返回一个超时的信息,我们可以根据该信息设定相应需求;

返回值:  <0 出错            >0 表示有事件产生;
               ------------  如果设置了超时检测时间:&tv  ------------
         <0 出错            >0 表示有事件产生;      ==0 表示超时时间已到;        

超时时间检测的结构体如下:                     
            struct timeval {
               long    tv_sec;         以秒为单位,指定等待时间
               long    tv_usec;        以毫秒为单位,指定等待时间  1s = 1000us
           };
          struct timespec {
               long    tv_sec;        以秒为单位
               long    tv_nsec;       以纳秒为单位  1s = 1000000ns
           };

10.1.2 poll超时检
声明:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
头文件: #include<poll.h>
功能: 监视并等待多个文件描述符的属性变化
参数:
1. struct pollfd *fds:   关心的文件描述符数组,大小自己定义
若想检测的文件描述符较多,则建立结构体数组struct pollfd fds[N]; 
           struct pollfd{
	                  int fd;	 //文件描述符
	             short events;	//等待的事件触发条件----POLLIN读时间触发
	             short revents;	//实际发生的事件(未产生事件: 0 ))
                }
2.  nfds:    最大文件描述符个数
3.  timeout: 超时检测 (毫秒级):1000 == 1s      如果-1,阻塞     如果0,不阻塞

返回值:  <0 出错		>0 表示有事件产生;
              如果设置了超时检测时间:&tv
              <0 出错		>0 表示有事件产生;	      ==0 表示超时时间已到;

10.1.3 epoll超时检测 -epoll也可以实现超时时间检测
声明: int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:等待事件的产生,类似于select的用法
参数: 	epfd:句柄;
		events:用来保存从链表中拿取响应事件的集合;
		maxevents:  表示每次在链表中拿取响应事件的个数;
		timeout:超时时间,毫秒级别,0立即返回  ,-1阻塞	

返回值:    < 0 出错     >0 实际从链表中拿出的数目
             如果设置了超时检测: 
               < 0出错      >0实际从链表中拿出的数目    ==0 表示超时或者没事件产生

10.2 setsockopt 设置套接字属性
10.2.1 socket属性
头文件:      #include<sys.socket.h> 
            #include<sys/types.h>
            #include<sys/time.h>
int setsockopt(int sockfd,int level,int optname,void *optval,socklen_t optlen)
功能:获得/设置套接字属性
参数:
sockfd:套接字描述符
level:协议层
optname:选项名
optval:选项值
optlen:选项值大小
返回值:   成功: 0               失败 -1

选项名称

说明

数据类型

 ========= SOL_SOCKET 应用层  ==========

 SO_BROADCAST

       允许发送广播数据

 int

               SO_DEBUG

允许调试

int

SO_DONTROUTE

不查找路由

int

SO_ERROR

获得套接字错误

int

SO_KEEPALIVE

 保持连接

int

SO_LINGER

延迟关闭连接

 struct linger 

SO_OOBINLINE

带外数据放入正常数据流 

int 

SO_RCVBUF

接收缓冲区大小

int

SO_SNDBUF

发送缓冲区大小

int

SO_RCVLOWAT

接收缓冲区下限

int

SO_SNDLOWAT

发送缓冲区下限

 int 

SO_RCVTIMEO

接收超时

struct timeval

SO_SNDTIMEO

发送超时

struct timeval

SO_REUSEADDR

允许重用本地地址和端口

int

SO_TYPE

获得套接字类型

int 

SO_BSDCOMPAT

与BSD系统兼容

                       int

==========  IPPROTO_IP IP层/网络层 ==========

  IP_HDRINCL

         在数据包中包含IP首部

 int

IP_OPTINOS

 IP首部选项

 int

IP_TOS

服务类型

int

IP_TTL

生存时间

int

IP_ADD_MEMBERSHIP

将指定的IP加入多播组

  struct ip_mreq

============ IPPRO_TCP 传输层 ==============

TCP_MAXSEG

TCP最大数据段的大小

int 

TCP_NODELAY

不使用Nagle算法

 int 

设置 接收超时
设置超时检测操作的结构体:  
struct timeval {
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};

struct timeval tm={2,0}; 
setsockopt(acceptfd,SOL_SOCKET,SO_RCVTIMEO,&tm,sizeof(tm));
//设置超时之后时间一旦到达,会打断接下来的阻塞,直接错误返回
int recvbyte = recv(acceptfd, .......);

设置端口和地址重用(在绑定bind上面写)
int optval=1; 
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
10.3.1 sigaction 修改信号的行为
头文件: #include <signal.h>
声明:   int sigaction(int signum, const struct sigaction *act,  struct sigaction *oldact);
功能:对接收到的指定信号处理   
参数:   1. signum  信号	

     2. //act为设置新行为   oldact为设置旧行为 

            结构体如下:  
               struct sigaction {     
                    void     (*sa_handler)(int); //函数指针
                    其他的结构体成员如mark(信号集),flag(对信号的标记)都不常用
               };

		===============需要定义一个函数接收====================

	    void handler()
		{
			printf("timeout .....\n");
		}   

一般,给目标设置新的属性,流程都为:  
      先获取原来的属性
      修改属性
      将属性写回去


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void handler(int sig)
{
    printf("1111111\n");
}


int main(int argc, const char *argv[])
{
  //1.定义结构体变量
	struct sigaction act;
  //2.获取原来的属性
   sigaction(SIGALRM,NULL,&act);
  //3.修改属性
   act.sa_handler = handler;
  //4.写回属性
  sigaction(SIGALRM,&act,NULL);

   char buf[128] = ""; 
	while(1)
	{
	    alarm(2);  
	  if(fgets(buf,sizeof(buf),stdin) == NULL)
	  {
	       perror("fgets is err:");
		   continue;
	  }
	  printf("!!!!!!!\n");
	}
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024企业加密软件丨为什么企业需要防泄密

企业为什么需要防泄密&#xff1f; 企业的数据中包含了许多核心机密&#xff0c;如研发成果、商业计划、客户资料等。这些信息的泄露可能使竞争对手获得不正当的优势&#xff0c;给企业带来严重损失。 数据泄露事件往往会对企业的声誉造成负面影响&#xff0c;降低客户信任度…

【ROS2】Ubuntu 24.04 源码编译安装 Jazzy Jalisco

目录 系统要求 系统设置 设置区域启用所需的存储库安装开发工具 构建 ROS 2 获取 ROS 2 代码使用 rosdep 安装依赖项安装额外的 RMW 实现&#xff08;可选&#xff09;在工作区构建代码 设置环境 尝试一些例子 下一步 备用编译器 Clang保持最新状态 故障排除 卸载 系统要求 当前…

RRStudio 下载及安装(详尽版)

R语言来自S语言&#xff0c;是S语言的一个变种。S语言、C语言、Unix系统都是贝尔实验室的研究成果。R 语言是一种解释型的面向数学理论研究工作者的语言&#xff0c;主要用于统计分析、绘图、数据挖掘。 R 语言自由软件&#xff0c;免费、开放源代码&#xff0c;支持各个主要计…

python实现windows非白名单exe监控并杀死

目录 一、限定死白名单 二、增加自定义白名单文件 需求&#xff1a;孩子在家用电脑上网课&#xff0c;总是悄悄打开游戏或视频软件 方案&#xff1a;指定白名单exe&#xff0c;打开非白名单的就自动被杀死&#xff0c;并记录日志供查看 一、限定死白名单 import psutil imp…

【C语言】continue 关键字

当在C语言中使用continue关键字时&#xff0c;它用于控制循环语句的执行流程。与break不同&#xff0c;continue不会终止整个循环&#xff0c;而是终止当前迭代&#xff0c;并立即开始下一次迭代。这种行为使得可以在循环内部根据特定条件跳过某些代码块&#xff0c;从而控制程…

中国国家标准介绍

一、介绍 中国国家标准信息公共服务平台&#xff0c;这是由中国国家市场监督管理总局和中国国家标准化管理委员会共同运营的官方网站 https://openstd.samr.gov.cn/ 标准分为三类&#xff1a; GB&#xff1a;强制性国家标准GB/T&#xff1a;推荐行国家标准GB/Z&#xff1a;指导…

LT86101UXE 国产原装 HDMI2.0 / DVI中继器方案 分辨率 4Kx2K 用于多显示器 DVI/HDMI电缆扩展模块

1. 描述 Lontium LT86101UXE HDMI2.0 / DVI中继器特性高速中继器符合HDMI2.0/1.4规范,最大6 gbps高速数据率、自适应均衡RX输入和pre-emphasized TX输出支持长电缆应用程序,没有晶体在船上保存BOM成本,内部灵活的PCB TX巷交换路由。 LT86101UXE HDMI2.0/DVI中继器自动检测线缆损…

傅里叶变换

傅里叶定理指出&#xff1a; 任何信号都可以表示成&#xff08;或者无限逼近&#xff09;一系列正弦信号的叠加。在一维领域&#xff0c;信号是一维正弦波的叠加&#xff0c;那么想象一下&#xff0c;在二维领域&#xff0c;实际上是无数二维平面波的叠加&#xff0c;$(x&…

【面向就业的Linux基础】从入门到熟练,探索Linux的秘密(九)-git(1)

Git是一个版本管理控制系统&#xff08;缩写VCS&#xff09;&#xff0c;它可以在任何时间点&#xff0c;将文档的状态作为更新记录保存起来&#xff0c;也可以在任何时间点&#xff0c;将更新记录恢复回来。 文章目录 前言 一、git是什么 二、git基本概念 三、git基本命令 总结…

Vue3中为Ant Design Vue中Modal.confirm自定义内容

在一次业务开发时代码时&#xff0c;碰到了一种既想要Modal.confirm样式&#xff0c;又想要定制其content内容的情况。 大部分情况下&#xff0c;使用Modal.method()这种方式时&#xff0c;可能content内容固定都是字符串&#xff0c;那如果想要做更高级的交互怎么办&#xff…

将QT移植到IMX6ULL开发板

文章目录 前言一、编译系统1.设置交叉编译工具链2.编译系统3.烧写 二、Linux中下载QT1.安装 Qtcreator2.创建第一个程序3.配置 QtCreator 开发环境&#xff08;1&#xff09;打开选项界面&#xff08;2&#xff09;选择编译器&#xff08;3&#xff09;设置编译器&#xff08;4…

SoftCLT: 时间序列的软对比学习《Soft Contrastive Learning for Time Series》(时间序列、时序分类任务、软...

2024年6月25日&#xff0c;10:11&#xff0c;好几天没看论文了&#xff0c;一直在摸鱼写代码(虽然也没学会多少)&#xff0c;今天看一篇师兄推荐的。 论文&#xff1a; Soft Contrastive Learning for Time Series 或者是&#xff1a; Soft Contrastive Learning for Time Seri…

AutoX.js从某音分享链接解析出视频ID

背景 从某音分享的链接中解析出数字的videoID&#xff0c;用来做评论Intent跳转 思路 基本所有的短链接都是302跳转或者js跳转&#xff0c;熟悉http协议都知道&#xff0c;当状态码为302&#xff0c;从headers中提取Location即刻获得视频的原链接 链接中就带有videoId 要注意…

【串口通信】之TTL电平

1. 什么是串口 串口,全称为串行通信端口,是一种计算机硬件接口,用于实现数据的串行传输。与并行通信不同,串口通信一次只传输一个比特,数据通过串行线按顺序传输。串口通信在嵌入式系统、工业控制、计算机与外围设备通信等领域非常常见 2. 什么是串口通信 串口通信是指通过…

提升速卖通店铺排名:自养号测评的实战策略

卖家们追求的目标之一就是推广爆品。通过有效的推广策略&#xff0c;可以增加爆品的曝光度、吸引更多的买家&#xff0c;并带来更多的销售机会。那么&#xff0c;速卖通上如何推广爆品呢?下面我们来探讨一下这个问题。 首先&#xff0c;为了推广爆品&#xff0c;卖家需要进行…

护眼落地灯哪个牌子好?盘点五款必入不踩雷的护眼大路灯

护眼落地灯哪个牌子好&#xff1f;在这个快节奏的时代&#xff0c;护眼落地灯已经从一种高端选择转变为日常用眼生活中的必须品。不论是提升普通照明&#xff0c;还是针对孩子学习是改善光线质量环境&#xff0c;一款优秀的护眼落地灯都能成为我们生活中的照明神器。怎么选择一…

xmind2testcase工具将测试用例从Xmind转为CSV导入禅道

使用xmind编写测试用例&#xff0c;使用xmind2testcase工具将测试用例从Xmind转为CSV导入禅道&#xff0c;便于管理。 1.工具准备 第一步&#xff1a;安装python 第二步&#xff1a;安装xmind2testcase工具 运行-cmd-打开命令提示符弹窗&#xff0c;输入安装命令 安装命令&…

数千万“四高”中老年患者,如何推动国产营养保健品创新

“三高”指高血压、高血糖&#xff08;糖尿病&#xff09;、高血脂&#xff0c;是中老年群体的常见病。 然而&#xff0c;除了前述三者&#xff0c;高尿酸血症在我国的患病率正逐年提高&#xff0c;已成为仅次于糖尿病的第二大代谢性疾病。痛风是高尿酸血症典型症状之一。 加上…

大华设备接入GB28181视频汇聚管理平台EasyCVR安防监控系统的具体操作步骤

智慧城市/视频汇聚/安防监控平台EasyCVR兼容性强&#xff0c;支持多协议接入&#xff0c;包括国标GB/T 28181协议、GA/T 1400协议、部标JT808协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等&#xff0c;并能对外分发RTMP、…

Linux 文件系统以及日志管理

一、inode 与block 1. inode 与block详解 在文件存储硬盘上&#xff0c;硬盘的最小存储单位叫做“扇区”&#xff0c;每个为512字节。 操作系统读取硬盘的时候&#xff0c;不会一个个扇区地读取&#xff0c;这样效率太低&#xff0c;而是一次性连续读取多个扇区,即一次性读取…