Linux C 进程间通信

news2024/9/21 10:53:00

进程间通信

  • 概述
  • 进程间通信方式
    • 管道
      • 概述
      • 管道函数
        • 无名管道 pipe
        • 有名管道 makefifo
        • 删除有名管道 rmove
      • 有名管道实现 双人无序聊天 例子
    • 信号
      • 信号概述
      • 信号处理过程
      • 信号函数
        • 传送信号给指定的进程 kill
        • 注册信号 signal
        • 查询或设置信号处理方式 sigaction
        • 设置信号传送闹钟 alarm
      • 有名管道+信号实现 双人无序聊天 例子
    • 共享内存
      • 概述
      • 特性
      • 共享内存命令
      • 共享内存函数
        • 创建\打开共享内存 shmget
        • 映射共享内存 shmat
        • 解除映射 shmdt
        • 删除共享内存
    • 消息队列
      • 概述
      • 消息队列函数
        • 创建消息队列 msgget
        • 消息队列发送消息 msgsnd
        • 消息队列接收消息 msgrcv
        • 删除消息队列 msgctl
    • 信号量集
      • 概述
      • 函数
        • 获取\创建信号量 semget
        • 控制信号量 semctl
        • 改变信号量的值 semop
  • 基于进程间通信+多进程编写的银行模拟系统案例

概述

  为什么进程间需要通信?为了传输数据、共享资源、通知事件、控制进程等。
  那么进程间通信的原理是什么呢?进程在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信机制。
在这里插入图片描述

进程间通信方式

  进程间通信主要有七种方式,分别是管道(有名、无名)、信号、共享内存、消息队列、信号量集以及套接字Socket(套接字后面单独介绍)。

管道

概述

  无名管道只能用于父子进程或兄弟进程之间的通信,而有名管道可用于任意两进程之间通信。

管道函数

无名管道 pipe

  无名管道单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存(RAM)中。
  数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

头文件:
  #include<unistd.h>
函数原型:int pipe(int filedes[2]);
参数介绍:
  fd:一个大小为2的一个数组类型的指针。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。
返回值:若成功则返回零,否则返回-1,错误原因存于 errno 中。
在这里插入图片描述
只有fork函数才能创建的父子进程间才能使用无名管道。

有名管道 makefifo

  命名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。命名管道是建立在实际的磁盘介质或文件系统上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。为了实现命名管道,引入了一种新的文件类型——FIFO 文件(遵循先进先出的原则)。实现一个命名管道实际上就是实现一个 FIFO 文件。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。在文件系统中有文件名,有文件节点。
头文件:
  #include<sys/types.h>
  #include<sys/stat.h>
函数原型:int mkfifo(const char * pathname,mode_t mode);
参数介绍:
  pathname:管道创建 路径+名字
  mode:文件权限,与umask有关
返回值:若成功则返回 0,否则返回-1,错误原因存于 errno 中。
在这里插入图片描述
这样任意两个进程可以通过文件IO操作在其中进行数据传输。

删除有名管道 rmove

头文件:
  #include<stdio.h>
函数原型:int remove(const char * pathname);
参数介绍:
  pathname:管道 路径+名字
返回值:若成功则返回 0,否则返回-1,错误原因存于 errno 中。

有名管道实现 双人无序聊天 例子

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc,char *argv[])
{
	//创建管道
	int val1 = mkfifo(argv[1],0666);
	int val2 = mkfifo(argv[2],0666);
	//打开管道
	int fd1 = open(argv[1],O_RDWR);
	int fd2 = open(argv[2],O_RDWR);
	//创建进程
	pid_t pid = fork();
	if( pid > 0 )//父进程
	{
		while(1)
		{
			char wb[512] = {0};
			gets(wb);
			write(fd1,wb,strlen(wb));
		}
	}
	else if( pid == 0 ) //子进程
	{
		while(1)
		{
			char rb[512] = {0};
			read(fd2,rb,sizeof(rb));
			printf("其他:%s\n",rb);
		}
	}
	close(fd1);
	close(fd2);
	return 0;
	//同时在两个终端中运行,形成双管道,四进程
	//父进程负责写入数据,子进程负责读出数据
	//因为read和write都是阻塞的,故可以一直等待到数据变化
}

信号

信号概述

  在Linux中使用 kill -l 命令可以查看到x 系统中有下 62 个信号,每一个信号都有自己独特的含义。前 31 个信号继承 unix 的非实时信号,后 31 个是 linux 自己扩展的实时信号,没有固定的含义(或者说可以由用户自由使用),所有的实时信号的默认动作都是终止进程。每一个信号用一个整型常量宏(信号编号)表示,以“SIG”开头,在系统头文件<signal.h>中定义。
在这里插入图片描述

信号处理过程

1 ) 信号的发生 ------ 内核进程能够发送信号(产生中断)。
2 ) 信号的接收 ------ 用户进程接收信号(保证进程不结束)。
3 ) 信号的处理 ------ 中断服务函数(信号服务函数)。

信号函数

传送信号给指定的进程 kill

头文件:
  #include<sys/types.h>
  #include<signal.h>
函数原型:int kill(pid_t pid,int sig);
参数介绍:
  pid:目标进程pid
  sig:要发送的信号(数字)
返回值:执行成功则返回 0,如果有错误则返回-1。

	kill(atoi(argv[1]),atoi(argv[2]));
注册信号 signal

头文件:
  #include<signal.h>
函数原型:void (signal(int signum,void( handler)(int)))(int);
即  typedef void (*sighandler_t)(int); //函数指针类型
   sighandler_t signal(int signum, sighandler_t handler);
参数介绍:
  下面的例子会然你看懂的
返回值:执行成功则返回 0,如果有错误则返回-1。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
//信号服务函数
void signal_function(int num)
{
	printf("2 号信号:%d\n",num);
}
int main(int argc,char *argv[])
{
	//注册信号
	sighandler_t val = signal(2,signal_function);
	while(1)return 0;
}

ctrl+c 信号是2号信号,所以当按下 ctrl+c 时服务函数 signal_function() 就会输出。

在这里插入图片描述

查询或设置信号处理方式 sigaction

头文件:
  #include<signal.h>
函数原型:int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
参数介绍:
  signum:要捕获的信号类型
  act:指定新的信号处理方式
  oldact:输出先前信号的处理方式
返回值:执行成功则返回 0,如果有错误则返回-1。
参数结构体 sigaction 定义如下:
struct sigaction
{
  void (*sa_handler) (int); //代表新的信号处理函数
  sigset_t sa_mask; //设置在处理该信号时暂时将 sa_mask 指定的信号搁置。
  int sa_flags; //用来设置信号处理的其他相关操作
  void (*sa_restorer) (void);// 此参数没有使用
}

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
void signal_function(int num)
{
	printf("2 号信号:%d\n",num);
}
int main(int argc,char *argv[])
{
	//注册信号
	struct sigaction act;
	act.sa_handler =signal_function;//信号服务函数
	sigemptyset(&act.sa_mask); //初始化信号集
	sigaddset(&act.sa_mask,2); //添加搁置信号
	sigaddset(&act.sa_mask,3); //添加搁置信号
	act.sa_flags =0;
	sigaction(2,&act,NULL);
	while(1);
	return 0;
	//运行结果图和注册信号代码运行结果图一样
	//当按下 ctrl+c 时服务函数signal_function()就会输出。
}
设置信号传送闹钟 alarm

头文件:
  #include<unistd.h>
函数原型:unsigned int alarm(unsigned int seconds);
参数介绍:
  seconds:经过指定的秒数后发送信号给当前进程。为 0,则之前设置的闹钟会被取消,并将剩下的时间返回。
返回值:返回之前闹钟的剩余秒数,如果之前未设闹钟则返回 0。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
typedef void (*sighandler_t)(int);
extern int errno;
void signal_function(int num)
{
	printf("14 号信号:%d\n",num);
}
int main(int argc,char *argv[])
{
	//注册信号
	struct sigaction act;
	act.sa_handler =signal_function;//信号服务函数
	sigemptyset(&act.sa_mask); //初始化信号集
	sigaddset(&act.sa_mask,2); //添加搁置信号
	sigaddset(&act.sa_mask,3); //添加搁置信号
	act.sa_flags =0;
	sigaction(14,&act,NULL);
	
	printf("%d\n",alarm(10));
	sleep(2);
	printf("%d\n",alarm(5));
	
	while(1);
	return 0;
}

在设置完10秒之后,经过两秒的睡眠还剩8秒,这时候被重新设置为五秒(上次计时还剩8秒),五秒后14号信号被发出并接收显示。
在这里插入图片描述

有名管道+信号实现 双人无序聊天 例子

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
char path[10];
//信号服务函数
void signal_fun(int num)
{
	int fd2 = open(path,O_RDWR);		//打开读管道
	char rb[512] = {0};
	read(fd2,rb,sizeof(rb));	
	printf("%d说:%s\n",num,rb);
	close(fd2);							//关闭读管道	
}
//关于argv:
// 1 是读通道  2 是写通道  3 是自己的信号  4 是发的信号
int main(int argc,char *argv[])
{
	//init
	strcpy(path,argv[2]);					//保证信号服务函数能打开对应的管道
	pid_t pid = getpid();					//或取自己的pid
	//创建管道
	int val1 = mkfifo(argv[1],0666);
	int val2 = mkfifo(argv[2],0666);
	//打开管道
	int fd1 = open(argv[1],O_RDWR); 		//写管道
	write(fd1,&pid,sizeof(pid_t));		//写入当前进程pid
	printf("当前pid:%d\n",pid);
	int fd2 = open(argv[2],O_RDWR); 		//读管道
	read(fd2,&pid,sizeof(pid_t));		//读出要通信的pid
	close(fd2);
	printf("通信pid:%d\n",pid);
	//注册信号
	sighandler_t val = signal(atoi(argv[3]),signal_fun);
	//等待写入
	while(1)
	{
		char wb[512] = {0};
		gets(wb);
		write(fd1,wb,strlen(wb));
		kill(pid,atoi(argv[4]));
	}
	close(fd1);
	return 0;
	//同时在两个终端中运行,形成双管道,双进程
	//主函数写入管道数据并发送信号到另一个进程
	//信号服务函数在接收到信号之后读取管道内容
}

共享内存

概述

  指同一块物理内存被映射到进程 A、B 进程地址空间中。进程 A 可以即时看到进程 B 对共享内存中数据的更新。

特性

  1. 数据传输效率快,适用于对数据的速率、数量要求较高的场合(如果要求不高,一般使用消息队列)。
  2. 共享内存具有内存的通用特性,对共享内存执行写操作时以覆盖的方式写入,对共享内存读取数据后,内存中的数据保留,不会删除。
  3. 内核中的内存是不具有共享机制的,在使用共享内存前需要先创建一块共享内存(物理内存)。
  4. 共享内存并未提供同步机制,在一个进程结束对共享内存的写操作之前,不可以使用另外一个进程开始对它进行读取。

共享内存命令

查看内核中 IPC 对象:
  ipcs -m 共享内存
     -q 消息队列
     -s 信号灯
删除内核中 ipc 对象:
  ipcrm -m id号

共享内存函数

创建\打开共享内存 shmget

头文件:
  #include <sys/ipc.h>
  #include <sys/shm.h>
函数原型:int shmget(key_t key, size_t size, int shmflg);
参数介绍:
  key:共享内存标识符
  size:创建共享内存空间大小
  shmflg:权限标志
返回值:成功返回共享内存的标识符。失败,则返回 -1,并设置 errno 来指示错误类型。

	int shmid = shmget(0x6666,512,IPC_CREAT|0644);
映射共享内存 shmat

头文件:
  #include <sys/types.h>
  #include <sys/shm.h>
函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
参数介绍:
  shmid:共享内存的标识符。
  shmaddr:指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
  shmflg:是一组标志位,通常为0。
返回值:调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.

	char * pos = (char *)shmat(shmid,NULL,0);
解除映射 shmdt

头文件:
  #include <sys/types.h>
  #include <sys/shm.h>
函数原型:int shmdt(const void *shmaddr);
参数介绍:
  shmaddr:指定共享内存连接到当前进程中的地址位置。
返回值:成功返回 0,失败返回-1。

	shmdt(shmid);
删除共享内存

头文件:
  #include <sys/ipc.h>
  #include <sys/shm.h>
函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数介绍:
  shmid:共享内存标识。
  cmd:采取的操作,具体如下:
    IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
    IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值。
    IPC_RMID:删除共享内存段。
  buf:指向共享内存模式和访问权限的结构。
返回值:成功返回 0,失败返回-1。
如果需要删除共享内存,必须保证共享内存的所有连接全部断开(取消映射)后才能被真正删除。

	int val = shmctl(shmid,IPC_RMID,NULL);

消息队列

概述

  消息通信方式以消息缓冲区为中间介质,通信双方的发送和接收操作均以消息为单位。在存储器中,消息缓冲区被组织成队列,通常称之为消息队列。
  消息队列是消息(消息内容及消息类型)的链表,存放在内核中并由消息队列标识符表示。消息队列与管道不同的是,消息队列是基于消息的,而管道是基于字节流的,且消息队列的读取不一定是先入先出,但是对于同一消息类型为先进先出。
  消息队列提供了一个从一个进程向另一个进程发送数据块(结构体)的方法,每个数据块都可以被认为是有一个类型,接受者接受的数据块可以有不同的类型,接收进程根据不同类型数据进行选择接收。

消息队列函数

创建消息队列 msgget

头文件:
   #include <sys/types.h>
   #include <sys/msg.h>
   #include <sys/ipc.h>
函数原型:int msgget(key_t key, int msgflg);
参数介绍:
  key:消息队列的标识符
  msgflg:权限标志,具体如下
    IPC_CREAT //如果key不存在,则创建(类似open函数的O_CREAT)
    IPC_EXCL //如果key存在,则返回失败(类似open函数的O_EXCL)
    IPC_NOWAIT //如果需要等待,则直接返回错误
返回值:成功执行时,返回消息队列标识符。失败返回-1。

	int msgid = msgget(0x6666, IPC_CREAT|0666);
消息队列发送消息 msgsnd

头文件:
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/msg.h>
函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数介绍:
  msqid:消息队列的标识符。
  msgp:指向要发送的消息所在的内存。
  msgsz:消息的长度。
  msgflg:是控制函数行为的标志,通常为0。
返回值:错误时返回-1,可以打印错误信息。正确返回 0。

struct msgbuf 
{
	long mtype; /* message type, must be > 0 */
	char mtext[512]; /* message data */
	int id;
};

	struct msgbuf info;
	int val = msgsnd(msgid,&info,sizeof(struct msgbuf)-sizeof(long),0)
消息队列接收消息 msgrcv

头文件:
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/msg.h>
函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数介绍:
  msqid:消息队列的标识符。
  msgp:指向要发送的消息所在的内存。
  msgsz:消息的长度。
  msgtyp:如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。
  msgflg:是控制函数行为的标志,通常为0。
返回值:

	struct msgbuf recvinfo;
	ssize_t len = msgrcv(msgid,&recvinfo,sizeof(struct msgbuf)-sizeof(long), 1,0);
删除消息队列 msgctl

头文件:
  #include <sys/types.h>
   #include <sys/ipc.h>
  #include <sys/msg.h>
函数原型:int msgctl ( int msgqid, int cmd, struct msgid_ds *buf );
参数介绍:
  msqid:消息队列的标识符。
  cmd:将要采取的动作,它可以取3个值:
    IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
    IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值。
    IPC_RMID:删除消息队列。
  buf :指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。
返回值:成功时返回0,失败时返回-1。

	msgctl (msgid, IPC_RMID, NULL);

信号量集

概述

  信号量集是由多个信号量组成的一个数组,作为一个整体,信号量集中的所有信号量使用同一个等待队列。Linux 的信号量集为进程请求多个资源创造了条件。Linux 规定,当进程的一个操作需要多个共享资源时,如果只成功获得了其中的部分资源,那么这个请求即告失败,进程必须立即释放所有已获得资源,以防止形成死锁。

函数

获取\创建信号量 semget

头文件:
  #include <sys/ipc.h>
  #include <sys/sem.h>
  #include <sys/types.h>
函数原型:int semget(key_t key, int nsems, int semflg);
参数介绍:
  key:信号量的键值
  nsems:创建信号量的个数,大多数情况为1。
  semflg:是一组标志,如果希望信号量不存在时创建一个新的信号量,可以和值 IPC_CREAT 做按位或操作。如果没有设置 IPC_CREAT标志并且信号量不存在,就会返错误(errno 的值为 2,No such file or directory)。
返回值:返回信号量集的标识;失败返回-1,错误原因存于 error 中。

	//获取键值为 0x5000 的信号量
	//如果该信号量不存在,就创建它
	int semid = semget(0x5000,1,0640|IPC_CREAT);
控制信号量 semctl

头文件:
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/sem.h>
函数原型:int semctl(int semid, int sem_num, int command, …);
参数介绍:
  semid:信号量标识
  sem_num:是信号量集数组下标
  command:对信号量操作的命令,具体如下:
    IPC_RMID:销毁信号量,不需要第四个参数;
    SETVAL:用来把信号量初始化为一个已知的值。
返回值:失败返回-1;如果成功,返回值比较复杂,想了解的自行搜索。
用于信号操作的共同体:
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};

	//销毁信号量。
	semctl(semid,0,IPC_RMID);
	//初始化信号量的值为 1,信号量可用。
	union semun sem_union;
	sem_union.val = 1;
	semctl(semid,0,SETVAL,sem_union);
改变信号量的值 semop

头文件:
  #include <sys/ipc.h>
  #include <sys/types.h>
函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
参数介绍:
  sem_id:信号量标识。
  sops:操作信号量的个数。
  nsops:结构体,具体内容在下面给出。
返回值:成功返回0,失败返回-1,错误原因存于 error 中。
nsops结构体:
struct sembuf
{
short sem_num; // 信号量序号,单个信号量设置为 0。
short sem_op; //信号量操作,-1 等待操作;1 发送操作。
short sem_flg; //把此标志设置为 SEM_UNDO,操作系统将跟踪这个信号量。
};

	//等待信号量的值变为 1,如果等待成功,
	//立即把信号量的值置为 0
	struct sembuf sem_b;
 	sem_b.sem_num = 0;
 	sem_b.sem_op = -1;
 	sem_b.sem_flg = SEM_UNDO;
 	semop(sem_id, &sem_b, 1);
 	//把信号量的值置为 1。
	struct sembuf sem_b;
 	sem_b.sem_num = 0;
 	sem_b.sem_op = 1;
 	sem_b.sem_flg = SEM_UNDO;
 	semop(sem_id, &sem_b, 1);

基于进程间通信+多进程编写的银行模拟系统案例

点我~~~

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

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

相关文章

天软特色因子看板 (2023.11 第10期)

该因子看板跟踪天软特色因子A05006(近一月单笔流入流出金额之比(%)该因子为近一个月单笔流入流出金额之比(%)均值因子&#xff0c;用以刻画 市场日内分时成交中流入、流出成交金额的差异性特点&#xff0c;发掘市场主力资金的作用机制。 今日为该因子跟踪第10期&#xff0c;跟踪…

《红蓝攻防对抗实战》十三.内网穿透之利用HTTP协议进行隧道穿透

内网穿透之利用HTTP协议进行隧道穿透 一.前言二.前文推荐三.利用HTTP协议进行隧道穿透1. Reduh进行端口转发2. ReGeorg进行隧道穿透3. Neo-reGeorg加密隧道穿透4. Tunna进行隧道穿透5 .Abptts加密隧道穿透6. Pivotnacci加密隧道穿透 四.本篇总结 一.前言 本文介绍了利用HTTP协…

python 实验7

姓名&#xff1a;轨迹 学号&#xff1a;6666 专业年级&#xff1a;2021级软件工程 班级&#xff1a; 66 实验的准备阶段 (指导教师填写) 课程名称 Python开发与应用 实验名称 文件异常应用 实验目的 &#xff08;1&#xff09;掌握基本文件读写的方式&#xff1b; …

基于消息队列+多进程编写的银行模拟系统

银行模拟系统 概述客户端 client.c服务端 serve.c开户 enroll.c存款 save.c转账 transfer.c取款 take.cmakefile文件 概述 该案例大体过程为&#xff0c;服务器先启动&#xff0c;初始化消息队列和信号&#xff0c;用多线程技术启动开户、存钱、转账、取钱模块&#xff0c;并且…

Python基础-解释器安装

一、下载 网址Welcome to Python.orgPython更新到13了&#xff0c;我们安装上一个12版本。 这里我保存到网盘里了&#xff0c;不想从官网下的&#xff0c;可以直接从网盘里下载。 链接&#xff1a;百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间…

IDEA从Gitee拉取代码,推送代码教程

打开IDEA&#xff0c;选择Get from Version Control 输入Gitee 仓库项目的URL地址 URL地址输入后点击Clone&#xff0c;即拉取成功 向Gitee提交推送代码 右键选中项目&#xff0c;选中Git 第一步先点击 Add 第二步 点击Commit填写提交信息&#xff0c;点击Commit就会出现下面…

Jenkins的一些其他操作

Jenkins的一些其他操作 1、代码仓库Gogs的搭建与配置 Gogs 是一款极易搭建的自助 Git 服务&#xff0c;它的目标在于打造一个最简单、快速和轻松的方式搭建 Git 服务。使用 Go 语言开发的它能够通过独立的二进制进行分发&#xff0c;支持了 Go 语言支持的所有平台&#xff0…

Vue修饰符(Vue事件修饰符、Vue按键修饰符)

目录 前言 Vue事件修饰符 列举较常用的事件修饰符 .stop .prevent .capture .once Vue按键修饰符 四个特殊键 获取某个键的按键修饰符 前言 本文介绍Vue修饰符&#xff0c;包括Vue事件修饰符以及按键修饰符 Vue事件修饰符 列举较常用的事件修饰符 .stop: …

【Linux基础IO篇】深入理解文件系统、动静态库

【Linux基础IO篇】深入理解文件系统、动静态库 目录 【Linux基础IO篇】深入理解文件系统、动静态库再次理解文件系统操作系统内存管理模块&#xff08;基础&#xff09;操作系统如何管理内存 Linux中task_struct源码结构 动态库和静态库动静态库介绍&#xff1a;生成静态库库搜…

IDEA安装配置SceneBuilder

1、下载 SceneBuilder 地址&#xff1a; Scene Builder - Gluon ​​​​​​​ Scene Builder | JavaFX中文官方网站 选择符合自己系统版本&#xff0c;JAVA版本的下载 2、安装SceneBuilder 执行下载的 SceneBuilder 安装程序&#xff0c;并按照安装向导的指示进行…

Pikachu漏洞练习平台之CSRF(跨站请求伪造)

本质&#xff1a;挟制用户在当前已登录的Web应用程序上执行非本意的操作&#xff08;由客户端发起&#xff09; 耐心看完皮卡丘靶场的这个例子你就明白什么是CSRF了 CSRF(get) 使用提示里给的用户和密码进行登录&#xff08;这里以lili为例&#xff09; 登录成功后显示用户…

(Matalb时序预测)GWO-BP灰狼算法优化BP神经网络的多维时序回归预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码展示&#xff1a; 四、完整代码数据说明手册下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于M…

SSH-远程连接服务器

一、理论知识 目前远程连接服务器的主要类型&#xff1a; 文字接口明文传输&#xff1a;Telnet、RSH 等为主&#xff0c;目前非常少用。文字接口加密&#xff1a;SSH 为主&#xff0c;已经取代上述的 Telnet、RSH 等明文传输方式。图形接口&#xff1a;XDMCP&#xff08;X Di…

Neo4j数据库介绍及简单使用

图数据库介绍 图数据库是一种专门设计用于存储和管理图形数据的数据库类型。在图数据库中&#xff0c;数据以图的形式表示&#xff0c;其中节点表示实体&#xff0c;边表示实体之间的关系。这种表示方式非常适合处理具有复杂关系的数据&#xff0c;如社交网络、推荐系统、网络…

安装部署PowerDNS--实现内网DNS解析(use)

使用PowerDNS实现内网DNS解析_powerdns-admin-CSDN博客 https://www.cnblogs.com/guangdelw/p/17348982.html 一、概念介绍 PowerDNS是一个域名解析服务&#xff0c;官网提供了三个组件&#xff1a;Authoritative、Recursor、dnsdist&#xff0c;分别用来作为权威服务器、域名递…

Leetcode——岛屿的最大面积

1. 题目链接&#xff1a;695. 岛屿的最大面积 2. 题目描述&#xff1a; 给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都…

ssh脚本找不到命令或者执行无效的解决办法

如图&#xff1a;今天在编写脚本时发现的这个问题&#xff0c; 在排除脚本语法错误、编码格式等情况下&#xff0c;仍然出现“bash 。。未找到命令”的字样 解决办法&#xff1a; 给每台虚拟机的环境变量source一下&#xff1a; 命令如下 source /etc/profile或者输入 vim ~…

【数据结构】直接选择排序(你知道最不常用的排序算法有哪些吗?)

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;数据结构 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有帮助…

【2023云栖】黄博远:阿里云人工智能平台PAI年度发布

本文根据2023云栖大会演讲实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a;黄博远 | 阿里云计算平台事业部资深产品专家、阿里云人工智能平台PAI产品负责人 演讲主题&#xff1a;阿里云人工智能平台PAI年度发布 AIGC是我们这个时代的新机遇 今年云栖大…

单相过压继电器DVR-G-100-1 0~500V AC/DC220V 导轨安装

系列型号 DVR-G-100-1X3数字式过压继电器&#xff1b; DVR-G-100-3三相过压继电器&#xff1b; DVR(H)-G-100-1单相过压继电器&#xff1b; DVR-Q-100-3三相欠压继电器&#xff1b; DVR(H)-Q-100-3三相欠压继电器 一、用途 主要应用于电机、变压器等主设备以及输配电系统的继…