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

【linux】重定向+缓冲区

重定向+缓冲区

  • 1.重定向
    • 1.1重定向本质
    • 1.2重定向接口
    • 1.3重定向分类
      • 1.3.1>输出重定向
      • 1.3.2>>追加重定向
      • 1.3.3<输入重定向
  • 2.理解 >, >>, <
  • 3.如何理解linux下一切皆文件
  • 4.缓冲区
    • 4.1理解缓冲区问题
      • 4.1.1为什么要有缓冲区
      • 4.1.2缓冲区刷新策略的问题
      • 4.1.3缓冲区在哪里,指的是什么缓冲区
      • 4.1.4如何解释fork问题
  • 5.缓冲区该如何理解
    • 5.1myStdio.h
    • 5.2myStdio.c
      • 5.2.1_fopen
      • 5.2.2_fwrite
      • 5.2.3_fflush
      • 5.2.4_fclose
    • 5.3main.c
  • 6.缓冲区和OS的关系

自我名言只有努力,才能追逐梦想,只有努力,才不会欺骗自己。在这里插入图片描述
喜欢的点赞,收藏,关注一下把!在这里插入图片描述

1.重定向

  1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13     close(1);                                                                                                                                                    14     umask(0);                                                         15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);             16     if(fd == -1)                                                      17     {                                                                 18         perror("open");                                               19         exit(1);                                                      20     }                                                                 21     printf("fd:%d\n",fd);                                             22                                                                       23     close(fd);                                                        24                                                                       25     return 0;                                                         26 }  

在这里插入图片描述

close(1),为什么没有打印新建文件fd呢?

printf(“%d\n”,fd); printf会把内容打印到stdout文件中。
但是close(1)关闭标准输出stdout—>显示器,int fd=open();新打开的文件fd是1。
stdout–>fd–>1,虽然我们手动关闭了stdout,但是系统并不知道,还以为fd为1的位置是stdout,但是这个位置现在已经被新打开的文件占用了,所以打印到了新打开的文件里。

  1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13     close(1);14     umask(0);15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);16     if(fd == -1)17     {18         perror("open");19         exit(1);20     }21     printf("fd:%d\n",fd);22     23     //这里必须刷新一下,不然log.txt里面没有内容,这里和缓冲区有关,下面讲                                                                                                                  24     fflush(stdout);      25     close(fd);           26                          27     return 0;            28 } 

在这里插入图片描述

本来应该打印到显示器文件中,但是却写到文件里了。------>重定向

1.1重定向本质

在这里插入图片描述

1.2重定向接口

在这里插入图片描述
这个主要介绍dup2函数。

int dup2(int oldfd, int newfd);

在这里插入图片描述
那怎么使用dup2来实现刚才的效果,把打印到显示器内容,写入到"log.txt"
在这里插入图片描述
是上面那样写的,还是下面那样写的,我们分析分析。
在这里插入图片描述
画图分析
在这里插入图片描述
在这里插入图片描述
因此正确写法如下
在这里插入图片描述

  4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13    // close(1);14     umask(0);15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);16     if(fd == -1)17     {18         perror("open");19         exit(1);20     }21     //重定向                                                                                                                                                     22     dup2(fd,1);                                                                                                               23     printf("fd:%d\n",fd);                                                                                                     24                                                                                                                               25     //这里必须刷新一下,不然log.txt里面没有内容                                                                               26     fflush(stdout);                                                                                                           27     close(fd);                                                                                                                28                                                                                                                               29     return 0;                                                                                                                 30 }  

在这里插入图片描述

1.3重定向分类

1.3.1>输出重定向

上面内容就是输出重定向,把新打开文件的fd重定向到fd为1(默认为显示器)的位置。

1.3.2>>追加重定向

    1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11    // close(0);12    // close(2);13    // close(1);14     umask(0);15    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);16     int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);17     if(fd == -1)18     {19         perror("open");20         exit(1);21     }22     //重定向23     dup2(fd,1);24     printf("你好\n");25     printf("吃了吗\n");                                                                                                                                           26                                                                                                                           27     //这里必须刷新一下,不然log.txt里面没有内容                                                                           28     fflush(stdout);                                                                                                       29     close(fd);                                                                                                            30                                                                                                                           31     return 0;                                                                                                             32 } 

在这里插入图片描述

1.3.3<输入重定向

#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>int main()    
{    // close(0);    // close(2);    // close(1);    umask(0);    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);    // int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);    int fd=open("log.txt",O_RDONLY);    if(fd == -1)    {      perror("open");      exit(1);      }      //输入重定向    dup2(fd,0);                                                                                                                                                      char outbuffer[64];        while(1)                   {                          printf("<");                                                     if(fgets(outbuffer,sizeof(outbuffer),stdin) == NULL) break;      printf("%s",outbuffer);                                                                                                                        }return 0;}   

在这里插入图片描述

2.理解 >, >>, <

在前面实现过一个自己的shell,现在我们给这个shell增加重定向功能来理解重定向。
在这里插入图片描述

//增加一个分割指令和文件名的函数                                                                                                                               
commandstrtok(lineCommand);

分割的时候,我们需要知道重定向是什么类型,文件是什么名字,因此增加两个全局变量来记录。

  //重定向类型    //第一个为初始重定向     #define DEFAULT_REDIR 0    #define INPUT_REDIR 1  #define OUTPUT_REDIR 2    #define ERROR_EDIRR 3    //重定向类型+文件名    int redirType=DEFAULT_REDIR;    char* redirFile=NULL;    

分割函数

  //这里找文件名没有写成函数,而写个宏#define trimSpace(start) do{\while(isspace(*start)) ++start;\}while(0)void commandstrtok(char* cmd){assert(cmd);char* start=cmd;char* end=cmd+strlen(cmd);while(start < end){if(*start == '<'){*start=0;++start;//这里可能 ls -a -l >      log.txt,trimSpace(start);redirType=INPUT_REDIR;redirFile=start;break;}else if(*start == '>')                                                                                                                                 {                                                                                                                                                      *start=0;                                                                                                                                          ++start;                                                                                                                                           if(*start == '>')                                                                                                                                  {                                                                                                                                                  redirType=APPEND_REDIR;                                                                                                                        ++start;                                                                                                                                       }                                                                                                                                                  else                                                                                                                                               {                                                                                                                                                  redirType=OUTPUT_REDIR;                                                                                                                        }                                                                                                                                                  trimSpace(start);                                                                                                                                  redirFile=start;                                                                                                                                       break;                                                                                                                                             }                                                                                                                                                      else{                                                                                                                                                      ++start;}}

因为命令是子进程执行的,真正重定向的功能一定是由子进程来完成的,
但是如何重定向是父进程要告知给子进程的。

//创建子进程
pid_t id = fork();
assert(id != -1);
if(id == 0)
{             switch(redirType){case INPUT_REDIR:{int fd=open("log.txt",O_RDONLY);if(fd <0){perror("open");return 1;}//重定向文件已经打开了dup2(fd,0);}break;case OUTPUT_REDIR:case APPEND_REDIR:{umask(0);int flags=O_WRONLY|O_CREAT;if(redirType == OUTPUT_REDIR) flags|=O_CREAT;else flags|=O_APPEND;                                                                                                                     int fd=open("log.txt",flags,0666);if(fd < 0){perror("open");return 1;}dup2(fd,1);     }break;default:printf("bug?\n");break;}//程序替换execvp(myargv[0],myargv);exit(1);
}

在这里插入图片描述

shell完整代码

问:子进程重定向会影响父进程吗?

不会
在这里插入图片描述

问:指向程序替换的时候,会不会影响曾经进程打开的重定向文件呢?

不会
在这里插入图片描述

3.如何理解linux下一切皆文件

Linux下一切皆文件,那键盘,显示器,磁盘,网卡等硬件在linux下都是文件吗?
可以这样说的。
在这里插入图片描述
在这里插入图片描述

站在struct file上层看来,所有的设备和文件,统一都是struct file--------->Linux下一切皆文件。

在这里插入图片描述

这里可能有这样一个问题,如果同一个文件被多个指针指向,但是某个进程把这个文件关了,会不会影响其他进程对这个文件的操作呢?

其实并不会,一个被打开的文件有引用计数
在这里插入图片描述
表明有几个指针指向这个文件,这样做是因为一个文件可能被多个指针指向。如果某个进程关闭文件,影响到其他进程,就不能保证进程的独立性。close关闭文件,其实并不是真正关闭文件,只是把引用计数减1,当只有一个指针指向这个文件,close关闭文件才是真正关闭这个文件。

4.缓冲区

先看一种现象。

  1 #include<stdio.h>  2 #include<string.h>                                                        3 #include<sys/types.h>  4 #include<sys/stat.h>  5 #include<fcntl.h>  6 #include<unistd.h>  7 #include<stdlib.h>  8   9 int main()  10 {  11     printf("hello printf\n");  12     fprintf(stdout,"%s\n","hello fprintf");  13   14   15     const char* output="hello write\n";  16     write(1,output,strlen(output));  17   18                                                                                                                                                                  19     return 0;  20 }     

在这里插入图片描述

  1 #include<stdio.h>2 #include<string.h>3 #include<sys/types.h>4 #include<sys/stat.h>5 #include<fcntl.h>6 #include<unistd.h>7 #include<stdlib.h>8 9 int main()10 {11     printf("hello printf\n");12     fprintf(stdout,"%s\n","hello fprintf");13 14 15     const char* output="hello write\n";16     write(1,output,strlen(output));17 18     fork();                                                                                                                                                      19     return 0;                                                                                                                           20 }    

在这里插入图片描述
对比两张图片,第二段代码补充fork(创建子进程),重定向之后,C接口的函数,被打印了两次,系统调用的接口前面都只是打印了一次。

这是什么原因?现在只是知道肯定是fork函数有关。
其实这里也和缓冲区有关。

4.1理解缓冲区问题

缓冲区本质就是一段内存!!!

4.1.1为什么要有缓冲区

这里讲一个小故事,帮助理解。

在四川的张三要给远在北京的李四送一个键盘。
在这里插入图片描述
张三为了节省时间,选择2;
现实中快递行业的意义?
节省发送者的时间。

进程把数据打包给磁盘,是一个很慢的过程,如果让进程一直等着显然不太好。因此我们也需要一个快速的方式----->缓冲区

在这里插入图片描述
缓冲区的意义是什么呢?

节省进程进行数据IO的时间。

但是我们在用文件写的接口时,并没有专门拷贝数据啊?(以fwrite为例)

其实与其理解fwrite是写入到文件的函数,倒不如理解fwrie是拷贝函数,将数据从进程拷贝到"缓冲区"或者“外设”中。

4.1.2缓冲区刷新策略的问题

把东西给顺丰之后,那顺丰什么时候发货呢?

张三第二天在想寄一个鼠标给李四,当走到快递站点发现自己昨天的快递还没有发走,就问快递人员,快递人员说,我们的快递都是用大货车和飞机发送的,就这一个快递不可能马上就发走,等到满足发送件货才发。

缓冲区的刷新策略:
在这里插入图片描述
不同外设IO访问速度是不同的。
缓冲区结合具体的设备,定制自己的刷新策略。(3策略,2特殊)

3策略
a.立即刷新 ----> 无缓冲
b.行刷新 ----> 行缓存 ----> 显示器 (显示器是给人看的,如果一次给很多信息,人看着不舒服)
c.缓冲区满 ----> 全缓存 ----> 磁盘文件(显示器除外)

2特例
1:用户强制刷新 (fflush)
2:进程退出 (进程退出要刷新缓冲区)

4.1.3缓冲区在哪里,指的是什么缓冲区

C接口打印了两次,系统调用接口打印了一次,这种现象一定和缓冲区有关。
虽然现在不知道缓冲区在哪里,但是我们知道缓冲区一定不在内核中
因为C接口底层调用的是系统调用接口,如果缓冲区在内核中,write也应该打印两次。

那缓冲区到底在哪?

我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区
还记得C程序默认给我们打开stdin,stdout,stderr都是------->FILE*------>指向FILE结构体,结构体包含-------> fd,其实还包含一个缓冲区

因此,缓冲区在FILE结构体中。

所以当我们自己要强制刷新:fflush(文件指针),关闭:fclose(文件指针)传的都是FILE*。因为缓存区在FILE结构体中。

4.1.4如何解释fork问题

在这里插入图片描述
代码结束之前,创建子进程。

1.我们没有进行>输出重定向,看到了三条信息。

stdout默认使用的是行刷新,在fork之前,两条C函数已经将数据打印输出到到显示器上,你的FILE内部,进程内部不存在对应的数据了。这时创建子进程,等到子进程,父进程退出的时,都要刷新缓冲区,但是这时缓冲区已经没有内容可以刷新了。因此C函数打印两条信息。

2.>输入重定向之后,C接口打印两次

当我们进行>,写入文件就不再是显示器,而是普通文件,采用的刷新策略是全缓存,之前2条C打印函数,虽然带了\n,但是不足与将stdout缓冲区写满,数据并没有被刷新。
fork的时候,stdout属于父进程,创建子进程紧跟着就是进程退出,谁先退出,一定要进行缓冲区刷新(缓存区刷新---->就是修改)
这时就有了写时拷贝!! 因此C接口,数据最终会显示两份。

3.write为什么前后只打印一次

上面过程都是write无关,write没有FILE,而用的是fd,就没有C提供的缓冲区。

5.缓冲区该如何理解

自己写一个简易的缓冲区,来帮助理解"数据刷新策略"+“数据如何缓存”

5.1myStdio.h

  1 #pragma once  2 #include<errno.h> 3 #include<stdio.h>      4 #include<string.h>      5 #include<sys/types.h>      6 #include<sys/stat.h>      7 #include<fcntl.h>      8 #include<unistd.h>      9 #include<stdlib.h> 10   11 #define SIZE 1024    12 #define SYNC_NOW 1    13 #define SYNC_LINE 2      14 #define SYNC_FULL 3     15                      16 typedef struct _FILE{  17     int flags;//刷新方式  18     int fileno;  //文件描述符19     int capacity;//buffer容量  20     int size;//buffer当前使用量  21     char buffer[SIZE]; //缓冲区22 }_FILE;              23   24                      25 _FILE* _fopen(const char* path_name,const char* mode);  26 void _fwrite(const void* ptr,int num,_FILE* fp);                                                                                                                 27 void _fclose(_FILE* fp);  28 void _fflush(_FILE* fp);  

5.2myStdio.c

5.2.1_fopen

 _FILE* _fopen(const char* path_name,const char* mode)
{assert(path_name);int flags=0;int defaultmode=0666;if(strcmp(mode,"r") == 0){flags|=O_RDONLY;}else if(strcmp(mode,"w") == 0){flags|=(O_WRONLY|O_CREAT|O_TRUNC);}else if(strcmp(mode,"a") == 0){flags|=(O_WRONLY|O_CREAT|O_APPEND);}int fd=0;if(flags & O_RDONLY){fd=open(path_name,flags);}else{fd=open(path_name,flags,defaultmode);                                                                                                                        }if(fd < 0){const char*err=strerror(errno);write(2,err,strlen(err));return NULL;//这就是为什么创建文件失败,返回NULL}_FILE* fp=(_FILE*)malloc(sizeof(_FILE));assert(fp);fp->flags=SYNC_LINE;fp->fileno=fd;fp->capacity=SIZE;fp->size=0;memset(fp->buffer,0,SIZE);return fp;
}

5.2.2_fwrite

void _fwrite(const void* ptr,int num,_FILE* fp)                                                                                       
{                                                                                   //写到缓冲区里                                                                                                                  memcpy(fp->buffer+fp->size,ptr,num); //这里没有考虑缓冲区溢出问题                                                                                           fp->size+=num;                                                                                                                  //判断是否要刷新                                                                                                                if(fp->flags & SYNC_NOW)                                                                                                        {                                                                                                                               write(fp->fileno,fp->buffer,fp->size);                                                                                       fp->size=0;//清空缓冲区                                                                                                     }                                                                                                                               else if(fp->flags & SYNC_LINE)                                                                                                  {                                                                                                                               if(fp->buffer[fp->size-1] == '\n')  //这里也没有考虑abc\ndef这种形式,如果是这样的可以用for循环                                                                                        {                                                                                                                            write(fp->fileno,fp->buffer,fp->size);                                                                                       fp->size=0;                                                                                                             }                                                                                                                           }                                                                                                                               else if(fp->flags & SYNC_FULL)                                                                                                  {                                                                                                                               if(fp->size == fp->capacity)                                                                                                {                                                                                                                            write(fp->fileno,fp->buffer,fp->size);                                                                                       fp->size=0;                                                                                   }                                                                                                                           }                                                                                                                               
}     

5.2.3_fflush

void _fflush(_FILE* fp)                                                                                       
{                                                                                       if(fp->size > 0) write(fp->fileno,fp->buffer,fp->size);                                                                                       fsync(fp->fileno); //把数据强制从内核缓冲区刷新到磁盘                                                                                     fp->size=0;                                                                                                                                                      
} 

这里引入了内核缓冲区,下面解释。

5.2.4_fclose

void _fclose(_FILE* fp)                                                                                       
{                                                                                       _fflush(fp);  close(fp->fileno);                                                                                                                                               
}    

5.3main.c

行刷新

  1 #include"myStdio.h"2 3 4 int main()5 {6     _FILE* fp=_fopen("log.txt","w");7     if(fp == NULL)8     {9         perror("_fopen");10         return 1;11     }12 13     int cnt=10;14     const char* msg="hello linux\n";15     while(1)16     {17         _fwrite(msg,strlen(msg),fp);18         sleep(1);19         printf("count:%d\n",cnt--);20         if(cnt == 0) break;21     }                                                                       22     _fclose(fp);23 24     return 0;25 }

在这里插入图片描述

退出刷新

    1 #include"myStdio.h"2 3 4 int main()5 {6     _FILE* fp=_fopen("log.txt","w");7     if(fp == NULL)8     {9         perror("_fopen");10         return 1;11     }12 13     int cnt=10;14     const char* msg="hello linux";15     while(1)16     {17         _fwrite(msg,strlen(msg),fp);18         sleep(1);19         printf("count:%d\n",cnt--);                                       20         if(cnt == 0) break;21     }                    22     _fclose(fp);         23                          24     return 0;            25 }  

在这里插入图片描述
立即刷新

  1 #include"myStdio.h"2 3 4 int main()5 {6     _FILE* fp=_fopen("log.txt","w");7     if(fp == NULL)8     {9         perror("_fopen");10         return 1;11     }12 13     int cnt=10;14     const char* msg="hello linux";15     while(1)16     {17         _fwrite(msg,strlen(msg),fp);18         _fflush(fp);                                                        19         sleep(1);20         printf("count:%d\n",cnt--);21         if(cnt == 0) break;22     }          23     _fclose(fp);24                25     return 0;  26 }   

在这里插入图片描述

6.缓冲区和OS的关系

在这里插入图片描述
这里是由write函数,直接把数据写到磁盘上的文件中吗?
其实并不是这样的。
在这里插入图片描述
在这里插入图片描述
write并不是直接把缓冲区里的内容刷新到文件中,在打开文件对应的struct file{}结构体中其他有一个方法指针,还有一个指向内核缓冲区的指针,系统会把FILE结构体里面缓冲区内容通过struct file{}找到内核缓冲区,再由write()拷贝到内核缓冲区,然后再由这个内核缓冲区把内容刷新到文件中区,至于如何刷新和用户毫无关系,我们所知道的行刷新等,这是由语言层面所分类的,而内核缓冲区刷新由OS自主决定。

那么我们该如何证明有这个内核缓冲区呢?
超级大佬可以证明,这里证明不了,但是我们可以看到接口。
在这里插入图片描述
还有一个问题,如果OS突然宕机了会发生什么情况?
数据肯定会丢失。如果还是按照OS规定的内核缓冲区刷新策略肯定是不行的。
我们希望可以在用户层就告知OS,内核缓冲区不要再给我缓存了,赶紧把数据刷新到磁盘中。

这里介绍fsync函数

在这里插入图片描述
强制性把该文件对应的内核缓冲区数据持久到磁盘。就是OS不要给我缓存了,赶紧把数据给我更新到磁盘上。

相关文章:

【linux】重定向+缓冲区

重定向缓冲区 1.重定向1.1重定向本质1.2重定向接口1.3重定向分类1.3.1>输出重定向1.3.2>>追加重定向1.3.3<输入重定向 2.理解 >&#xff0c; >>&#xff0c; <3.如何理解linux下一切皆文件4.缓冲区4.1理解缓冲区问题4.1.1为什么要有缓冲区4.1.2缓冲区刷…...

【vim 学习系列文章 10 -- vim 将代码中空格高亮显示方法】

文章目录 vim 高亮空格使用背景如何配置vim 可以自动显示空格呢&#xff1f;vim highlight 命令使用介绍vim 空白行的处理vim match 命令详细介绍 vim 高亮空格使用背景 开发人员在编写代码之后&#xff0c;在review通过之后会将代码推到服务器然后merge&#xff0c;但是有些代…...

吴恩达深度学习笔记

B站看的视频&#xff0c;课太长了&#xff0c;180多节&#xff0c;但搬运的没有作业练习&#xff0c;最好找个能练习的 1&#xff0c;假设模型时&#xff0c;以前(2011版机器学习)用西塔代表参数组成的向量&#xff0c;现在用w代表参数组成的向量&#xff0c;b代表西塔0&#x…...

基于SpringBoot的医疗预约服务管理系统

基于SpringBootVue的医疗预约服务管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 登陆界面 管理员界面 医生界面 会员界面 摘要 基于SpringBoot的…...

Java本地缓存的使用

在项目开发中&#xff0c;经常会碰到一些数据量小、但使用频率极高的数据。比如&#xff0c;团队到BU的映射表。此类数据通常不会变动&#xff0c;使用频率高且数据量较小&#xff0c;如果每次使用都去数据库查询&#xff0c;代价比较大&#xff0c;可以考虑在项目启动时将此类…...

华为数通方向HCIP-DataCom H12-831题库(单选题:281-300)

第281题 如图所示,某工程师利用4台路由器进行网络互通测试,其中R1、R2、R3部署OSPF (Area0)实现网络互通,R2、R3、R4部署IS-IS(均部署为Level-2路由器)实现网络互通,现在该工程师在R1的OSPF进程中引入直连路由,在R2的IS-IS进程中引入OSPF路由,则以下关于该场景的描述,正…...

【分享Python代码】图片转化为素描画

哈喽&#xff0c;大家好&#xff0c;我是木易巷~ 代码生成效果图 原图&#xff1a; 生成图&#xff1a; 原图&#xff1a; 生成图&#xff1a; 准备工作 Python编程首先需要安装环境&#xff0c;下面是详细步骤&#xff1a; 会的小伙伴可自行跳过&#xff0c;代码在最后 1…...

汇川Easy521PLC与压力传感器485通讯实例

本例是汇川Easy521PLC与支持485通讯的压力传感器进行通讯的实例记录。对于初次使用汇川PLC的朋友,可能有借鉴的意义。 配置: 1、汇川Easy521PLC 2、美控压力变送器 3、汇川Autoshop编程软件 将压力变送器的485线与PLC本体的485端子一一连接: 485+:A+ 485-:B- 一般485的标…...

创意作品管理软件 Bridge 2024 mac中文版 br2024功能特色

Bridge 2024 mac旨在连接不同的Ad obe应用程序&#xff0c;帮助用户更轻松地管理和编辑他们的创意作品。 Bridge 2024 mac软件特色和功能介绍 一致的用户体验&#xff1a;Bridge 2024现在具有增强的用户界面&#xff0c;可提供与其他Creative Cloud应用程序类似的体验。用户还…...

【分享】教你加速访问GitHub,进来学!

哈喽&#xff0c;大家好&#xff0c;木易巷来啦&#xff01; 众所周知&#xff0c;Github是一款程序猿必备的代码托管平台&#xff0c;上面已经存在了无数前辈的心血&#xff01;经常需要在上面查看大佬写的一些好用的开源项目&#xff0c;无赖国外网站的速度实在让人难以接受。…...

利用在线培训系统提升员工技能,助力企业发展

近年来&#xff0c;随着互联网技术的发展&#xff0c;在线培训系统逐渐成为企业提升员工技能的利器。这种新型的培训方式打破了时间和空间的限制&#xff0c;为企业提供了更加灵活和高效的培训解决方案。下面&#xff0c;我们将详细介绍如何利用在线培训系统提升员工技能&#…...

深度学习小工具:Linux 环境下的用户命令和脚本顺序执行器

前言 深度学习跑代码的时候&#xff0c;需要跑很多个对比实验&#xff0c;要么开多个窗口并行执行代码&#xff0c;要么就写在一个 .sh 文件里面顺序执行&#xff0c;前面一种并行执行多个任务出结果很慢&#xff0c;而后一种如果想添加任务或者删除某个任务就得全部停止&…...

c# WPF 应用程序在屏幕上居中显示

xaml<Window ... WindowStartupLocation"CenterScreen">...

JVM之class文件结构剖析

文章目录 0.前言1. 引言1.1 Java编译原理基础1.2 Class文件在Java编译过程中的角色 2. Class文件的整体结构2.1 Class 文件组成 3. Class文件的详细解析3.1 魔数与版本号的作用和意义3.2 常量池的结构和作用3.3 访问标志的含义和可能的值3.4 类索引、父类索引和接口索引集合的作…...

TDengine 签约中石化,支撑八大油田 PCS 系统

近日&#xff0c;TDengine 成功签约中国石化 PCS 一级部署时序数据库项目。未来&#xff0c;TDengine 将作为中国石化 PCS 系统的时序数据库&#xff0c;为石化总部、胜利油田、西北油田、中原油田、河南油田、华北油田、江苏油田、华东油田、江汉油田等油田 PCS 系统提供高效、…...

win11 定时计划任务

控制面板 任务计划 添加任务计划 &#xff0c;选按步骤添加。...

C++入门之引用与内联函数

一、引用 1、初步理解 引用在语法上的理解就是起别名&#xff0c;用法就是在类型后面加&&#xff0c;例子&#xff1a;int a 1; int& b a; 上例所示&#xff0c;执行后&#xff0c;b就是a的别名&#xff0c;它们代表同一块空间&#xff0c;a的改变会影响b&#xff0…...

浅谈智能照明控制系统应用在城市轨道交通

叶根胜 江苏安科瑞电器制造有限公司 江苏江阴 214405 摘要&#xff1a;在传统的城市轨道交通设计方面&#xff0c;照明设计方案具有一定的弊端。随着计算机技术的发展&#xff0c;智能化技术渐渐步入人们的生活并成为主流&#xff0c;故在城市轨道交通中应用新型的照明控制设…...

macos 中ios系统升级,但是macos还是老系统,在手机上无法安装ios软件

https://github.com/filsv/iOSDeviceSupport 构建项目出现 解决的方法&#xff1a; 就可以了&#xff0c;...

Pytest+Allure生成可添加附件的测试报告

#测试套件层级 allure.feature("测试PecExplorer") #重试次数&#xff0c;粒度为用例&#xff0c;建议用例设计可重复性高 pytest.mark.flaky(reruns3) class TestPecExplorer:#功能模块层级allure.story("登录界面")#测试用例层级allure.title("Test…...

Spacedrive:开源跨平台文件管理 | 开源日报 No.57

denoland/deno Stars: 91.2k License: MIT Deno 是一个简单、现代和安全的 JavaScript 和 TypeScript 运行时&#xff0c;使用 V8 引擎并用 Rust 构建。其主要功能包括&#xff1a; 默认情况下具有高度安全性&#xff0c;除非显式启用&#xff0c;否则无法访问文件、网络或环…...

c# 同步异步锁

在 C# 中&#xff0c;synchronization&#xff08;同步&#xff09;和asynchronization&#xff08;异步&#xff09;锁都是用来保护共享资源的。在单线程环境中&#xff0c;这些锁不是必要的&#xff0c;但在多线程环境中&#xff0c;由于多个线程可以访问和修改同一资源&…...

【Spring AOP】统⼀数据返回格式

为什么需要统一数据返回格式&#xff1f; ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。降低前端程序员和后端程序员的沟通成本&#xff0c;按照某个格式实现就⾏了&#xff0c;因为所有接⼝都是这样返回的。有利于项⽬统⼀数据的维护和修改。有利于后端技术部⻔的…...

python+django高校体育乒乓球场地预约管理系统_s2409

本系统提供给管理员对首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;乒乓球场管理,场地类型管理,场地预约管理,暂离申请管理,离开申请管理,管理员管理,留言反馈,系统管理等诸多功能进行管理。本系统对于用户输入的任何信息都进行了一定的验证&#xff0c;为管理员操…...

Python Selenium设计模式-POM

前言本文就python selenium自动化测试实践中所需要的POM设计模式进行分享&#xff0c;以便大家在实践中对POM的特点、应用场景和核心思想有一定的理解和掌握。 为什么要用POM 基于python selenium2开始UI级自动化测试并不是多么艰巨的任务。**只需要定位到元素&#xff0c;执…...

【计算机毕设选题推荐】网络在线考试系统SpringBoot+SSM+Vue

前言&#xff1a;我是IT源码社&#xff0c;从事计算机开发行业数年&#xff0c;专注Java领域&#xff0c;专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 项目名 网络在线考试系统 技术栈 SpringBootSSMVueMySQLMaven 文章目录 一、网络在线考试系统-环境…...

AUTOSAR汽车电子嵌入式编程精讲300篇-基于FPGA的LIN总线控制器设计与验证(续)

目录 3.2.3波特率发生模块 3.2.4数据采样模块 3.2.5校验和产生模块 3.2.6奇偶校验模块 3.2.7接收模块<...

Qt ModelView显示数据库数据

利用qt的model view来显示数据表userudps里的数据 用了一个label 两个combox和一个tableview&#xff0c;实现如下效果&#xff1a; 我这里用到是mysql数据库&#xff0c;一般配置mysql数据库就两种有驱动或者没驱动&#xff0c;有的话把mysql的bin目录的libmysql.dll复制到q…...

Vue-3.1缓存组件keep-alive

问题&#xff1a;从首页卡片点到详情页&#xff0c;又点返回&#xff0c;数据重新加载了->希望回到原来的位置 原因&#xff1a;路由跳转后&#xff0c;组件被销毁了&#xff0c;返回回来组件又被重建了&#xff0c;所以数据重新被加载了 解决&#xff1a;利用keep-alive将…...

14.8 Socket 一收一发通信

通常情况下我们在编写套接字通信程序时都会实现一收一发的通信模式&#xff0c;当客户端发送数据到服务端后&#xff0c;我们希望服务端处理请求后同样返回给我们一个状态值&#xff0c;并以此判断我们的请求是否被执行成功了&#xff0c;另外增加收发同步有助于避免数据包粘包…...

7天狂揽 1.3w star 的 MetaGPT,他们的目标让软件公司为之一惊

在 AI 产品爆炸的今天&#xff0c;拥有各种本领的 AI 产品层出不穷&#xff0c;但 MetaGPT 的出现仍然显的格外耀眼&#xff0c;其可以实现只输入单一 prompt&#xff0c;就可以输出需求分析、需求文档、技术架构、最终代码等等产物&#xff0c;这相当于一个开发团队的输出成果…...

工控网络协议模糊测试:用peach对modbus协议进行模糊测试

0x00 背景 本人第一次在FB发帖&#xff0c;进入工控安全行业时间不算很长&#xff0c;可能对模糊测试见解出现偏差&#xff0c;请见谅。 在接触工控安全这一段时间内&#xff0c;对于挖掘工控设备的漏洞&#xff0c;必须对工控各种协议有一定的了解&#xff0c;然后对工控协议…...

python+opencv+机器学习车牌识别 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于机器学习的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;3分 该项目较为新颖&#xff0c;适…...

魔域服务端数据库说明

Magic.DB MagID: 魔法ID Mag:Magic MagName: 魔法名称 EffectType: 效果类型 Effect: 效果 Spell: 魔力&#xff08;魔法值&#xff09; Power: 能力&#xff0c;力量 MaxPower: 最大能力 DefSpell: 变化后的魔力Def&#xff1a;deformation DefPower: 变化后能力 DefMaxPower:…...

笔记本无线网卡MAC一直改动

今天在网管处把我无线网卡的MAC地址添加后&#xff0c;回来链接无线网却一直显示网络链接失败&#xff0c;以为是自己的驱动问题&#xff0c;去官网下载了最新的驱动结果依然无法链接。之前在家或者公共场合链接WiFi从来没有出现过类似情况。 百思不得其解之际发现自己的无线网…...

【Tomcat】Apache发布两个新版本Tomcat修复多个Bug

Apache 官网发布了两个最新的 Tomcat 版本包&#xff0c;分别是&#xff1a;8.5.94、9.0.81 这两个最新版本修复了多个漏洞&#xff0c;统计信息如下表所示。有关漏洞的详细信息&#xff0c;请查阅官方相关文档&#xff08;见&#xff1a;参考&#xff09;。 严重等级漏洞说明…...

Empowering Low-Light Image Enhancer through Customized Learnable Priors 论文阅读笔记

中科大、西安交大、南开大学发表在ICCV2023的论文&#xff0c;作者里有李重仪老师和中科大的Jie Huang&#xff08;ECCV2022的FEC CVPR2022的ENC和CVPR2023的ERL的一作&#xff09;喔&#xff0c;看来可能是和Jie Huang同一个课题组的&#xff0c;而且同样代码是开源的&#xf…...

LeetCode 2652. 倍数求和【数学,容斥原理】简单

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

ansible-playbook剧本

一&#xff0c;playbook组成&#xff1a; &#xff08;1&#xff09;Tasks&#xff1a;任务&#xff0c;即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 &#xff08;2&#xff09;Variables&#xff1a;变量 &#xff08;3&#xff09;Templates&…...

竞赛选题 深度学习LSTM新冠数据预测

文章目录 0 前言1 课题简介2 预测算法2.1 Logistic回归模型2.2 基于动力学SEIR模型改进的SEITR模型2.3 LSTM神经网络模型 3 预测效果3.1 Logistic回归模型3.2 SEITR模型3.3 LSTM神经网络模型 4 结论5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 …...

机械设计师应该在工作中培养哪些良好习惯?

图纸规范 1、一定要按照制图标准设计图纸&#xff01;图纸上任何一条直线&#xff08;无论是点划线、粗实线、细实线等等&#xff09;、数值、公差、图标等&#xff0c;都必须有理有据&#xff0c;不能想当然。图纸是产品生产的基础&#xff0c;无论是生产、加工、装配&#x…...

小程序新增功能页面

需求背景: 小程序主页面有个报名板块,我打算替换主页面报名板块菜单,迁移到我的页面里面, 替换成资讯栏目,我喜欢分享最新技术,开源课题,IT资讯,本想做成论坛的效果,由于时间问题,先替换添加板块 替换后效果: 模块功能: 添加、修改、删除、查看 文件目录:// 添…...

LeetCode每日一题——2652. Sum Multiples

文章目录 一、题目二、题解 一、题目 Given a positive integer n, find the sum of all integers in the range [1, n] inclusive that are divisible by 3, 5, or 7. Return an integer denoting the sum of all numbers in the given range satisfying the constraint. E…...

Python问答题(更新中)

1. 列表&#xff08;list&#xff09;和元组&#xff08;tuple&#xff09;有什么区别&#xff1f; 列表是可变的&#xff0c;创建后可以对其进行修改&#xff1b;元组是不可变的&#xff0c;元组一旦创建&#xff0c;就不能对其进行更改。列表表示的是顺序。它们是有序序列&a…...

服务器中了locked勒索病毒怎么办,勒索病毒解密,数据恢复

最近一段时间内&#xff0c;相信很多使用金蝶或用友的办公软件的企业&#xff0c;有很多都经历了locked勒索病毒的攻击&#xff0c;导致企业服务器被加密无法正常使用&#xff0c;严重影响了企业的正常工作。通过云天数据恢复中心的解密恢复发现&#xff0c;在今年locked勒索病…...

游游的字母串 (环形数组两点之间的位置)

题目链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 yab 输出 3 思路&#xff1a; 暴力枚举&#xff0c;全部变成对应的26个字母字符需要的操作步数&#xff0c;取最少的一个操作步数&#xff0c; 这里的操作步数&#xff0…...

Flink的ResourceManager详解(一)

ResourceManager 总结 一、概述 1、ResourceManager 管理 Flink 集群中的计算资源&#xff0c;计算资源主要来自 TaskManager 组件。 2、如果集群采用 Native【本地模式】部署&#xff0c;则 ResourceManager 会动态地向集群资源管理器申请 Container 并启动TaskManager&…...

Tornado 可以使用 nginx 提供负载均衡

Tornado和nginx都是网络服务器的重要组成部分&#xff0c;但它们在职能和使用场景上存在显著的差异。 Tornado可以独立运行&#xff0c;而不需要依赖nginx等其他Web服务器。这是因为Tornado本身就是一个完整的Web服务器&#xff0c;可以独立处理HTTP请求并返回响应数据。 ngi…...

Golang 面向对象编程 多态

基本介绍 变量(实例)具有多种形态。面向对象的第三大特征&#xff0c;在Go语言&#xff0c;多态特征是通过接口实现的&#xff08;接口能够体现多态的特征&#xff09;。可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。 在前面的Usb接口案例&#xff0c;u…...

WLAN 无线案例(华为AC控制器配置模板)

实验说明&#xff1a; 无线用户VLAN 30 192.168.30.0/24 AP和AC用VLAN 20 192.168.20.0/24 有线网段 VLAN 10 192.168.10.0/24 步骤一&#xff1a;全网互通 sw1&#xff1a; sysname sw1 # vlan batch 10 20 30 # dhcp enable # ip pool 20 gateway-list 192.168.20.1…...