最近想为系统添加一个统计脚本,但是系统内的模块是有perl和java两种语言编写,且模块是通过crontab定时调用的,所以需要使用IPC传输信息。

第一个想到的是socket方式,感觉需要统一设定一个端口,不是特别保险,并且全都在一台服务器上,用socket有些浪费,所以打算尝试一下linux的IPC功能。

1.FIFO. 接着想起FIFO,即有名管道。在linux中是一种特殊的文件,因为linux中所有事物都可以被视为文件,所以对FIFO的操作和对文件的操作方式是一样的。

可以使用mkfifo命令创建一个有名管道:

$ mkfifo fifo
$ ll fifo
prw-r--r-- 1 star star 0 Feb 14 15:42 fifo|

属性‘p’表示这个文件是个管道,最后的‘|’也是相同的意义。

先上perl代码:

读管道:
my $fifo = 'fifo';
# 和普通文件一样打开
open( my $fh, "<", $fifo) or die "open($fifo) failed: $!";
seek($fh,,);
while()
{
while(my $line = readline($fh))
{
print "$line";
}
}

。。。

写管道:
my $fifo = 'fifo';
open( my $fh, ">", $fifo) or die "open($fifo) failed: $!";print $fh "test fifo\n";

FIFO是一种先进先出的文件,没有seek等的操作,只能从开始读,写到末尾。与普通文件不同之处在于:

a) 如果当前是为读打开FIFO,则需要有其他进程为写打开FIFO,否则会阻塞(没有设置非阻塞标志)。

b) 如果是为写打开,则需要有其他进程为读打开。

也就是说,默认情况下,读和写至少都要有一个才能正常打开FIFO,如果想要不阻塞在打开操作上,可以使用O_NONBLOCK标志。参考自:http://blog.csdn.net/xiaobai1593/article/details/7402205

sysopen( my $fh, $fifo, O_WRONLY | O_NONBLOCK) or die "open($fifo) failed: $!";

后来没有使用FIFO,原因有两个:

a) java端虽然可以正常操作FIFO文件,但是java的打开文件操作没有O_NONBLOCK方式,如果另一方进程由于非正常原因退出了,那么java会一直阻塞在打开操作上。如果通过设置超时等方式处理,会比较繁琐。

b) 多次写入后,一次读取有可能读取不完整。

另外值得注意的是,对FIFO而言,当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。 PIPE_BUF这个值是可以设置的,所以如果一次写入的数据很小,可以不用担心写写冲突的问题。如果是读的话,应该是只有一个读者才好。

2. shared memory

共享内存在linuxIPC中是性能最高的,因为别的方式需要先把数据复制到内核区,再复制到用户区,而共享内存全部在内存,不经过内核区。

并且,共享内存是可以设置IPC_PRIVATE方式的,提高独立性。

但是它的操作方式和文件类似,这就会有内容覆盖和需要制定位置的问题。也就是说,每次写入新的内容,很容易出错就覆盖掉老的内容,读的时候还得把读过内容删除掉,非常麻烦。

所以没有选择共享内存的方式。

3. Message Queue

最后比较下来,选用了消息队列的方式。

消息队列的好处:

1. 每个消息是相互独立的,数据是被包装成条消息,没有上面的内容覆盖问题。读取都是对消息的操作,比较方便。

2. 操作系统层面上会保证每个消息的完整,不会有写写冲突的存在。

消息队列需要注意的是:读写之间的配合,如果写入过多会导致消息队列到达容量上限,不能再写入;写入的数据不能过大,可以在 /etc/sysctl.conf中设置。http://www.cnblogs.com/samurail/archive/2012/11/14/2770379.html

perl可以直接创建一个消息队列,这点是java做不到的,java只能打开一个已经存在的消息队列。

所以如果想要perl和java之间通过消息队列交互,需要先用perl创建一个消息队列,再把这个消息队列的编号保存在一个文件中,java读取文件获得编号,打开mq进行操作。

perl创建代码如下(使用的是SysV标准):

use IPC::SysV qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRUSR S_IWUSR IPC_NOWAIT);
use IPC::Msg; $key = IPC::SysV::ftok($file,'a');
$msg =new IPC::Msg($key,|IPC_CREAT) or logAbort("create message queue:$!");

移除:

$msg->remove();

为了确保程序意外终止的情况下,不会有消息队列遗留,remove操作最好放在END{}代码区内。

读取:

# infinite loop to read messages from MQ
while () {
$msg->rcv($buf,,$msgtype);
if ($!) {
killThread($thr);
logAbort("read message queue failed: $!");
}
$q->enqueue($buf);
}

$msg->rcv在没有IPC_NOWAIT时会阻塞至有数据来,所以会新建一个线程专门读取mq数据。

写入:

$msg->snd($msgtype, $buf, IPC_NOWAIT) or logWarning("writing message to mq failed. $!");

其中读和写的$msgtype需要一致才行,最简单的就是都设为1。这里设置了IPC_NOWAIT,因为写操作不能阻塞,会影响正常程序运行。

http://perldoc.perl.org/perlipc.html#SysV-IPC

java要操作消息队列有点繁琐,因为java本意是为了跨平台运行,而消息队列是操作系统相关的,所以如果想要操作mq,需要使用JNI。

需要使用的包是lajp-10.05,这是专门开发用来结合java和php优点的包,但是在目前,我们只需要使用其中的IPC部分。

另外,java的项目管理通常都是使用maven,而lajp并不在maven的几个主流仓库中,所以,要想在maven中纳入lajp包,需要做一些额外的工作,

比较方便的是使用maven把lajp包放入本地的maven仓库,这样可以随时使用:

mvn install:install-file -Dfile=./lajp-10.05/lajp-10.05.jar -DgroupId=lajp -DartifactId=lajp -Dversion=10.5 -Dpackaging=jar -DgeneratePom=true

成功之后,在pom里就可以和往常一样把lajp写入<dependency></dependency>中。在java代码中还得加入:

static {
//JNI
System.loadLibrary("lajpmsgq");
});
}

java操作mq:

import lajp.MsgQ;

Integer key;
// 打开
msqid = MsgQ.msgget(key);
// 写
// 1:和perl中$msgType一致
MsgQ.msgsnd(msqid, 1, str.getBytes(), str.getBytes().length);

这里的key即时前文中perl写在文件中的key。

4. 命令行查看和删除IPC

查看命令:

ipcs

删除命令:

ipcrm

可以指定删除某一个IPC对象

usage: ipcrm [ [-q msqid] [-m shmid] [-s semid]
[-Q msgkey] [-M shmkey] [-S semkey] ... ]

ps:perl中,在使用了chdir之后,再使用abs_path,结果和预料的有时候会有偏差。。。

在操作IPC对象时,需要考虑如果进程突然终止或退出了的情况,这时候往往会在IPC对象中留下遗留数据(比如在统计时间时,需要写入结束标志才能统计一个任务的时间,而进程突然中止后,mq中收不到结束标志了,另一个统计进程会认为这个任务一直在运行)。这时候需要使用一些预防措施,如在java中使用

Runtime.getRuntime().addShutdownHook()

函数,在退出时,会由jvm执行,补上结束标志。

linux下fifo,mq,shm的更多相关文章

  1. linux下的/dev/shm目录

    linux下的/dev/shm目录 linux中/dev目录下一般都是一些设备文件,例如磁盘.内存.摄像头等. /dev/shm这个目录是linux下一个利用内存虚拟出来的一个目录,这个目录中的文件都 ...

  2. Linux下安装MQ

    1.下载Linux下MQ的安装包,网上下载试用版或购买正版,此处以7.0.0.0版为例安装 2.如上图所示,是linux的MQ安装包展开图 3.创建用户和用户组 >root用户连接linux & ...

  3. linux下的/dev/shm/ 以及与swap目录的区别【转】

    /dev/shm 概念 首先可以看出来/dev/shm是一个设备文件, 可以把/dev/shm看作是系统内存的入口, 可以把它看做是一块物理存储设备,一个tmp filesystem, 你可以通过这个 ...

  4. linux下的/dev/shm/及对Oracle 的影响

    一./dev/shm/介绍: /dev/shm/是linux下一个非常有用的目录,因为这个目录不在硬盘上,而是在内存里.因此在linux下,就不需要大费周折去建ramdisk,直接使用/dev/shm ...

  5. linux下修改/dev/shm tmpfs文件系统大小

    默认系统就会加载/dev/shm ,它就是所谓的tmpfs,有人说跟ramdisk(虚拟磁盘),但不一样.象虚拟磁盘一样,tmpfs 可以使用您的 RAM,但它也可以使用您的交换分区来存储.而且传统的 ...

  6. 用linux服务器下的/dev/shm/来释放磁盘的压力

    巧用linux服务器下的/dev/shm/来释放磁盘的压力 浏览:646 | 更新:2013-06-18 18:08 | 标签: 磁盘 tmpfs是Linux/Unix系统上的一种基于内存的文件系统. ...

  7. Linux下的几种IPC方式及其C语言实现

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  8. 20155202 张旭 课下作业: Linux下IPC机制

    20155202张旭 Linux下IPC机制 IPC机制定义 在linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication),它是多个进程之间相互沟通的一种方 ...

  9. 2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制

    2017-2018-1 20155222 <信息安全系统设计基础>第10周 Linux下的IPC机制 IPC机制 在linux下的多个进程间的通信机制叫做IPC(Inter-Process ...

随机推荐

  1. mysql死锁-非主键索引更新引起的死锁

    背景:最近线上经常抛出mysql的一个Deadlock,细细查来,长了知识! 分析:错误日志如下: 21:02:02.563 ERROR dao.CommonDao        [pool-15-t ...

  2. jquery 轮播图实例

    实现效果:1.图片每2秒钟切换1次. 2.当鼠标停留在整个页面上时,图片不进行轮播. 3.当点击右下角的小球时,出现该选项的对应图片,而且切换页选项的背景颜色发生相应的变化. 4.当图片发生轮播切换时 ...

  3. 【IE兼容性】代码中多语言样式+IE不兼容解决

    一.代码中样式根据不同语言对IE做不兼容解决 二.代码逻辑: 1. 后台返回语言信息: result.addObject("language",getLocaleStr());   ...

  4. MD5-【验签】

    MD5是什么? MD5是message-digest algorithm 5(信息-摘要算法)的缩写,被广泛用于加密和解密技术上,它可以说是文件的"数字指纹".任何一个文件,无论是 ...

  5. Openstack虚拟机创建流程

    续上一篇Openstack安装配置 一,keystone交互认证阶段 1,发送用户名和密码给keystone认证获取token 2,带着token访问nova-api 3,nova-api使用toke ...

  6. 学习使用turtlebot2——turtlebot2上使用Hokuyo激光雷达(型号UST-10LX)

    目标     在turtlebot2上添加Hokuyo激光雷达传感器,使用激光雷达调用gmapping进行建图. 配置情况     电脑使用Ubuntu 14.04版本,ROS为 Indigo,激光雷 ...

  7. npm的本地模式与全局模式

    关于npm的本地模式和全局模式的总结: npm install命令就是采用本地模式,即把包安装到当前目录的node_modules子目录下:npm [install/i] [package_name] ...

  8. python list中append()与extend()用法

    列表是以类的形式实现的.“创建”列表实际上是将一个类实例化.因此,列表有多种方法可以操作. 1. 列表可包含任何数据类型的元素,单个列表中的元素无须全为同一类型. 2. append() 方法向列表的 ...

  9. 原!!关于java 单元测试Junit4和Mock的一些总结

    最近项目有在写java代码的单元测试,然后在思考一个问题,为什么要写单元测试??单元测试写了有什么用??百度了一圈,如下: 软件质量最简单.最有效的保证: 是目标代码最清晰.最有效的文档: 可以优化目 ...

  10. 几分钟私人定制APP全攻略!!

    上网百度了一下什么是自媒体,你会看到这种介绍:自媒体(外文名:We Media)又称"公民媒体"或"个人媒体",是指私人化.平民化.普泛化.自主化的传播者,以现 ...