最近想为系统添加一个统计脚本,但是系统内的模块是有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. HDU 4059 The Boss on Mars(容斥原理)

    The Boss on Mars Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  2. Scala 中我们长见到=> 解析下

    =>这符号其实是映射转化的意思,个人理解,可能不准确, var increase = (x: Int) => x + 1 increase(10) res0: Int = 11 意思就是你 ...

  3. Grunt-Less批量编译为css

    Grunt批量编译less module.exports = function (grunt) { grunt.initConfig({ less: { main: { expand: true, s ...

  4. iMessenger 2.0.14.0801简述

    有些梦,看似遥不可及.但并非不能实现,仅仅要你足够的强!!.人力有时而穷,所以我们可能还须要一些热心人的帮助.这个人可能就是你. 四年来,我们一直在努力,从未放弃. 在我们做好一件事之前.我们永远不知 ...

  5. Activity # runOnUiThread 与 View # post

    There is no real difference, except that the View.post is helpful when you don't have a direct acces ...

  6. SQL逻辑查询语句 执行顺序 语法顺序

    SELECT语句语法顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOIN < ...

  7. Python基础总结(字符串常用,数字类型转换,基本运算符与流程控制)

    一.字符串常用操作 #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格) name='*egon**' print(name.strip('*'))#移除 name 变量对应 ...

  8. mybatis 插入之后返回id

    usermapper.xml <insert id="insert" parameterType="app.models.User" keyPropert ...

  9. HDFS 详解

    HDFS 概述 基于2.7.3 HDFS 优点: 1.高容错性 数据自动保存多个副本,默认是三个副本 副本丢失后,会自动恢复 2.适合批处理 移动计算而非移动数据,批处理的时候,数据量很大,移动数据是 ...

  10. js防抖

    那我们设置个 options 作为第三个参数,然后根据传的值判断到底哪种效果,我们约定: leading:false 表示禁用第一次执行trailing: false 表示禁用停止触发的回调 我们来改 ...