【Linux】利用消息队列实现一个简单的进程间双向通信(两种方式)

2023-10-30

在实现利用消息队列的进程间通信之前,先了解一下基本的概念和所需要用到的函数。

消息队列

  • 消息队列是Linux内核地址空间中的内部链表,各个进程可以通过它来进行消息传递。
  • 进程发送的消息会顺序写入消息队列之中,且每个消息队列都有IPC标识符唯一地进行标识。简单理解就是,每个消息队列都有一个ID号,而这个号用来区分不同的消息队列,从而保证不同消息队列之间不冲突。而每个消息队列内部也维护了一个独立的链表。

消息缓冲区的基本结构

消息缓冲区可以理解成进程通过消息队列在传送或接收消息时的信息容器。
当有人发送信息时则将信息通过消息缓冲区放入队列,有人读取此消息队列时,则从队列中取出信息放入接收方缓冲区(先进先出)。
在这里插入图片描述
而消息缓冲区的常用结构是msgbuf结构:

struct msgbuf{
	long mtype;
	char mtext[1];
}

其中第一个成员mtype表示消息类型,一般用正数来表示,其作用是为某个消息设定一个类型,从而保证自己在消息队列中正确地发送和接收自己的消息
第二个成员即具体的数据,其大小可以由我们自行重新构建。

消息的大小有一个最大限制,其定义在Linux/msg.h文件中
#define MSGMAX 8192
也就是说,消息结构的总大小不能超过8192字节(包括type的大小)

键值构建ftok()函数

前面说到了,每个消息队列都需要一个唯一的IPC作为标识符。
而ftok()函数即实现将文件路径名和项目的表示符转变成一个系统IPC键值。
它的函数原型描述如下:

# include <sys/types.h>
# include <sys/ipc,.h>
key_t ftok(const char *pathname, int proj_id);

其中的pathname必须是已经存在的目录,而项目的表示符是一个8位,1个字节的值,通常情况下用a,b等字母表示。

获得消息msgget()函数

如果我们想访问消息队列的信息或者向消息队列写入信息,首先便要使用msgget()函数,它会返回一个队列标识符。
它的作用就是创建一个新的消息队列,或者访问一个已经存在的消息队列。
其函数原型如下所示:

# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg,h>
int msgget(key_t key, int msgflg);

该函数的第一个参数不难理解,就是刚才ftok()函数生成的唯一ipc键值,它用来定位消息队列。
而第二个参数则是在定位到消息队列之后的一系列权限操作。其取值有IPC_CREAT与IPC_EXCL两种:

  1. IPC_CREAT:若内核中不存在指定队列就创建它;
  2. IPC_EXCL:当与IPC_CREAT一起使用时,若队列已存在则出错(函数返回-1)。

实际上,第二个参数还需要与文件权限一起使用,如IPC_CREAT|00666表示若内核中不存在指定队列则创建它,同时进程可以对队列消息进行读写操作。
简单点儿说,就是第一个用来找到队列,第二个则是定义相关的权限及操作。

发送消息msgsnd()函数

当我们通过msgget()函数得到了队列标识符,我们就可以在对应的消息队列上来执行相关的读写操作了,如果我们要发送消息,则需要用到的就是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);

其实从命名就可以大概看出来,第一个参数是消息队列的id,message queue id,即用来告诉系统向哪个消息队列发送消息;
第二个参数是message pointer,是一个空型指针,这个但从命名似乎看不太出来其意义,但是根据刚刚画的那个小模型,应该需要用到消息缓冲区,其实这个指针就是指向消息缓冲区的;
第三个参数是message size,顾名思义,就是消息的长度,它是以字节为单位的,注意,这里的大小单纯指消息的大小,并不含消息类型的大小;
第四个参数是message flag,它通常取0,也就是忽略它,也可以设置成IPC_NOWAIT,如果设置成后者,也就是不等待,即消息队列满了的话就不等了,今天你爱搭不理,明天我高攀不起,若不指定的话,则会阻塞等待,直到可以写入为止。

接受消息msgrcv()函数

同样的道理,当我们获取了队列标识符后,也可以通过msgrcv()函数来在指定消息队列上接受消息,其函数原型如下:

# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/msg,h>
int msgrcv(int msqid, void *msgp, size_t msgsz,  long msgtyp, int msgflg);

前三个参数和上述发送函数msgsnd()函数的参数作用相同
最后一个参数作用也是一样的。
而第四个参数则指定要从队列中获取的消息类型,若取0,则不管是什么类型都接收。

利用消息队列实现一个简单的进程间通信

在介绍完上述概念之后,我们可以知道每个消息队列都有一个独特的IPC值,而每个消息队列内,可以有不同类型的消息进行传递。
而进程在收发消息时,都需要借助一个消息缓冲区进行。
故而单向通信只要保证不同进程读写的是同一个消息队列(key值相同),并且收发同一种消息类型即可。
双向通信则可以通过以下两种基本方式进行:

  1. 创建两个消息队列来进行通信
    根据之前的简单模型,我们可以画出使用这种方式进行双向通信的基本示意图:
    在这里插入图片描述
    也就是说,两个不同的进程需要使用两个对应的key来调用msgget()函数。
    这里直接po代码和注释:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/msg.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    
    int main(){
    	int ret = -1;
    	int msg_flags, smsg_id ,rmsg_id;/*创建消息队列函数所用的标志位,以及收消息与发消息的队列id*/
    	key_t key1,key2;/*队列的键值*/
    	struct msgmbuf{/*消息的缓冲区结构*/
    		long mtype; // 注意long与int的字长问题
    		char mtext[10];
    		};
    	struct msgmbuf msg_mbuf;/*创建消息缓冲区*/
    	
    	int msg_sflags,msg_rflags;/*收发消息函数所用的标志位*/
    	char *msgpath1 = "/usr/bin";/*消息key1产生所用的路径*/
    	char *msgpath2 = "/usr/bin";/*消息key2产生所用的路径*/
    	key1 = ftok(msgpath1,'b');/*产生key1*/
    	key2 = ftok(msgpath2,'a');/*产生key2*/
    	if(key1 != -1 || key2 != -1)/*产生key成功*/
    	{
    		printf("成功建立KEY\n");		
    	}
    	else/*产生key失败*/
    	{
    		printf("建立KEY失败\n");		
    	}
    	msg_flags = IPC_CREAT;//|IPC_EXCL;		/*设置创建消息的标志位*/
    	smsg_id = msgget(key1, msg_flags|0666); /*建立收消息的消息队列*/
    	rmsg_id = msgget(key2, msg_flags|0666);	/*建立发消息的消息队列*/
    	if( -1 == smsg_id || -1 == rmsg_id)
    	{
    		printf("消息建立失败\n");
    		return 0;		
    	}	
    
    	pid_t pid;
    	pid = fork();/*通过fork()创建子进程,主进程进行发消息,子进程进行收消息*/
    
    	while(1){
    		if(pid != 0){/*主进程*/
    		msg_sflags = IPC_NOWAIT;/*当消息队列满了的时候不等待*/
    		msg_mbuf.mtype = 10;/*设置发送的消息类型*/
    		sleep(1);
    		char *content;
    		content = (char*)malloc(10*sizeof(char));
    		printf("input:\n");
    		scanf("%s",content);/*用户输入内容*/
    		if(strncmp(content,"end",3) == 0)/*如果前三个字符为end,则跳出循环*/
    			break;
    	
    		memcpy(msg_mbuf.mtext,content,10);/*复制字符串*/
    		ret = msgsnd(smsg_id, &msg_mbuf, 10, msg_sflags);/*发送消息*/
    		if( -1 == ret)
    		{
    			printf("发送消息失败\n");		
    		}
    		}
    		else{/*子进程*/
    			sleep(1);
    			msg_mbuf.mtype = 10;/*设置收消息的类型*/
    			msg_rflags = IPC_NOWAIT;//|MSG_NOERROR;
    			ret = msgrcv(rmsg_id, &msg_mbuf,10,10,msg_rflags);/*接收消息*/
    			if( -1 == ret)
    			{
    				/*可添加出错处理等*/
    			}
    			else
    			{
    				printf("接收消息成功,长度:%d\n",ret);	
    				printf("content:%s\n",msg_mbuf.mtext);	
    			}
    		
    		}
    	}
    
    	ret = msgctl(rmsg_id, IPC_RMID,NULL);/*删除收消息的队列*/
    	if(-1 == ret)
    	{
    		printf("删除消息失败\n");
    		return 0;		
    	}
    	return 0;
    }
    
    上述代码是其中一个文件所使用的,而另一个只需要将收发消息的队列颠倒即可(将key值交换)。
  2. 通过创建不同的消息类型来进行双向通信
    这种方式是指在同一个消息队列中,使用不同的消息类型来标识收发信息,基本示意图如下:
    在这里插入图片描述
    图中不同颜色的信息表示不同的消息类型。这就要求在发送信息时将消息缓冲区中的类型值设置好,在收信息时则要在msgrcv()函数中的第四个参数匹配发送方的消息类型。
    代码如下:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/msg.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    
    int main(){
    	int ret = -1;
    	int msg_flags, msg_id;/*创建消息队列函数所用的标志位以及消息队列的id号*/
    	key_t key;/*队列的键值*/
    	struct msgmbuf{/*消息的缓冲区结构*/
    		long mtype; // 注意long与int类型的字长问题
    		char mtext[10];
    		};
    	struct msgmbuf msg_mbuf;/*创建消息缓冲区*/
    	
    	int msg_sflags,msg_rflags;/*收发消息函数所用的标志位*/
    	char *msgpath = "/usr/bin/";/*消息key产生所用的路径*/
        key = ftok(msgpath,'b');/*产生key*/
    	if(key != -1)/*产生key成功*/
    	{
    		printf("成功建立KEY\n");		
    	}
    	else/*产生key失败*/
    	{
    		printf("建立KEY失败\n");		
    	}
    	msg_flags = IPC_CREAT;//|IPC_EXCL;		/*设置创建消息的标志位*/
    	msg_id = msgget(key, msg_flags|0666);	/*建立消息队列*/
    	if( -1 == msg_id )
    	{
    		printf("消息建立失败\n");
    		return 0;		
    	}	
    
    	pid_t pid;
    	pid = fork();/*通过fork()创建子进程,主进程进行发消息,子进程进行收消息*/
    
    	while(1){
    		if(pid != 0){/*主进程*/
    		msg_sflags = IPC_NOWAIT;
    		msg_mbuf.mtype = 10;/*发送消息的类型为10,另一个进程收消息的类型应为10*/
    		sleep(1);
    		char *content;
    		content = (char*)malloc(10*sizeof(char));
    		printf("input:\n");
    		scanf("%s",content);/*用户输入内容*/
    		if(strncmp(content,"end",3) == 0)/*如果前三个字符为end,则跳出循环*/
    			break;
    	
    		memcpy(msg_mbuf.mtext,content,10);/*复制字符串*/
    		ret = msgsnd(msg_id, &msg_mbuf, 10, msg_sflags);/*发送消息*/
    		if( -1 == ret)
    		{
    			printf("发送消息失败\n");		
    		}
    		}
    		else{/*子进程*/
    			sleep(1);
    			msg_mbuf.mtype = 11;/*收消息的类型为11,另一个进程发消息的类型应为11*/
    			msg_rflags = IPC_NOWAIT;//|MSG_NOERROR;
    			ret = msgrcv(msg_id, &msg_mbuf,10,11,msg_rflags);/*接收消息*/
    			if( -1 == ret)
    			{
    				/*可添加出错处理等*/
    			}
    			else
    			{
    				printf("接收消息成功,长度:%d\n",ret);	
    				printf("content:%s\n",msg_mbuf.mtext);	
    			}
    		
    		}
    	}
    
    
    	ret = msgctl(msg_id, IPC_RMID,NULL);/*删除消息队列*/
    	if(-1 == ret)
    	{
    		printf("删除消息失败\n");
    		return 0;		
    	}
    	return 0;
    }
    
    同样的,这里只是其中一个文件的代码,而另一个将对应的收发信息的类型颠倒即可。
    最终两者实现的效果是相同的:
    在这里插入图片描述

从上面的代码我们可以观察到一个没有提到的函数msgctl()函数,它是用来在消息队列上执行控制操作,如获取队列的基本情况,设置消息队列状态以及删除队列等。
在了解msgctl()函数之前,应该先了解一下消息队列的基本结构,实际上,每个消息队列都有相应的数据结构来记录其信息:

struct msqid_ds {
	struct ipc_perm msg_perm;
	struct msg *msg_first;		/* first message on queue,unused  */
	struct msg *msg_last;		/* last message in queue,unused */
	__kernel_time_t msg_stime;	/* last msgsnd time */
	__kernel_time_t msg_rtime;	/* last msgrcv time */
	__kernel_time_t msg_ctime;	/* last change time */
	unsigned long  msg_lcbytes;	/* Reuse junk fields for 32 bit */
	unsigned long  msg_lqbytes;	/* ditto */
	unsigned short msg_cbytes;	/* current number of bytes on queue */
	unsigned short msg_qnum;	/* number of messages in queue */
	unsigned short msg_qbytes;	/* max number of bytes on queue */
	__kernel_ipc_pid_t msg_lspid;	/* pid of last msgsnd */
	__kernel_ipc_pid_t msg_lrpid;	/* last receive pid */
};

此定义位于linux源代码的include/uapi/linux/msg.h之中。可以看到它记录了消息队列的许可权限信息,以及消息时间戳,消息数目,当前的消息大小,最大容量以及使用该消息队列进行收发的进程id等。
而结果ipc_perm的定义如下:

struct ipc_perm
{
	__kernel_key_t	key;//函数msgget()使用的键值
	__kernel_uid_t	uid;//用户的uid
	__kernel_gid_t	gid;//用户的gid
	__kernel_uid_t	cuid;//建立者的uid
	__kernel_gid_t	cgid;//建立责的gid
	__kernel_mode_t	mode; //权限
	unsigned short	seq;//序列号
};

它的定义位于linux源代码的include/uapi/linux/ipc.h之中,此文件中还有如上述IPC_START等参数定义。
此时我们再来看msgctl()的函数原型:

# include <sys/types.h>
# include <sys/ipc,h>
# include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

第一个参数顾名思义,就是message queue id,即操作的消息队列的id,由msgget()函数获得;
第二个参数是控制命令,它的取值如下:

#define IPC_RMID 0     /* remove resource */
#define IPC_SET  1     /* set ipc_perm options */
#define IPC_STAT 2     /* get ipc_perm options */
#define IPC_INFO 3     /* see ipcs */

IPC_STAT即获取队列的msqid_ds中的ipc_perm的设置(这个要看linux内核版本,有的可以用其查看整个结构信息),并把它存放在第三个参数指向的位置。
IPC_RMID即将对应的消息队列从内核中删除
IPC_SET即设置消息队列结构中的ipc_perm的成员的值
IPC_INFO即获取结构信息(这个要看linux内核版本,有的并没有这个值)
而msgctl()函数的第三个参数即指向消息队列数据结构的buf指针。

以上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux】利用消息队列实现一个简单的进程间双向通信(两种方式) 的相关文章

  • 在Linux上编译C# + WPF以便在Windows上运行

    我有一个 C 应用程序 其中某些部分是使用 WPF 编写的 Mono 不支持 可以在 Linux 上编译这个应用程序吗 最终 该应用程序将在 Windows 上运行 但它是更大框架的一部分 并且我们的整个构建过程在 Linux 上运行 因此
  • ansible 重新启动 2.1.1.0 失败

    我一直在尝试创建一个非常简单的 Ansible 剧本 它将重新启动服务器并等待它回来 我过去在 Ansible 1 9 上有一个可以运行的 但我最近升级到 2 1 1 0 并且失败了 我正在重新启动的主机名为 idm IP 为 192 16
  • awk 子串单个字符

    这是columns txt aaa bbb 3 ccc ddd 2 eee fff 1 3 3 g 3 hhh i jjj 3 kkk ll 3 mm nn oo 3 我可以找到第二列以 b 开头的行 awk if substr 2 1 1
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • 强制卸载 NFS 安装目录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • Linux 中的无缓冲 I/O

    我正在写入大量的数据 这些数据数周内都不会再次读取 由于我的程序运行 机器上的可用内存量 显示为 空闲 或 顶部 很快下降 我的内存量应用程序使用量不会增加 其他进程使用的内存量也不会增加 这让我相信内存正在被文件系统缓存消耗 因为我不打算
  • 使用 grep 查找包含所有搜索字符串的行

    我有一个文件 其中包含很多与此类似的行 id 2796 some model Profile message type MODEL SAVE fields account 14 address null modification times
  • GLIBCXX_3.4.26 未找到在 BeagleBone 上运行交叉编译的程序

    我有以下程序 include
  • nginx 上的多个网站和可用网站

    通过 nginx 的基本安装 您的sites available文件夹只有一个文件 default 怎么样sites available文件夹的工作原理以及如何使用它来托管多个 单独的 网站 只是为了添加另一种方法 您可以为您托管的每个虚拟
  • 如何根据 HTTP 请求使用 Python 和 Flask 执行 shell 命令并流输出?

    下列的这个帖子 https stackoverflow com questions 15092961 how to continuously display python output in a webpage 我能够tail f网页的日志
  • 我可以从命令行打印 html 文件(带有图像、css)吗?

    我想从脚本中打印带有图像的样式化 html 页面 谁能建议一个开源解决方案 我使用的是 Linux Ubuntu 8 04 但也对其他操作系统的解决方案感兴趣 你可以给html2ps http user it uu se jan html2
  • Linux 中的动态环境变量?

    Linux 中是否可以通过某种方式拥有动态环境变量 我有一个网络服务器 网站遵循以下布局 site qa production 我想要一个环境变量 例如 APPLICATION ENV 当我在 qa 目录中时设置为 qa 当我在生产目录中时
  • Android 时钟滴答数 [赫兹]

    关于 proc pid stat 中应用程序的总 CPU 使用率 https stackoverflow com questions 16726779 total cpu usage of an application from proc
  • 无法使用 wget 在 CentOS 机器上安装 oracle jdk

    我想在CentOS上安装oracle java jdk 8 我无法安装 java jdk 因为当我尝试使用命令安装 java jdk 时 root ADARSH PROD1 wget no cookies no check certific
  • PHP 从命令行启动 gui 程序,但 apache 不启动

    首先 我阅读了有类似问题的人的一些帖子 但所有答案都没有超出导出 DISPLAY 0 0 和 xauth cookies 这是我的问题 提前感谢您的宝贵时间 我开发了一个小库 它使用 OpenGL 和 GLSL 渲染货架 过去几天我将它包装
  • 如何在apache 2.4.6上安装apxs模块

    我刚刚用过apt get update我的 apache 已更新为2 4 6 我想安装 apxs 来编译模块 但收到此错误 The following packages have unmet dependencies apache2 pre
  • 使用 sh 运行 bash 脚本

    我有 bash 脚本 它需要 bash 另一个人尝试运行它 sh script name sh 它失败了 因为 sh 是他的发行版中 dash 的符号链接 ls la bin sh lrwxrwxrwx 1 root root 4 Aug
  • iptables通过注释删除特定规则

    我需要删除一些具有相同评论的规则 例如 我有带有 comment test it 的规则 所以我可以像这样获得它们的列表 sudo iptables t nat L grep test it 但是我怎样才能删除所有带有注释 测试它 的 PR
  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • ubuntu:升级软件(cmake)-版本消歧(本地编译)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我的机器上安装了 cmake 2 8 0 来自 ubuntu 软件包 二进制文件放置在 usr bin cmake 中 我需要将 cmake 版本至少

随机推荐

  • #python 输入三条边的长度,判断这几条边是否能组成三角形

    python 输入三条边的长度 判断这几条边是否能组成三角形 问题描述 输入三角形的三条边 判断该三角形的形状 周长 面积和每条边的高 第一步 导入所需要的库math import math 第二步 判断此三条线段是否能组成三角形 判断条件
  • JSP数据交互(一)---内置对象》application:

    JSP数据交互 一 内置对象 application application实现用户之间的数据共享 application对象常用方法 applicatiion常用方法 方法名称 说明 void 色图Attribute String key
  • pandas读取Excel file

    Pandas read excel 参数 pandas read excel io sheet name 0 header 0 names None index col None usecols None squeeze False dty
  • Oracle + MyBatis 3 实现批量新增/修改

    批量新增Mapper 定义 public interface BaseHouseMapper 批量新增Mapper 定义 void batchInsert Param list List
  • git 查看该项目在git的具体地址

    在终端输入如下命令 git remote v 结果如下 上图显示的是该项目的git地址
  • 【Python】Pycharm连接云服务器的MySQL数据库详细步骤

    Pycharm连接数据库 MySQL 云服务器 准备阶段 pycharm的配置 服务器配置 问题汇总 准备阶段 准备阶段 pycharm正确运行环境 服务器一枚 pycharm直接官网下载 我是用的2020 3 2版本 服务器是腾讯云的免费
  • 关于android的WebView

    android webkit库聚合了webkit内核的浏览器功能 webview就是她的一个控件 可以使得网页轻松的内嵌到app里 并且比较强大的是 还可以直接跟js相互调用 webview有两个方法 setWebChromeClient和
  • flutter设置状态栏颜色

    Android flutter SystemUiOverlayStyle systemUiOverlayStyle SystemUiOverlayStyle statusBarColor Colors transparent SystemC
  • C语言程序设计之猜数字游戏(随机数的讲解)

    游戏玩法 电脑随机生成一个随机数 1 100之间 玩家根据提示进行猜测 直到猜对为止 相关知识点 分支与循环 随机数的生成 时间戳 标准输入输出 强制类型转换等 时间戳和随机数的生成将在本篇blog中重点讲解 其他知识点在其他blog中有重
  • 关于视频自动截取封面_ ffmpeg

    后台富文本框内 插入视频后 保存信息时 对视频封面处理 ffmpeg下载地址 创建bat文件 如以下关于bat文件的内容 start C Users 83469 Desktop ffmpeg 20180310 2536bd8 win64 s
  • Android 虚拟机简单介绍——ART、Dalvik、启动流程分析

    Android 虚拟机方面的知识 我是通过 深入理解 Android 内核设计思想 来学习的 内容特别多 只有一章 但有 160 页 感觉和 Android 开发有些偏 因此很多内容都没有认真去看 比如 EFL 格式等 这里只是选取了一些感
  • 尝试CornerNet-Lite进行目标识别并嵌入ROS

    CornerNet Lite是刚开源不久的实时目标检测方法 据说比YOLO3 牛逼 于是打算尝鲜一波 首先说运行的环境要求 1 Python 3 7 2 PyTorch 1 0 0 3 CUDA 10 意思是你得有一张NVIDIA的显卡 比
  • 10款最好用的代码编辑器 你是用哪种登录酷游?

    你是学习程式语言的初学者吗 本文由酷游登录网址AP98点NE 原创 未经许可请勿转发 可能刚学会第一门代码语言 或是厌倦了当前的代码编辑器 想改换一款介面美观又好用 以下将整理5款我们认为好用的代码编辑器 也欢迎各位分享自己正在使用的咯 1
  • 在Ubuntu上使用NFS挂载

    假设要把192 16 2 101服务器上的 home sharedata 挂载到192 16 2 102服务器上的 home receive data 一 服务端 1 安装NFS服务端 sudo apt get install nfs ke
  • 结合分析和数值技术 Python 在基本力学应用

    特点 展示了如何将分析方法和数值方法无缝集成来解决物理问题 内容 介绍 开始编程 单位和测量 一维运动 一维力 二维和三维运动 二维和三维力 受限运动 力和约束运动 工作能量 动量 脉冲和碰撞 多粒子系统 旋转运动 刚体的旋转 刚体动力学
  • java aop拦截器

    可在切面代码修改为数据库获取或redis中获取 依赖
  • 大数据平台搭建及搭建过程出错解析

    1 安装第一台虚拟机 参照博主文章 连接如下 https blog csdn net weixin 46457946 article details 114758813 2 配置网卡 配置网卡前看看你的ifconfig命令能不能用 一般来说
  • go详解strings包

    Count 计算字符串 sep 在 s 中的非重叠个数 如果 sep 为空字符串 则返回 s 中的字符 非字节 个数 1 使用 Rabin Karp 算法实现 html view plain copy func Count s sep st
  • 【Java开发者专场】阿里专家杜万:Java响应式编程,一文全面解读 ...

    本篇文章来自于2018年12月22日举办的 阿里云栖开发者沙龙 Java技术专场 杜万专家是该专场第四位演讲的嘉宾 本篇文章是根据杜万专家在 阿里云栖开发者沙龙 Java技术专场 的演讲视频以及PPT整理而成 摘要 响应式宣言如何解读 Ja
  • 【Linux】利用消息队列实现一个简单的进程间双向通信(两种方式)

    在实现利用消息队列的进程间通信之前 先了解一下基本的概念和所需要用到的函数 消息队列 消息队列是Linux内核地址空间中的内部链表 各个进程可以通过它来进行消息传递 进程发送的消息会顺序写入消息队列之中 且每个消息队列都有IPC标识符唯一地