【操作系统三】图解网络IO(bio\nio\slect\epoll)

news2024/11/25 18:29:18

【操作系统三】图解网络IO+实战

  • 一、计算机组成
  • 二、系统中断
  • 三、晶振(时间中断、分时复用)
  • 四、事件中断
    • 1、DMA
    • 2、事件中断
    • 3、网卡也会产生中断?
  • 五、linux系统知识
    • 1、linux下一切皆文件?
      • 1.1、nc启动一个服务端,端口号8080
      • 1.2、linux下一切皆文件.
      • 1.3、程序有三个基本的流.
      • 1.4、监听和建立链接.
    • 2、linux系统文档
      • 2.1、安装系统文档
      • 2.2、查看第二类的系统文档。
      • 2.3、知识连接
      • 2.4、linux系统函数给出的,创建socket的例子
  • 六、网络通信IO
    • 1、什么是io?
    • 2、BIO
      • 2.1、bio工作流程如下。
      • 2.2、bio的问题(read阻塞)
      • 2.3、怎么解决bio的阻塞问题
    • 3、NIO
    • 4、多路复用(slect)
    • 5、epoll
      • 5.1、简介
      • 5.2、相关函数介绍
        • 5.2.1、epoll_create
      • 5.2.2、eopll_ctl
      • 5.2.2、eopll_wait
    • 5.3、epoll的过程
    • 5.4、aio和epoll
  • 七、知识互联:kafka用到的三个技术点
    • 1、kafka写数据为何那么快?mmap
    • 2、kafka读数据为何那么快?零拷贝
    • 3、kafka其实还用到了nio/epoll
  • 七、知识互联:redis、ngnix

  • 简介
    上一章,我们讲解过了TCP/IP模型,本篇我们详细的介绍下网络通信中的io知识,包括bio、nio、slect、epoll。考虑到很多同学并非计算机专业出身,在讲解这些知识之前,我们还提前补充了计算机组成、系统中断、晶振的时间中断和事件中断等。

一、计算机组成

对于非计算机专业的同学,很多人并没有系统的学习过计算机操作系统和计算机网络等。比如冯诺依曼模型:中央处理器(CPU)、内存、输⼊设备、输出设备、总线。
在这里插入图片描述

对于上图,非计算机的同学理解起来还是太抽象。我们可以简单的把计算机简单的分为:cpu、内存、io设备。(如下图)

  • 在开机前,计算机内存是空的。内存分为用户空间、内核空间(也叫用户态和内核态)。
  • 内核也是一个程序?
    开机时,首先会把计算机的内核(kernel)加载到内存中。内核进入内存中时,首先会划分一个空间,就是内核空间。
    用户的进程存活在用户空间。
  • 为何要有内核?
    多个进程访问硬件,需要通过内核。内核托管了硬件。
    在这里插入图片描述

二、系统中断

  • 用户程序直接访问内核空间?
    答:不可以。cpu有一个保护机制,开机时会划分出内核空间,受保护的。
  • 用户程序如何访问硬件?
    答:通过内核的系统调用。内核有一个系统调用,系统调用走的是软中断。此时,cpu会有一个从用户态到内核态的切换。内核里面,会有一些硬件的访问,封装的一些方法。而这些方法,通过中断的方式调取。(软中断)
    在这里插入图片描述

三、晶振(时间中断、分时复用)

假如只有1个cpu,内核和系统进程间是怎么运行的?也就是说,假如一个进程不释放cpu,其他的怎么继续执行?

  • cpu内有一个晶振。
  • 从cpu通电开始,晶振一直在嗒嗒嗒的震动。(比如,1秒中震动1万次)
  • 计算机系统是分时的,一个时间片是多久。(假如,1个时间片是1毫秒)
  • 比如晶振1毫秒可以震动10次。(晶振震动10次会产生一个中断(时间中断)
  • 产生中断后。
    • 内核启动时,会在内核中埋一个进程调度的回调地址(callback)
    • 假如进程1的时间片用完了,pia的以下就会产生一个中断。(cpu可以执行其他进程了(包括内核))
    • 首先,把进程1的现场保护起来。
    • 然后,调用进程调度的回调地址,知道该调用哪个进程了,
    • 最后,把另外一个进程2(比如应该执行进程2了)加载起来。
    • 这样就可以执行进程2了,如此反复。
      在这里插入图片描述

备注:

  • 进程间的的分时复用,依赖晶振的中断,成本较大。比如真的切换到进程2了,进程2也不一定要执行,也可能在阻塞。
  • cpu不能百分百作用在业务上,有可能50%的时间都在调度上。

四、事件中断

CPU假如只有一颗,比如,同时接收网卡数据、移动鼠标

1、DMA

DMA,全称Direct Memory Access,即直接存储器访问。

DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

2、事件中断

  • 当io设备接收到数据时,会产生一个事件中断,等待cpu进行处理。
    在这里插入图片描述

3、网卡也会产生中断?

  • 网卡也会产生中断?
    答:网卡也是一个io设备,也会产生中断事件。
  • DMA用来干啥?
    答:DMA就是内存中的一个区域,网卡的数据来了后,可以直接把数据存入DMA.
  • 有什么用?
    答:网卡来了数据后,可以直接存入DMA,不用每次都都产生一个cpu中断。
  • 为何不每次产生cpu中断?
    答:cpu内存寻址的速度是纳秒,io的操作都是毫秒。
    如果在cpu处理其他过程中,我们直接把数据放入dma,就可以告诉cpu,你去操作数据吧,这样cpu的效率就是纳秒。
    如果中间染指了io操作,那cpu就变成了毫秒。

五、linux系统知识

1、linux下一切皆文件?

1.1、nc启动一个服务端,端口号8080

  • 命令如下
nc -l 8080
  • 输出如下,监听成功。
    在这里插入图片描述

  • 查看nc进程id,

ps -fe | grep nc
  • 如下图,进程id3671
    在这里插入图片描述

1.2、linux下一切皆文件.

  • 根目录下,有一个文件夹proc。(开机才有,平时是空的)
cd /
ll
  • 输出如下,有一个存放进程的文件夹proc.
    在这里插入图片描述

  • 进入proc目录,找到进程id为3671的文件夹,如下图

cd proc
ls
  • 输出如下,proc里面存的是所有的进程。
    在这里插入图片描述
  • 进入进程3671的文件夹。进程抽象成了文件。
cd 3671
pwd
ls
  • 输出如下
    在这里插入图片描述

1.3、程序有三个基本的流.

一个程序有三个基本的流:输入流、输出流、错误流。1、2、3是文件描述符。

  • 0:输入流
  • 1:输出流
  • 2:错误流
  • 3:socket的监听的文件描述符。
cd fd
pwd
ll
  • 输出如下
    在这里插入图片描述

备注:今天就写到这里吧,后面的会基于此继续写。后面的nc的进程号可能会变。

1.4、监听和建立链接.

分别启动3个shell
1、使用nc启动一个服务端

nc -l 8080

2、使用nc启动一个客户端,和服务端建立链接,(如下图,分配的随机端口号为58438)

nc localhost 8080

3、查看建立的链接

netstat -natp
  • 输出如下
    在这里插入图片描述

  • 查看客户端进程的fd目录如下
    在这里插入图片描述

  • 问题:为何服务端下的fd有2个socket,而客户端下有1个socket.
    答:因为服务端除了建立链接,还需要监听,所以需要两个文件描述符。

2、linux系统文档

2.1、安装系统文档

yum instal man-pages

2.2、查看第二类的系统文档。

  • 系统文档一共有8类。第二类是系统调用。
  • 我们查看第二类的系统文档中的socket
man 2 socket
  • 输出如下图,系统调用是提供的c的调用方式。
    在这里插入图片描述
    上面的图片往下拉下,可以看到,socket返回一个文件描述符。
RETURN VALUE
       On  success,  a  file  descriptor  for  the new socket is returned.  On
       error, -1 is returned, and errno is set appropriately.

我们获取socket的文件描述符干嘛呢?其实拿到文件描述符就可以操作了。比如使用read函数读文件描述符。

man 2 read
  • 输出如下
    在这里插入图片描述

2.3、知识连接

socket返回的文件描述符,也是我们在1、linux下一切皆文件,中看到的,fd目录下的3和4。
所有 io抽象成了文件描述符。
在这里插入图片描述

2.4、linux系统函数给出的,创建socket的例子

在函数bind中,有完整的创建socket服务端的例子。

man 2 bind

输出中,有一个examle,从中看到,服务端socket流程,如下

  • 创建套接字(socket)
  • 绑定端口号(bind)
  • 监听(listen)
  • 接收数据(accept)
EXAMPLE
       An example of the use of bind() with Internet  domain  sockets  can  be
       found in getaddrinfo(3).

       The  following  example  shows  how to bind a stream socket in the UNIX
       (AF_UNIX) domain, and accept connections:

       #include <sys/socket.h>
       #include <sys/un.h>
       #include <stdlib.h>
       #include <stdio.h>
       #include <string.h>

       #define MY_SOCK_PATH "/somepath"
       #define LISTEN_BACKLOG 50

       #define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

       int
       main(int argc, char *argv[])
       {
           int sfd, cfd;
           struct sockaddr_un my_addr, peer_addr;
           socklen_t peer_addr_size;

           sfd = socket(AF_UNIX, SOCK_STREAM, 0);
           if (sfd == -1)
               handle_error("socket");

           memset(&my_addr, 0, sizeof(struct sockaddr_un));
                               /* Clear structure */
           my_addr.sun_family = AF_UNIX;
           strncpy(my_addr.sun_path, MY_SOCK_PATH,
                   sizeof(my_addr.sun_path) - 1);

           if (bind(sfd, (struct sockaddr *) &my_addr,
                   sizeof(struct sockaddr_un)) == -1)
               handle_error("bind");

           if (listen(sfd, LISTEN_BACKLOG) == -1)
               handle_error("listen");

           /* Now we can accept incoming connections one
              at a time using accept(2) */

           peer_addr_size = sizeof(struct sockaddr_un);
           cfd = accept(sfd, (struct sockaddr *) &peer_addr,
                        &peer_addr_size);
           if (cfd == -1)
               handle_error("accept");

           /* Code to deal with incoming connection(s)... */

           /* When no longer required, the socket pathname, MY_SOCK_PATH
              should be deleted using unlink(2) or remove(3) */
       }

六、网络通信IO

1、什么是io?

i就是input,输入,o就是output,输出,合起来就是以流为基本的输入输出。

2、BIO

同步阻塞I/O处理(也就是BIO,Blocking I/O):

当客户端有请求到服务端的时候,服务端就会开启一个线程进行处理,当有多个请求进入时,就会开启多个线程分别处理对应的请求。

2.1、bio工作流程如下。

  • 第一步:建立socket链接、绑定端口号、监听。
  • 第二部:接收客户端的链接。
  • 第三步:接收客户端的数据。
    在这里插入图片描述

2.2、bio的问题(read阻塞)

  • 如下图,当有新的客户端fd过来链接时。
  • 从1.1bio的流程可知,bio的read存在阻塞。

2.3、怎么解决bio的阻塞问题

  • 方案一:多线程。
    抛出一个线程,专门读。如上图,分别读fd4和fd5。

方案一的缺点:10万个链接,对接10万个线程。

  • 痛点:线程链接1对1.(因为阻塞)
    在这里插入图片描述

  • 方案二:NIO

可以让读文件描述符,变成非阻塞的。读不到数据时,继续往后走。
不用抛出那么多线程了。

3、NIO

  • NIO:同步非阻塞式IO,(non-blocking IO、or java中也指的new IO)
  • read时没有数据时返回一个错误。不阻塞了。
    在这里插入图片描述

优点:

  • 1、10完个链接不需要发出10万个线程了。一个线程就可以搞定了。(或者把接受和工作抛出两个线程)
  • 2、减少了cpu在几千几万个线程间的切换的事情了。
  • 3、cpu的利用率高了。

问题:

  • 1、每次read,都需要把cpu从用户状态,切换到内核状态。
  • 2、用户态和内核态切换,有些频繁。(假如有10万个链接,会有10万次的read,10万次的内核态和用户态的切换,假如这其中只有1个客户端发来了数据,那么会有99999次的read的浪费,也就是99999次内核态和用户态切换的浪费)
  • read的时间复杂度——O(n) ,时间复杂度n。其中n=10万。

怎么解决?

  • 多路复用

4、多路复用(slect)

  • 查看多路复用,系统调用的方法。
  • slect可以拿到10万个文件描述符中,真正有数据的文件描述符。
man 2 slect
  • 多路复用的流程图如下
    在这里插入图片描述

优点:

  • slect调用了一次,就知道哪些文件描述符需要读。(比如5个)
  • 这样,我们调用5次read就可以了。
  • 把10万次的循环,压到了内核里面使用。
  • 真正的意义:没有那10万次的内核态和用户态的切换了。
  • read的时间复杂度——o(5),假如只有5个文件描述符需要读。

slect有什么弊端?

  • 1、没循环fd*,需要把10万次的文件描述符传给内核。
  • 2、内核每次都需要循环10万次,找哪些文件描述符需要读。

解决方案

  • 1、epoll

5、epoll

5.1、简介

  • 如《四、事件中断》介绍,io接收到数据后,就会产生一个中断,且放到了内存dma中了。内核只需要看下io数据属于哪个fd的,然后通知给程序就可以了。
  • 这样就是,内核被动的通过中断事件消耗这个事情。而不是主动的便利10万次。

查看epoll

man 7 epoll
  • 输出如下(可以看到,epoll属于7类,如果我们使用,需要调用3个二类系统调用的接口epoll_create、epoll_ctl、epoll_wait)
    在这里插入图片描述

5.2、相关函数介绍

5.2.1、epoll_create

man 2 epoll_create
  • 可以看到这个函数的返回值是一个文件描述符,代表内核的一个空间。
    在这里插入图片描述
  • 这样你就可以把所有的文件描述符放到内核的这个空间中了。
  • 怎么把所有的文件描述符放进去?
    答:通过epoll_ctl

5.2.2、eopll_ctl

man 2 epoll_ctl
  • 可以看到,把客户端来的文件描述符,放到epoll_create创建的空间中,及时来了10万了链接,我们只放一次就可以了。
    在这里插入图片描述
  • 我们怎么知道那些客户端的数据到了呢?
    答:使用epoll_wait

5.2.2、eopll_wait

man 2 epoll_wait
  • 可以看到,假如我们设置了8个文件描述符的结构体,那么当io数据来了8个后,我们就可以产生一个中断事件。
    在这里插入图片描述

  • epoll vs mmap
    问:epoll有使用mmap吗?
    答:前期epoll有用mmap,后面epoll没有用mmap

5.3、epoll的过程

前提:已经创建了socket监听,并绑定了端口号,获得了文件描述符fd3.

  • 第一步:创建epoll,获取内核空间的一个文件描述符,fd1,
  • 第二步:把监听的文件描述符fd3,加入到第一步创建的空间中。埋下接收链接的事件。
  • 第三步:等待链接,
  • 第四步:若收到了链接fd8,。
  • 第五步:把收到的客户端链接的描述符fd8,加入到epoll_create创建的空间中,埋下读数据的事件。
  • 第六步:若fd8收到了数据,就会把数据放到dma中,并会产生事件中断。
    在这里插入图片描述

备注:

  • 循环的去epoll_wailt。
  • 相当于基于event的多路复用。
  • epoll只拿到了event,读数据还是要调用read.
  • 网卡把数据放到了dma,我们通过事件知道了里面有数据。仅仅把这个事件告诉了你,wait得到了事件。真正操作数据还是要读内核。

优点

  • 压榨计算资源到极致。

5.4、aio和epoll

  • aio:异步非阻塞,通过回调处理,没有read。(目前非内核提供)

七、知识互联:kafka用到的三个技术点

kafka我们之前介绍过,其实就是mq.(消息队列)

  • kafka整个过程
    • 第一步:客户端的数据到内核。
    • 第二部:kafka进程读取数据。
    • 第三步:kafka把数据存入硬盘
      在这里插入图片描述

1、kafka写数据为何那么快?mmap

mmap 即 memory map,也就是内存映射

  • 实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read、write 等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。
  • 问:kafka写数据为何那么快?
    答:因为写数据采用了mmap,写数据不用系统调用write,写到内存的同时,就同时写到了内核和硬盘里面。少了一次系统调用write的过程。
    在这里插入图片描述
    其他:
  • kafka配置文件,有个segment01 1G,共享内存就是1个G.硬盘和内核的空间也是1个G.
  • 如果segment01满了后,会再次创建segment02 ,也是1个G。

2、kafka读数据为何那么快?零拷贝

  • sendfile是在内核中实现的,不需要拷贝了。
  • 表示在两个文件描述符之间传输数据,它是在操作系统内核中操作的,避免了数据从内核缓冲区和用户缓冲区之间的拷贝操作,因此可以使用它来实现零拷贝。

3、kafka其实还用到了nio/epoll

  • nio和epoll参考之前的介绍。

七、知识互联:redis、ngnix

  • redis底层用的是epoll、单线程。
  • ngnix底层用的也是epoll、还有零拷贝(sendfile)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vulnhub靶机:matrix:1

目录 查看靶机的ip 开放端口扫描 解密 字典生成爆破 ssh登录 rbash逃逸 下载地址&#xff1a;Matrix: 1 ~ VulnHub Kali地址&#xff1a;192.168.174.128 靶机地址&#xff1a;192.168.174.139 这个靶机是我在刷到的一个视频&#xff0c;讲解这个靶机的博主比较有趣&a…

web网页设计期末课程大作业:水果网站设计——HTML+CSS+JavaScript水果超市(带论文)

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

大一学生Web课程设计 HTML+CSS保时捷汽车介绍(可以很好的应付老师的作业)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

2022CTF培训(八)ARM PWN 环境搭建ARM PWN 入门

附件下载链接 环境搭建 QEMU qemu是一款可执行硬件虚拟化的虚拟机&#xff0c;与他类似的还有Bochs、PearPC&#xff0c; 但qemu具有高速&#xff08;配合KVM&#xff09;、跨平台的特性 qemu主要有两种运行模式&#xff1a;qemu-user 和 qemu-system qemu-system 可以进行…

[附源码]Python计算机毕业设计高校互联网班级管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

[附源码]Nodejs计算机毕业设计基于的开放式实验室预约系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

k8s编程operator实战之云编码平台——④web后端实现

文章目录1、简介1.1 目录结构1.2 开发模式2、数据库设计2.1 user表2.2 space_template和space_kind表2.3 space和spacespec表3、gRPC客户端4、数据库访问4.1 mysql4.2 redis5、缓存加载5.1 通用缓存5.2 数据加载6、功能开发6.1 用户登录6.2 获取所有模板6.3 创建工作空间6.4 创…

如何进行C++动态转换

&#x1f4d2;博客主页&#xff1a; ​​开心档博客主页​​ &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由开心档原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2022年12月12日&#x1f334; ✉…

如何评价「仙剑奇侠传六」使用Unity 3D引擎?

2022年看到问题&#xff0c;根据2022年Unity3D、Unreal Engine及仙剑六来一波“穿越马后炮式”回答。 1&#xff1a; 2022年看到问题&#xff0c;根据2022年Unity3D、Unreal Engine及仙剑六来一波“穿越马后炮式”回答。 1&#xff1a; 仙剑奇侠传六确为unity引擎制作&#…

大学生简单静态HTML网页模板源码——家乡介绍美丽乡村11页

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

【leetcode】将有序数组转换为二叉搜索树

一、题目描述 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 示例 1&#xff1a; 输入&#xff1a;nums …

微信对接chatGPT,实现自动回复消息、在线答疑等功能

前言 近来chatGPT挺火的&#xff0c;也试玩了一下&#xff0c;确实挺有意思。这里记录一下在在微信中也可以使用chatGPT&#xff0c;顺带可以自动回复微信消息、实时答疑等。。。 上一篇文章回顾&#xff1a;https://frica.blog.csdn.net/article/details/128316712 本文章在u…

Spark3.3.0的DataFrame及Spark SQL编程的性能对比【单机模式下】

Spark3.3.0的DataFrame及Spark SQL编程的性能对比【单机模式下】 前言 Spark3.3.0较老早的2.4.0有极大的性能优化&#xff0c;尤其是对SQL做了大量的优化【数据倾斜等】&#xff0c;恰好近期遇到一些性能问题&#xff0c;特意写个Demo测试下DataFrame和Spark SQL在获取到相同…

c#入门-接口的抽象成员和虚成员

接口的抽象成员 接口的成员如果不指定主体&#xff0c;那么就是抽象成员。 你可以主动为他们加抽象修饰符&#xff0c;不过没什么用。 interface I属性 {public abstract int Hp { get; set; }public abstract int Mp { get; set; } }接口的虚成员 接口的成员可以指定主体。…

Jina 开箱即用的云原生多模态系统解决方案

Jina 是一个基于云原生的多模态应用框架&#xff0c;开发者使用 Jina 可以轻松构建、部署和维护高性能的云原生应用。你可能认为这些都只是空泛的营销口号&#xff0c;甚至产生疑问&#xff0c;到底什么是云原生&#xff1f;对构建多模态应用有什么帮助&#xff1f;它是否只是 …

Linux CentoOs7中用命令打开并修改文本文件

概述&#xff1a;VI/VIM VI 是 Unix 操作系统和类 Unix 操作系统中最通用的**文本编辑器**。 VIM 编辑器是从 VI 发展出来的一个性能更强大的**文本编辑器**。可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计。VIM 与 VI 编辑器完全兼容。 我们常常用vim命令…

C#语言实例源码系列-实现热键屏幕和设置热键

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册 &#x1f449;关于作者 众所周知&#xff0c;人生是一个漫长的流程&#xff0c;不断克服困难&#xff0c;不断反思前进的过程。在这个过程中…

C++ 初阶 文件操作和io流

作者&#xff1a;小萌新 专栏&#xff1a;C初阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;简单介绍C中的文件操作和io流 文件操作和io流C语言中的输入和输出流是什么&#xff1f;Cio流C标准io流C中流的特性C文件io流以二进制形…

Jenkins全局安全配置

文章目录一、进入全局安全设置页面二、各选项功能Disable remember me&#xff08;禁用记住我&#xff09;Security Realm(安全域)Delegate to servlet container&#xff08;servlet 容器代理&#xff09;Jenkins’ own user database&#xff08;Jenkins 专有用户数据库&…

Pr:导出页面之预览与摘要窗口

使用“预览”窗口&#xff0c;可在导出前预览媒体&#xff0c;设置自定义的持续时间&#xff0c;如果导出为不同的帧大小&#xff0c;还可以控制源视频适应输出帧的方式。使用“摘要”窗口&#xff0c;可以快速查看源及输出的音视频信息。◆ ◆ ◆预览窗口范围Range可自定义导…