【网络】多路转接——五种IO模型 | select

🐱作者:一只大喵咪1201
🐱专栏:《网络》
🔥格言:你只管努力,剩下的交给时间!
图

五种IO模型 | select

  • 🍧五种IO模型
  • 🍧select
    • 🧁认识接口
    • 🧁简易select服务器
    • 🧁select的特点
  • 🍧总结

🍧五种IO模型

在学习系统部分的时候,本喵就讲解过IO,当时我们学习的IO就是从文件中读数据和写数据,到了后来学习网络的时候,我们知道,从网络中读取和写入数据也是IO,那么IO到底是什么呢?今天我们来更深刻的认识一下IO。

就拿读取数据来说,无论是调用read还是recv,在文件描述符所指向的struct file中的接收缓冲区如果没有数据的时候,都会阻塞等待

当缓冲区中有数据后,才会进行读取,所谓读取,本质就是在拷贝,就是将内核缓冲区中的数据拷贝到用户缓冲区中供用户去使用。

无论是等待还是拷贝,都是读取的过程,二者缺一不可。

  • IO = 等 + 数据拷贝

那么什么是高效的IO呢?我们知道,IO过程中我们在意的是拷贝,而不是等待,由于各种技术的发展,拷贝所花费的时间几乎是固定的,是由电路或者系统等等机制来保证的,所以拷贝的效率已经很难再有提升了。

  • 高效的IO = 减少等待的比重

IO的种类有五种,下面本喵给大家介绍一下:

  1. 阻塞IO:在内核将数据准备好之前,系统调用会一直等待,所有的套接字以及文件,默认都是阻塞方式。

图
如上图所示便是阻塞IO的示意图,在进程调用recvfrom从内核缓冲区中读取数据时,如果数据没有准备好,进程就会阻塞在调用处等待,直到数据准备好,才会将内核缓冲区的数据拷贝到用户缓冲区,并且给进程返回值。

  • 阻塞IO是最常见的IO模型,也是最简单的IO模型,我们之前写的所有IO都是阻塞式的。
  1. 非阻塞IO:如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回EAGAN或者EWOULDBLOCK错误码。

图

如上图所示,进程调用recvfrom从内核缓冲区中读取数据时,即使数据没有准备好,仍然会给进程一个返回一个EAGAN或者EWOULDBLOCK

通常情况下使用这种IO方式时,如果返回EAGAN或者EWOULDBLOCK,说明数据没有准备好,就会再次调用recvfrom去读取数据,如此反复,直到数据准备好并且完成拷贝,最后返回表示成的返回值。

  • 非阻塞IO需要程序员以循环的方式反复尝试读写文件描述符,这个过程称为轮询
  • 这对CPU来说是较大的浪费,一般只有特定场景下才使用。

默认情况下,文件描述符fd指向的struct file中的缓冲区的阻塞式IO,所以我们前面无论是在进行文件操纵还是使用套接字的时候,都是阻塞IO。

图
如上图所示系统调用fcntl,可以使用它将fd所指向的文件改成非阻塞IO模式,它的参数是一个可变参数。

  • int fd:要修改文件的文件描述符fd。
  • 返回值fl:大于0表示当前文件的状态,小于0表示调用失败。
  • int cmd:对fd所指向的文件要进行的操作,可以传递两个参数:
  • F_GETFL:用来获取该文件当前的状态。
  • F_SETFL:用来设置该文件当前的状态。
  • 可变参数部分:可以传递参数有O_RDONLY,O_WRONLY等等,最重要的是O_NONBLOCK非阻塞IO方式,但是在传参的时候,必须和fl进行按位或,如fl | O_NONBLOCK

图
如上图所示代码是本喵写的一个工具函数,作用就是将指定fd所代表的文件设置成非阻塞IO方式。

图
如上图,从内核中的代码可以看到,O_NONBLOCK是一个宏,仅仅代表着一个比特位的状态,所以在传参时,需要使用fl | O_NONBLOCK的方式,在文件原有的状态上增加非阻塞。

再重新来看一下read系统调用:

图
如上图所示为man手册中的描述,调用失败以后,返回-1,并且错误码被设置

  • 设置不同的错误码代表着不同的意义。

图
如上图所示,可以设置的错误码有这么多,虽然返回值是-1,但是不同的错误码代表着不同的情况,其中EAGAIN或者EWOULDBLOCK表示的就是数据没有准备好,需要稍后再读。

  • 读取数据时,内核中缓冲区的数据没有准备好并没有错,这是很正常的情况。
  • 所以错误码EAGAIN并不表示错误了,只是表示数据暂时没有准备好,需要稍后再来读取。

TU
如上图所示,EAGAINEWOULDBLOCK都是宏,而且它们的值都是11,本质上是一个东西。

图
如上图代码所示,使用本喵写的工具serNonBlock将标准输入,也就是文件描述符为0的文件设置成非阻塞IO模式,然后运行。

图
如上图所示,可以看到,输入提示符>>>在不停打印,在本喵从键盘上输入的时候,仍然在打印,虽然输入的内容被>>>分隔开了,但是输入完成以后,回显echo的内容却是完整的,仍然是helloworld

  • 输入和输出互不影响,因为有输入缓冲区和输出缓冲区,二者是相互独立的。

图
如上图所示便是默认情况下的阻塞IO,可以看到,输入和输出轮替进行着,在本喵没有输入的情况下,该进程是阻塞等待的。

图
如上图所示,可以在else情况,也就是返回值s小于0的时候再进行具体的判断,如果错误码errno的值是EAGAIN说明只是数据没有准备好,并不是出错了,在等待数据就绪的过程中可以执行其他任务。
图
如上图所示,此时进程并没有阻塞,而是在轮询,数据没有准备好就执行其他任务来打发时间。

  1. 信号驱动IO:内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作。

图

如上图所示信号驱动IO模型,该模式调用recvfrom并不是在主进程中调用,而且使用signal注册信号处理函数,在信号处理函数中调用recvfrom

进程一直在正常运行,执行自己的逻辑,当内核接收缓冲区有数据到来时,进程会收到系统给发的信号SIGIO,然后就会调用该信号注册的处理方式,在信号处理方式中调用recvfrom读取缓冲区中的数据。

  • 一旦进入信号处理函数中,说明内核缓冲区中的数据已经准备好了,在这里只需要读取,而不再需要等待。
  1. IO多路转接:虽然从流程图上看起来和阻塞IO类似,实际上最核心在于IO多路转接能够同时等待多个文件描述符的就绪状态。

图
如上图IO多路转接模式,该模式中,将IO的等待拷贝两个步骤分开了。

进程调用select系统调用来等待内核缓冲区中数据就绪,当数据就绪以后通知进程调用recvfrom来将数据拷贝到用户缓冲区中。

这样看起来和信号驱动的IO模式没有什么区别,但是多路转接的优势在于可以同时等待多个文件描述符所指向的文件。

  • IO多路转接模式下,可以同时等待多个文件,当一个或者多个文件的缓冲区中数据就绪时,就会通知上层用户来读取。

此时虽然也有等,但是等的比重就降低了,因为能够一次等待多个文件,进而让上层用户一次来读取多个缓冲区中的数据,拷贝的比重就增加了,从而提高了IO的效率。

  1. 异步IO:由内核在数据拷贝完成时,通知应用程序直接去用户缓冲区中使用数据。
  • 同步和异步关注的是消息通信机制:
  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回,但是一旦调用返回,就得到返回值了。
  • 也就是由调用者主动等待这个调用的结果。

异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。

  • 当一个异步过程调用发出后,调用者不会立刻得到结果,而是在调用发出后,被调用者通过状态、信号等来通知调用者,或通过回调函数处理这个调用。

图
如上图所示异步IO模式示意图,进程调用aio_read,将等待数据就绪和将数据拷贝到用户缓冲区两个步骤的工作全部交给操作系统来完成。

当操作系统完成两个步骤以后,通知上层用户直接去用户缓冲区中使用数据即可。

信号驱动是告诉进程可以从内核缓冲区中拷贝数据到用户缓冲区了,而异步IO连拷贝这一步也不用做了,直接使用数据。

  • 另外,我们回忆在学习多进程多线程的时候,也提到同步和互斥,这里的同步通信和进程之间的同步是完全不同的概念。
  • 进程/线程同步也是进程/线程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。尤其是在访问临界资源的时候。

比较这五种IO模式,阻塞IO模式肯定是效率最低的,非阻塞以及信号驱动的IO模式,同样需要参加IO的等待拷贝两个过程,对于IO的效率是相同的。

异步IO模式也是同样的道理,虽然等待和拷贝不是由线程去做的,而是由操作系统在做,但是线程也得在等待和拷贝完成后才能使用数据,所以IO的效率还是没有提高的。

而多路转接不一样,虽然等待拷贝两个过程都参与,但是等待时可以一次等待多个文件描述符,拷贝时也是可以拷贝多个文件描述符中的数据。

  • 由于等待的文件描述符数量多,所以有数据就绪的概率就高,进行拷贝也更加频繁。
  • 站在上帝视角来看,多路转接模式下,进程在单位时间内进行拷贝的次数要比其他几种模式多。

所以多路转接更加高效,而我们研究的重点也在多路转接模式上,主要有selectpollepoll三种方式。

🍧select

🧁认识接口

图
如上图所示,该系统调用有5个参数。

  • int nfds:要等待的所有文件描述符中的最大fd+1

假设现在要等待的文件有3个,文件描述符分别是3,4,7,则传参时就需要传7+1=8给nfds。

  • fd_set* reads:等待读取就绪文件描述符的位图。

select等待的文件有不同的事件会就绪,比如读取就绪,写就绪,错误就绪等等。

图
如上图所示是fd_set类型在内核中的定义,可以看到它就是一个位图。它有多个比特位,每一个比特位代表一个文件描述符,比特位的状态表示该比特位是否被监听。

图
如上图所示便是fd_set位图示意图,其中比特位的顺序由低到高从左向右,比特位的下标就是代表文件描述符fd,比特位的内容表示状态,这张图中,文件描述符为1,3,1023的三个文件描述符需要被select监视。

图
如上图所示,使用sizeof得到fd_set类型的大小是8字节,所以有1024个比特位,这意味着使用select最多监视1024个文件描述符。

将接收缓冲区所在文件的文件描述符设置到readfds中,当该缓冲区有数据到来时(读就绪),select就会通知上层进程去读取该缓冲区中的数据。

  • fd_set* writefds:等待写入就绪文件描述符所在位图。

该位图和readfds一样,只是操作系统等待的事件由读就绪变成了写就绪,当发送缓冲区空了以后(写就绪),操作系统就会通知上层进程向该缓冲区中写入数据。

  • fd_set* exceptfds:等待异常就绪文件描述符所在位图。

打开的文件,如TCP中的套接字,当对端关闭套接字以后,自己这边的套接字就会出现异常,此时操作系统就会通知上层进程处理该异常。

需要操作系统监视哪里事件就将对应的位图传给select,待事件就绪后就会通知上层进程去处理,如果不需要监视直接设置成nullptr就行。

  • struct timeval* timeout:设置等待方式。

图

如上图所示struct timeval类型的定义,有两个成员,第一个是秒,第二个是微秒。

该参数传入nullptr的时候,select是阻塞等待,只有当一个或者多个文件描述符就绪时才会通知上层进程去读取数据。

该参数如果是struct timeval timeout = {0, 0},时间设置成0,select是非阻塞等待,就需要使用轮询的方式。

该参数如果设置了具体值,如struct timeval timeout = {5, 0},时间设置成5,select在5秒内阻塞等待,如果在5秒内有文件描述符就绪,则通知上层,如果没有文件描述符就绪则超时返回。

  • 返回值:

ret > 0表示有ret个fd就绪了,ret == 0表示超时返回,ret < 0表示select调用失败了。


为了使用方便,内核还提供了一组宏供用户去设置fd_set位图,将对应的文件描述符设置进去,避免了我们自己使用按位或等运算给位图赋值的麻烦:

图
如上图所示,FD_CLR是将位图中指定文件描述符fd所对应位的状态清零,表示不用操作系统再等待该文件。

FD_ISSET是用来判断特定文件描述符fd是否被设置进了位图,如果设置返回1,没有则返回0。

FD_SET是用来将指定文件描述符fd对应的位图设置为1,表示需要操作系统等待该文件。

FD_ZERO是用来将整个位图清空的,此时操作系统不等待任何一个文件。


select的五个参数中,后面四个都是输入输出型参数,都是传的指针,意味着操作系统和用户共用一个参数。

调用select传参时,表示用户告诉内核,需要操作系统等待哪个文件,以及哪种事件。操作系统第一时间会将传入的位图参数清空,每就绪一个文件,传入位图相应比特位置一,然后传返回值给用户。

此时就是内核在告诉用户,你关心的多个fd,有哪些已经就绪了。

用户根据返回值来处理调用结果,如果是ret>0,则判断自己当初设置进位图中的文件描述符是否被置一了,如果置一了,说明该文件所对应的事件就绪了,用户就可以进行进一步处理。

  • 由于传入的参数是输入输出型的,操作系统等待后的结果也是在这个参数中,所以用户必须自己再维护一个数据结构来记录自己最初设置要等待的文件描述符。
  • 根据select返回状态以及操作系统修改后的位图,与自己维护的记录结构作对比,得出自己当初要等待的文件是否就绪的结论。

无论是读取数据,还是写入数据,再或者是异常事件,都是采用这样的方式和机制。

struct timeval* timeout表示的阻塞等待时间,操作系统内部也会进行修改,假设初值是{5, 0}表示阻塞等待5s中,如果5s内没有事件就绪则select返回0,表示超时返回,此时原本传入的time的值也变成了{0, 0}

如果5s内有事件就绪,假设操作系统等待了3秒,selsect返回值大于0,表示不是超时返回,有事件就绪,此时原本传入的time的值也变成了{2, 0},表示设置的阻塞事件还剩两秒。

  • 所以在轮询过程中,每循环一次就需要重新设置一下时间,否则第一次超时返回后,time的值就成了0,之后select就成了非阻塞IO,与初衷不符。
  • 输入输出型参数的作用就是让用户和内核之间相互沟通,互相知晓对方要关心的。

🧁简易select服务器

本喵将创建套接字的代码封装成了一个Sock类,使用的时候直接调用即可,同样可以将其作为一个小组件。
图
如上图上,Sock类中包含套接字的创建,绑定,监听,以及获取新连接等四个方法,这些函数中还包含日志信息,具体的日志代码本喵就不贴了,有兴趣的小伙伴自行去查阅日志功能。

图
如上图所示便是select简易服务器的基本配置,成员变量包含监听套接字,端口号,用户维护的用于设置等待位图的数组_fdarry,以及回调函数。

定义了几个全局默认变量,包括默认端口号,select所能等待文件的上限1024,以及用户维护数组的初始默认值。

  • initServer():初始化服务器

图
如上图所示,第一步便是初始化服务器,在系统中创建套接字,进行绑定和监听,构建完整的会话层。之后将用户维护的用来设置等待位图的数组进行初始化,大小是1024个元素,初始值都是-1。

  • 0,1,2文件描述符不用select等待,从listen套接字开始进行等待。
  • Start():启动服务器

图
如上图所示,服务器在启动后,是一个while(1)的死循环,在这个循环中进行一遍又一遍的轮询。

由于select的后面四个参数都是输入输出型参数,所以每一次轮询之前都需要重新设置一遍,否则就会因为操作系统的修改而出现问题。需要重新设置位图状态,重新设置等待时间等等。

  • 每次轮询的时候,都需要将用户维护的数组中需要等待的文件描述符重新设置到fd_set位图中。

在将参数设置好以后便调用select系统调用,用switch将返回的情况分别处理,当n>0时,说明有文件就绪,可以去读取,所以调用HandlerReadEvent函数去处理该事件。

事件处理函数:
图
如上图所示,当执行到该函数的时候,必有套接字就绪,此时用户要做的就是判断到底是哪个套接字上事件就绪。

第一次执行该函数的时候,必然是监听套接字就绪,因为当前select等待的只有这一个套接字,所以判断符合条件以后,去执行Accepter函数来获取新连接。

  • 监听套接字就绪也是属于读事件就绪,因为此时有新连接到来,需要用户去将新连接读取走。

图
如上图所示,当监听套接字就绪后,用户第一时间肯定就是读取监听到的新连接,并且获取客户端的IP地址以及端口号。

新连接获取成功后,由于此时没有客户端的数据到来,所以新连接套接字没有就绪。

  • 此时必须将新连接套接字交给select去等待就绪,所以需要向用户层维护的数组中添加该套接字的文件描述符。
  • 如果此时直接读取新连接套接字的话,由于没有就绪,就会阻塞在这里,服务器无法继续执行下去,与我们的初衷就不符合了。

图
为了方便,本喵还增加了一个Print函数,打印新增加的需要select等待的文件描述符。


第一次之后调用Accepter函数时,已经就绪的文件就不一定是监听套接字了,有可能是前面获取的新连接套接字,所以就需要进行具体判断到底是哪个套接字就绪了。当新连接套接字就绪后,就调用Recver从套接字中读取客户端的请求。

图
如上图所示,当新连接套接字就绪以后,首先要进行的就是读取套接字中客户端发来的数据,使用recv获取数据。

  • 当前这种读取数据的方式是存在一定问题的,因为不能保证套接字中的数据是否被读完了。

但是此时并不会产生影响,所以暂且这样,后面本喵会制定具体的协议去处理它。

如果读取数据出现了问题,或者套接字出现异常,那么就需要关闭套接字,并且将文件描述符从用户维护的数组中清除。

读取成功后将请求处理,并且构建响应发送给客户端,当前的select服务端的重点在于读取,所以写入本喵这里就不详细写了。


  • selectServer.cpp

tu
如上图所示就是selectServer.cpp中的代码,服务器的回调函数中仅是将客户端发送来的数据原封不动的响应给客户端,没有做其他处理,其他部分代码本喵不再解释。

图
如上图所示,当服务器开始运行后,由于此时没有新连接到来,所以监听套接字一直处于未就绪的状态,前面在设置等待事件的时候设置了5s,所以每隔5s就超时返回一次。

  • 可以看到当前最大文件描述符是3,也就是监听套接字的文件描述符。

图
如上图所示,为了避免超时返回的干扰,本喵将select的最后一个参数也设置成nullptr此时select就是阻塞等待,根据运行结果也可以看成是阻塞不动的。

图

如上图所示,此时使用两个telnet连接客户端,可以看到服务端提示有新事件就绪,此时是监听套接字监听到了两个客户端连接,所以显示两次,服务端每处理一次,用户层维护的数组中文件名描述符就会增加一个,所以最终是3,4,5三个文件需要select进行等待。

两个客户端向服务端发送消息的时候,服务端显示事件就绪,这是进行数据通信的套接字上有数据到来,提醒用户层去读取数据。

  • 服务器上只有一个进程(线程),客户端有多个,此时服务端可以同时接收多个客户端的连接请求和数据。
  • 多路转接实现了我们之前只能通过多进程或者多线程才能实现的功能,而且效率非常高。

🧁select的特点

  1. select能同时等待的文件fd是有上限的,除非重新修改内核,否则无法解决。

fd_set位图大小只有1024个比特位,意味着select同时最多只能等待1024个文件描述符。

图
可以看到,本喵的Linux机器上,最多可以打开100001个文件,远大于1024,所以说select能够同时等待的文件数量在高访问量的服务器中是远远不够的。

  1. 必须借助第三方数组等结构来维护需要select等待的文件描述符fd。

由于select的后四个参数都是输入输出型参数,操作系统也会修改这几个参数,这就导致用户层必须自己维护一个数组来记录自己曾经想要让select等待的文件描述符。

并且每轮询一次就需要重新设置一次fd_set位图,不仅繁琐,而且对于效率相对较低。

  1. select存在遍历成本。

在上面本喵实现的服务器代码中,对于用户层来说,存在多处遍历所维护的数组。

在将文件描述符设置到fd_set位图中的时候,需要遍历数组中的所有元素来找到合法的fd设置到位图中。

select完成等待后,同样需要遍历一次数组,来确定是哪个fd的事件就绪了,然后再去处理。

  1. 内核也要进行遍历

select的第一个参数传参时传入的是最大文件描述符fd + 1,这个参数就是为了让内核确定遍历的范围,这个值之前的所有文件描述符,操作系统都会进行查看,看看是否有事件就绪。

  1. 内核和用户层来回拷贝的成本问题

select采用的是位图来标记哪个文件的事件就绪,无论是用户层告诉内核,还是内核告诉用户层,都需要拷贝,这样来回进行数据拷贝也是有很大的成本。


🍧总结

多路转接是一个非常重要的IO模式,而select方式只最基础的一种,它主要的作用是带领我们理解多路转接,后面本喵还会讲解pollepoll方式。

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

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

相关文章

SpringBoot中间件ElasticSearch

Elasticsearch是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的 全文搜索引擎 &#xff0c;基于RESTful web 接口。 Elasticsearch 是用 Java 语言开发的&#xff0c;并作为 Apache 许可条款下的开放源码发布&#xff0c;是一种流行的企业级搜索引擎。Elastics…

基于Servlet实现博客系统--- 前后端分离

目录 一.博客系统概述 1.软件的生命周期 2.学习目标 二.数据库的建立 2.插入数据 三.创建项目 1.建立maven项目 2.导入相关的依赖 3.编写工具类 1.编写数据库相关的工具类 2.编写字符串的工具类 3.编写用户的工具类 4.创建实体类 1.创建user实体类 2.创建blog…

ant-vue1.78版监听a-modal遮罩层的滚动事件

监听a-modal遮罩层的滚动事件 我们开发过程中经常有遇到监听页面滚动的事件需求&#xff0c;去做一些下拉加载或者是下拉分页的需求&#xff0c;我们直接在vue的生命周期中去绑定事件监听非常的方便&#xff0c;但如果是弹框的遮罩层的滚动监听呢&#xff1f;页面的监听完全是…

学习pytorch6 torchvision中的数据集使用

torchvision中的数据集使用 1. torchvision中的数据集使用官网文档注意点1 totensor实例化不要忘记加括号注意点2 download可以一直保持为True代码执行结果 2. DataLoader的使用 1. torchvision中的数据集使用 官网文档 注意左上角的版本 https://pytorch.org/vision/0.9/ 注…

【业务功能篇81】微服务SpringCloud-ElasticSearch-Kibanan-docke安装-入门实战

ElasticSearch 一、ElasticSearch概述 1.ElasticSearch介绍 ES 是一个开源的高扩展的分布式全文搜索引擎&#xff0c;是整个Elastic Stack技术栈的核心。它可以近乎实时的存储&#xff0c;检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;…

【漏洞复现】万户协同办公平台未授权访问漏洞

漏洞描述 万户ezOFFICE协同管理平台涵盖门户自定义平台、信息知识平台管理、系统管理平台功能&#xff0c;它以工作流引擎为底层服务&#xff0c;以通讯沟通平台为交流手段&#xff0c;以门户自定义平台为信息推送显示平台&#xff0c;为用户提供集成的协同工作环境。该平台存…

软件测试面试题及答案,2023秋招必看版

导读 精选400道软件测试面试真题&#xff0c;高清打印版打包带走&#xff0c;横扫软件测试面试高频问题&#xff0c;涵盖测试理论、Linux、MySQL、Web测试、接口测试、APP测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块…

【方案】基于AI边缘计算的智慧工地解决方案

一、方案背景 在工程项目管理中&#xff0c;工程施工现场涉及面广&#xff0c;多种元素交叉&#xff0c;状况较为复杂&#xff0c;如人员出入、机械运行、物料运输等。特别是传统的现场管理模式依赖于管理人员的现场巡查。当发现安全风险时&#xff0c;需要提前报告&#xff0…

python VTK PyQt5 VTK环境搭建 创建 渲染窗口及三维模型,包含 三维模型交互;

目录 Part1. VTK 介绍 Part2. PyQt5 VTK环境搭建 安装Anaconda 自带Python Anaconda下载 安装PyQt5 安装 VTK Part3 :PyQt VTK 结合样例: Part1. VTK 介绍 VTK&#xff08;visualization toolkit&#xff09;是一个开源的免费软件系统&#xff0c;主要用于三维计算机图形…

【Python开发环境搭建】【Pycharm设置】 新建python文件默认添加编码格式、时间、作者、文件名等信息

1、设置路径 打开pycharm&#xff0c;选择File->Settings&#xff08;Ctrl Alt S&#xff09;&#xff0c;Editor->File and Templates->Python Script 文件- 设置-编辑器-文件和代码模板-Python Script 2、设置内容 # -*- coding: utf-8 -*- # Time : ${DATE} …

SmartInspect Professional .Net Delphi Crack

SmartInspect Professional .Net & Delphi Crack SmartInspect Professional是一个用于调试和跟踪.NET、Java和Delphi软件的高级日志记录工具。它使您能够识别错误&#xff0c;找到客户问题的解决方案&#xff0c;并让您清楚地了解软件在不同环境和条件下的工作方式。可以轻…

【广州华锐互动】VR沉浸式体验红军长征路:追寻红色记忆,传承红色精神

在历史的长河中&#xff0c;长征无疑是一段充满艰辛和英勇的伟大征程。为了让更多的人了解这段历史&#xff0c;我们利用虚拟现实&#xff08;VR&#xff09;技术&#xff0c;为您带来一场沉浸式的体验&#xff0c;重温红军万里长征的壮丽篇章。 一、踏上长征之路 戴上VR眼镜&a…

Hbase--技术文档--单机docker基础安装(非高可用)

环境准备-docker 配置Linux服务器华为云耀云服务器之docker安装&#xff0c;以及环境变量安装 java &#xff08;虚拟机一样适用&#xff09;_docker配置java环境变量_一单成的博客-CSDN博客 说明&#xff1a; 本文章安装方式为学习使用的单体hbase项目。主要是学习&#xff…

win10+wsl2+Ubuntu20.2+Pycharm+WSL解释器

目的&#xff1a;创建一个ubuntu系统下的python解释器&#xff0c;作为win平台下的pycharm的解释器。 这样做的好处是可以直接在win系统里操作文件&#xff0c;相比于linux方便一点&#xff0c;而且也不用对wsl的子系统进行迁移。 一、安装前准备 1. 设置-Windows更新-window…

[C++ 网络协议] 套接字的多种可选项

目录 1. 套接字的可选项 2. 获取/设置套接字可选项 2.1 getsockopt函数&#xff08;获取套接字可选项&#xff09; 2.2 setsockopt函数&#xff08;设置套接字可选项&#xff09; 3. 常用套接字可选项 3.1 SOL_SOCKET协议层的SO_TYPE可选项 3.2 SOL_SOCKET协议层的SO_SN…

IET独立出版 | EI检索 | 2023年第三届机械、航空航天与汽车工程国际会议

会议简介 Brief Introduction 2023年第三届机械、航空航天与汽车工程国际会议&#xff08;CMAAE 2023&#xff09; 会议时间&#xff1a;2023年12月8 -10日 召开地点&#xff1a;中国南京 大会官网&#xff1a;www.cmaae.org 航天是当今世界最具挑战性和广泛带动性的高技术领域…

Vue3 Element-plus Upload 上传图片

技术栈&#xff1a;Vue3 Ts Element-plus 官网地址&#xff1a;Upload 上传 | Element Plus 一、背景&#xff1a; 表单上传图片功能 二、效果&#xff1a; 三、流程&#xff1a; ①点击上传图片按钮&#xff0c;系统弹出文件选择对话框&#xff0c;选择图片并确认 ②调…

nvm安装及使用说明

1.说明&#xff1a; nvm 一个nodejs版本管理工具&#xff01; 2.官网&#xff1a;https://nvm.uihtm.com/ 3.卸载node.js&#xff08;没安装的话忽略&#xff09; 4.下载 链接&#xff1a;https://nvm.uihtm.com/nvm-1.1.10-setup.zip 5.nvm安装 卸载之前的node后安装nvm…

SpringCloud教程 | 第二篇: 服务消费者(rest+ribbon)

在上一篇文章&#xff0c;讲了服务的注册和发现。在微服务架构中&#xff0c;业务都会被拆分成一个独立的服务&#xff0c;服务与服务的通讯是基于http restful的。Spring cloud有两种服务调用方式&#xff0c;一种是ribbonrestTemplate&#xff0c;另一种是feign。在这一篇文章…

ADS 错误 1808可能原因 ADSError 1808

​ 调试问题记录&#xff1a; 背景&#xff1a; Ads调试时遇到错误&#xff0c;返回码是 1808&#xff0c;查询倍福官网 得出1808错误原因是 symbol not found 原因&#xff1a; ADSError: symbol not found (1808). Possible incorrect runtime port selected 可能是ads的地…
最新文章