当前位置: 首页 > 编程日记 > 正文

进程间通信学习小结(共享内存)

要使用共享内存,应该有如下步骤:
1.开辟一块共享内存 shmget()
2.允许本进程使用共某块共享内存 shmat()
3.写入/读出
4.禁止本进程使用这块共享内存 shmdt()
5.删除这块共享内存 shmctl()或者命令行下ipcrm

共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同
进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程
地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。
由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量
都可以。

一:概念

采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内
存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在
内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存
区,另一次从共享内存区到输出文件。
实际上,进程之间在共享内存时,并不总是读写少量数据后就
解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这
样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写
回文件的。因此,采用共享内存的通信方式效率是非常高的。
Linux的2.2.x内核支持多种共享内存方式,如mmap()系统调用,Posix共享内存,以及系统V共享内
存。linux发行版本如Redhat 8.0支持mmap()系统调用及系统V共享内存,但还没实现Posix共享内存,
本文将主要介绍系统V共享内存API的原理及应用。

系统V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),
任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域
用来映射存放共享数据的物理内存页面。

系统V是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信。也就是说,每个
享内存区域
对应特殊文件系统shm中的一个文件
(这是通过shmid_kernel结构联系起来的),后面还将阐述。

进程间需要共享的数据被放在一个叫做IPC共享内存区域的地方,所有需要访问该共享区域的进程都
要把该共享区域映射到本进程的地址空间中去。系统V共享内存通过shmget获得或创建一个IPC共享
内存区域,并返回相应的标识符。
内核在保证shmget获得或创建一个共享内存区,初始化该共享内
存区相应的shmid_kernel结构的同时,还将在特殊文件系统shm中,创建并打开一个同名文件,
在内存中建立起该文件的相应dentry及inode结构,新打开的文件不属于任何一个进程(任何进程都
可以访问该共享内存区)。
所有这一切都是系统调用shmget完成的。
注:每一个共享内存区都有一个控制结构struct shmid_kernel,shmid_kernel是共享内存区域中非常
重要的一个数据结构,它是存储管理和文件系统结合起来的桥梁,定义如下:
struct shmid_kernel
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
};
该结构中最重要的一个域应该是shm_file,它存储了将被映射文件的地址。每个共享内存区对象都对
应特殊文件系统shm中的一个文件,一般情况下,特殊文件系统shm中的文件是不能用read()、write
()等方法访问的,当采取共享内存的方式把其中的文件映射到进程地址空间后,可直接采用访问内存的方式对其访问。

正如消息队列和信号灯一样,内核通过数据结构struct ipc_ids shm_ids维护系统中的所有共享内存
区域。
上图中的shm_ids.entries变量指向一个ipc_id结构数组,而每个ipc_id结构数组中有个指向
kern_ipc_perm 结构的指针。到这里读者应该很熟悉了,对于系统V 共享内存区来说,
kern_ipc_perm的宿主是shmid_kernel结构,shmid_kernel是用来描述一个共享内存区域的,这样内
核就能够控制系统中所有的共享区域。
同时,在shmid_kernel结构的file类型指针shm_file指向文件
系统shm中相应的文件,这样,共享内存区域就与shm文件系统中的文件对应起来。
在创建了一个共享内存区域后,还要将它映射到进程地址空间,系统调用shmat()完成此项功能。由
于在调用shmget()时,已经创建了文件系统shm中的一个同名文件与共享内存区域相对应,因此,
调用shmat()的过程相当于映射文件系统shm中的同名文件过程。

二:系统V共享内存API

对于系统V共享内存,主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。
#include <sys/ipc.h>
#include <sys/shm.h>

shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。shmat()把
共享内存区域映射到调用进程的地址空间中去,这样,进程就可以方便地对共享区域进行访问操作。shmdt()调用用来解除进程对共享内存区域的映射。shmctl实现对共享内存区域的控制操作。

三:实例

两个进程通过系统V共享内存通信的范例。


#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct{
char name[4];
int age;
} people;//进程地址空间里开辟了一个内存区域用于与共享内存映射
main(int argc, char** argv)
{
int shm_id,i;
key_t key;
char temp;
people *p_map;
char* name = "/dev/shm/myshm2";
key = ftok(name,0);//以前的都是'a'
if(key==-1)
perror("ftok error");
shm_id=shmget(key,4096,IPC_CREAT);
if(shm_id==-1)
     {
perror("shmget error");
return;
     }

p_map=(people*)shmat(shm_id,NULL,0);//映射到进程地址空间内存里
temp='a';
for(i = 0;i<10;i++)
     {
temp+=1;
memcpy((*(p_map+i)).name,&temp,1);//对共享内存写操作(就是在进程的映射内存里写),

(*(p_map+i)).age=20+i;//(*(p_map+i)).name等同于(p_map+i)->name
     }
if(shmdt(p_map)==-1)//解除映射
perror(" detach error ");
}

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct{
char name[4];
int age;
} people;
main(int argc, char** argv)
{
int shm_id,i;
key_t key;
people *p_map;
char* name = "/dev/shm/myshm2";
key = ftok(name,0);
if(key == -1)
perror("ftok error");
shm_id = shmget(key,4096,IPC_CREAT);
if(shm_id == -1)
       {
perror("shmget error");
return;
       }
p_map = (people*)shmat(shm_id,NULL,0);
for(i = 0;i<10;i++)
{
printf( "name:%s\n",(*(p_map+i)).name );//对共享内存进行读操作(就是读进程的映射内存)
printf( "age %d\n",(*(p_map+i)).age );
}
if(shmdt(p_map) == -1)
perror(" detach error ");
}

testwrite.c创建一个系统V共享内存区,并在其中写入格式化数据;testread.c访问同一个系统V共享
内存区,读出其中的格式化数据。分别把两个程序编译为testwrite及testread,先后执行./testwrite
及./testread 则./testread输出结果如下:
name: b age 20; name: c age 21; name: d age 22; name: e age 23; name: f age 24;
name: g age 25; name: h age 26; name: I age 27; name: j age 28; name: k age 29;

四:总结

系统V共享内存是以文件的形式组织在特殊文件系统shm中的。通过shmget可以创建或获得共享内存的标识符。取得共享内存标识符后,要通过shmat将这个内存区映射到本进程的虚拟地址空间(本进程内通过开辟一个内存进行映射)。

1、 系统V共享内存中的数据,从来不写入到实际磁盘文件中去;而通过mmap()映射普通文件实现
的共享内存通信可以指定何时将数据写入磁盘文件中。注:前面讲到,系统V共享内存机制实际是通
过映射特殊文件系统shm中的文件实现的,文件系统shm的安装点在交换分区上,系统重新引导后,
所有的内容都丢失。
2、 系统V共享内存是随内核持续的,即使所有访问共享内存的进程都已经正常终止,共享内存区仍
然存在(除非显式删除共享内存),在内核重新引导之前,对该共享内存区域的任何改写操作都将
一直保留。
3、 通过调用mmap()映射普通文件进行进程间通信时,一定要注意考虑进程何时终止对通信的影
响。而通过系统V共享内存实现通信的进程则不然。注:这里没有给出shmctl的使用范例,原理与消
息队列大同小异。

共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种
进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制
实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现更安
全通信,往往还与信号灯等同步机制共同使用。

转:共享内存---shmget shmat shmdt

要使用共享内存,应该有如下步骤:
1.开辟一块共享内存 shmget()
2.允许本进程使用共某块共享内存 shmat()
3.写入/读出
4.禁止本进程使用这块共享内存 shmdt()
5.删除这块共享内存 shmctl()或者命令行下ipcrm


ftok():它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。

shmkey = ftok( "mcut" , 'a' ); // 计算标识符

操作共享内存,我们用到了下面的函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget( key_t shmkey , int shmsiz , int flag );
void *shmat( int shmid , char *shmaddr , int shmflag );
int shmdt( char *shmaddr );

shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:
key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。
int shmsiz 是这块内存的大小.
int flag 是这块内存的模式(mode)以及权限标识。
模式可取如下值: 新建:IPC_CREAT
使用已开辟的内存:IPC_ALLOC
如果标识符以存在,则返回错误值:IPC_EXCL
然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。
如: IPC_CREAT | IPC_EXCL | 0666
这个函数成功时返回共享内存的ID,失败时返回-1。

// shmid开辟共享内存

shmid = shmget( shmkey , sizeof(in_data) , IPC_CREAT | 0666 ) ;


shmat()是用来允许本进程访问一块共享内存的函数。
int shmid是那块共享内存的ID。
char *shmaddr是共享内存的起始地址
int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回-1。

char *head , *pos ,

head = pos = shmat( shmid , 0 , 0 );

// 允许本进程使用这块共享内存

shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。
参数char *shmaddr是那块共享内存的起始地址。
成功时返回0。失败时返回-1。

shmdt( head ); // 禁止本进程使用这块内存

此外,还有一个用来控制共享内存的shmctl()函数如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl( int shmid , int cmd , struct shmid_ds *buf );
int shmid是共享内存的ID。
int cmd是控制命令,可取值如下:
IPC_STAT 得到共享内存的状态
IPC_SET 改变共享内存的状态
IPC_RMID 删除共享内存
struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。
返回值: 成功:0
失败:-1

shmctl(shmid,IPC_RMID,NULL);

刚才我们的mpaste.c程序中还可以加入这样几句。

struct shmid_ds buf;
... ...
shmctl( shmid , IPC_STAT , &buf ); // 取得共享内存的状态
... ...
shmctl( shmid , IPC_RMID , &buf ); // 删除共享内存

注意:在使用共享内存,结束程序退出后。如果你没在程序中用shmctl()删除共享内存的话,一定要在命令行下用ipcrm命令删除这块共享内存。你要是不管的话,它就一直在那儿放着了。
简单解释一下ipcs命令和ipcrm命令。

取得ipc信息:
ipcs [-m|-q|-s]
-m 输出有关共享内存(shared memory)的信息
-q 输出有关信息队列(message queue)的信息
-s 输出有关“遮断器”(semaphore)的信息
ipcs -m

删除ipc
ipcrm -m|-q|-s shm_id
ipcrm -m 105

例如,我们在以0x12345678为KEY创建了一个共享内存,可以直接使用ipcrm -M 0x12345678来删除共享内存区域。

相关文章:

[ObjectiveC]NSDATA, NSDICTIONARY, NSSTRING互转

2019独角兽企业重金招聘Python工程师标准>>> NSDATA-->NSDICTIONARY NSDictionary *dict [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSDICTIONARY-->NSDATA NSData *data [NSJSONSerialization dat…

如流智会2021:技术结合场景 让企业知识懂员工

12月10日&#xff0c;“如流智会2021智能进化”在京举行&#xff0c;学界专家业界大咖云集荟聚&#xff0c;共商企业智能化转型之道。会上&#xff0c;百度集团副总裁、百度集团首席信息官&#xff08;CIO&#xff09;李莹表示&#xff1a;“智能经济时代&#xff0c;智能组织是…

WSFC 仲裁模型选择

今天我们再来详细讨论下关于WSFC的仲裁模型&#xff0c;主要仲裁模型的优缺点&#xff0c;应该如何去思考选择最佳合适方案WSFC引入仲裁&#xff0c;主要有两个目的跟踪群集当前运作票数是否符合仲裁模型协定&#xff0c;如果低于最少允许节点&#xff0c;则决定关闭群集&#…

关于进程间通信的学习心得

进程&#xff1a;进程是指独立地址空间的指令序列进程的五种状态&#xff1a;新建&#xff0c;就绪&#xff0c;运行&#xff0c;睡眠&#xff0c;僵死进程间通信&#xff1a;是不同进程之间进行一些"接触"&#xff0c;这种接触有简单&#xff0c;有复杂。机制不同&a…

Go modules基础精进,六大核心概念全解析(上)

Go 语言做开发时&#xff0c;路径是如何定义的&#xff1f;Go Mudules又为此带来了哪些改变&#xff1f;本文将会全面介绍Go Modules六大核心概念&#xff0c;包括了设计理念与兼容性原则等&#xff0c;掌握这些技术点对于管理和维护Go 模块有重要价值。 在Go Modules 的前世今…

PARAMETERS 指令

语法: PARAMETERS <p> [DEFAULT <f>] [LOWER CASE] [OBLIGATORY] [AS CHECKBOX] [RADIOBUTTON GROUP <rad>] 实例: PARAMETERS: NAME(8), AGE TYPE I, BIRTH TYPE D. OBLIGATORY:强制要求输入, 屏幕上会出現一个“√” , 使用者必须要输入才可。 AS C…

阿里发布AliGenie2.0系统,“百箱大战”用上视觉武器

天猫精灵X1的升级版X2没有预期出现&#xff0c;而人机交互系统AliGenie升级到最新的2.0版本&#xff0c;功能强大。 3月22日&#xff0c;阿里巴巴人工智能实验室总经理浅雪&#xff08;陈丽娟&#xff09;发布AliGenie2.0系统&#xff0c;它最大的改进是在1.0的基础上增加了视觉…

Centos5.6 VNC安装配置【无错版】

不严格按本步骤就会出现VNC桌面花屏&#xff0c;就是桌面分离为一层一层的。。。 ---------------------------------------- 先装X window http://blog.csdn.net/21aspnet/article/details/6997549 ---------------------------------------- Centos5.6 VNC安装配置 一、检查是…

关于IOS的屏幕适配(iPhone)——资源适配

IOS的屏幕适配几乎不需要大量的代码操作&#xff0c;更多的时间我们只是动动鼠标选择一下就搞定。可以苹果在这方面做的还是比较人性的&#xff0c;解放了开发者。 首先来说说Iphone这几种屏&#xff08;由于最近做的是iPhone APP还未涉及到iPad&#xff0c;将来涉及到iPad时会…

Go modules基础精进,六大核心概念全解析(下)

Go 语言做开发时&#xff0c;路径是如何定义的&#xff1f;Go Mudules又为此带来了哪些改变&#xff1f;本文将会全面介绍Go Modules六大核心概念&#xff0c;包括了设计理念与兼容性原则等&#xff0c;掌握这些技术点对于管理和维护Go 模块有重要价值。 在上篇中&#xff0c;我…

京东区块链白皮书解读, 做“链接器”,一次技术宣言

前天&#xff0c;京东对外发布了《京东区块链技术白皮书(2018)》。 昨天&#xff0c;京东金融发布了旨在帮助中小银行提升零售信贷效率的产品“北斗”。目前&#xff0c;“北斗”已经接入包括江苏银行、南京银行、包商银行在内的近30家银行。京东金融还与近30家商业银行共同发起…

xauth: (stdin):1: bad display name LSPPC-Lenny:1 in add command

启动vnc4server之后出现如下错误提示&#xff1a;LSPPC-Lenny:~# vnc4serverxauth: (stdin):1: bad display name "LSPPC-Lenny:1" in "add" command New ‘LSPPC-Lenny:1 (root)’ desktop is LSPPC-Lenny:1 Starting applications specified in /root/…

使用 Python 和 OpenCV 构建 SET 求解器

作者 | 小白来源 | 小白学视觉小伙伴们玩过 SET 吗&#xff1f;SET 是一种游戏&#xff0c;玩家在指定的时间竞相识别出十二张独特纸牌中的三张纸牌&#xff08;或 SET&#xff09;的模式。每张 SET 卡都有四个属性&#xff1a;形状、阴影/填充、颜色和计数。下面是一个带有一些…

Delphi XE5 常用功具与下载

1.Delphi XE5 正式版http://altd.embarcadero.com/download/radstudio/xe5/delphicbuilder_xe5_win.isohttp://altd.embarcadero.com/download/radstudio/xe5/delphicbuilder_xe5_upd1_win.iso2. cnpack 助手工具http://www.cnpack.org/download/unstable/CnWizards_1.0.1.665_…

maven学习(4)-Maven 构建Web 项目

紧接着上一节(3)&#xff0c;现在maven新建web项目&#xff0c;user-web。模拟一个用户登录的需求&#xff1a; 工程结构&#xff1a; pom.xml: <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…

如何查看linux版本

1. 查看内核版本命令&#xff1a; 1) [rootq1test01 ~]# cat /proc/version Linux version 2.6.9-22.ELsmp (bhcompilecrowe.devel.redhat.com) (gcc version 3.4.4 20050721 (Red Hat 3.4.4-2)) #1 SMP Mon Sep 19 18:00:54 EDT 2005 2) [rootq1test01 ~]# uname -a …

存储过程由结构表生成表

结构表 CREATE TABLE JGTB5001( ZDM VARCHAR2(30 BYTE), HZM VARCHAR2(100 BYTE), LX VARCHAR2(50 BYTE), JD VARCHAR2(20 BYTE), WBKLX VARCHAR2(100 BYTE), FUNCTIONNAME VARCHAR2(50 BYTE), FUNCTIONPARAMETER VARCHAR2(50 BYTE)); 生成的TB表CREATE OR REPLACE PROCEDURE P…

好礼相送|CSDN云原生 Meetup 成都站报名热烈启动,12.18见!

伴随着容器、Kubernetes及微服务等技术热度的持续攀升&#xff0c;云原生正以不可撼动之势&#xff0c;剑指云计算的下一个十年。12月18日&#xff0c;CSDN将在成都举办第三场云原生线下Meetup。在这里&#xff0c;您可以了解各大领先企业的云原生落地实践&#xff0c;与众多云…

vue-music 音乐网站

在学习完vueJS,一直想做个项目来锻炼一下,选来选去&#xff0c;还是做个网易云音乐&#xff0c;其间遇到了很多坑,也逐渐接受了vue这种组件化的思想以及从Dom操作转换为用数据去驱动视图。并且在某部分基础组件上借鉴(搬运)了elementUI的源码(不过elementUI写的是真好) 技术栈 …

shell环境变量

shell环境变量 环境变量 还记得上一章里面﹐我曾经提到过﹕当我们登入系统的时候﹐首先就获得一 shell﹐而且它也占据一个行程&#xff08;进程&#xff09;﹐然后再输入的命令都属于这个 shell 的子程序&#xff08;子进程&#xff09;。如果您学习够细心﹐不难发现我们的 sh…

apache用户认证

先创建一个“用户认证”目录&#xff08;设为abc&#xff09;[rootLAMPLINUX ~]# cd /data/www[rootLAMPLINUX www]# mkdir abc进入abc目录[rootLAMPLINUX www]# cd abc拷贝一个文件&#xff08;作用&#xff1a;验证配置是否生效&#xff09;[rootLAMPLINUX abc]# cp /etc/pas…

20个经典函数细说 Pandas 中的数据读取与存储,强烈建议收藏

作者 | 俊欣来源 | 关于数据分析与可视化大家好&#xff0c;今天小编来为大家介绍几个Pandas读取数据以及保存数据的方法&#xff0c;毕竟我们很多时候需要读取各种形式的数据&#xff0c;以及将我们需要将所做的统计分析保存成特定的格式。我们大致会说到的方法有&#xff1a;…

fastlane自动打包--详细介绍

fastlane--Packaging 自动化打包&#xff0c;通过fastlane自动发布Fastlane安装不在这里详细罗列&#xff0c;参照一下链接流程 https://www.jianshu.com/p/0a113f754c09操作步骤 1.检查Fastlane是否正确安装。输入以下命令&#xff1a; fastlane --version 复制代码可以看到Fa…

【Big Data】HADOOP集群的配置(一)

Hadoop集群的配置&#xff08;一&#xff09; 摘要: hadoop集群配置系列文档&#xff0c;是笔者在实验室真机环境实验后整理而得。以便随后工作所需&#xff0c;做以知识整理&#xff0c;另则与博客园朋友分享实验成果&#xff0c;因为笔者在学习初期&#xff0c;也遇到不少问题…

C语言 条件编译详解

预处理过程扫描源代码&#xff0c;对其进行初步的转换&#xff0c;产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。在C 语言中&#xff0c;并没有任何内在的机制来完成如下一些功能&#xff1a;在编译时包含其他源文件、定义宏、根据条件决定编译时是…

凝聚406万开发者 飞桨十大发布提速产业智能化

12月12日&#xff0c;由深度学习技术及应用国家工程实验室主办的WAVE SUMMIT2021深度学习开发者峰会在上海召开。百度首席技术官、深度学习技术及应用国家工程实验室主任王海峰公布飞桨最新成绩单&#xff1a;凝聚406万开发者、创建47.6万模型、服务15.7万企事业单位&#xff0…

环境变量,cp,mv,查看文档命令

2019独角兽企业重金招聘Python工程师标准>>> 一、环境变量PATH echo $PATH 打印当前的环境变量 PATH$PATH:路径 自定义环境变量 which查找某个命令的绝对路径&#xff0c;也可以查看某个命令的别名&#xff0c;which查找的范围就在PATH下的几个目录下查找&#xff1…

Linux中errno使用

当linux中的C api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因&#xff0c;在实际编程中用这一招解决了不少原本看来莫名其妙的问题。但是errno是一个数字&#xff0c;代表的具体含义还要到errno.…

工程师文化:BAT 为什么不喊老板

BAT员工之间不喊老板&#xff0c;也不喊真名&#xff0c;而是用同学、花名&#xff0c;这是虚情假意&#xff1f;还是弘扬武侠文化&#xff1f;还是另有隐情&#xff1f;为什么欧美公司不这么做&#xff1f;本文将带大家走进科学&#xff0c;探索真相。 BAT 的称呼方式 腾讯&am…

SVN常见问题

2019独角兽企业重金招聘Python工程师标准>>> 目录[隐藏] 1. 提示SVN证书过期&#xff1f; 2. 用户名密码校验失败&#xff1f; 3. SVN提交文件时提示文件冲突怎么办&#xff1f; 4. SVN提交文件时提示失败&#xff1f; 1. 提示SVN证书过期&#xff1f; 问题描述&…