SysV IPC:Message Queue

いま保守担当しているシステムの一つで SysV IPC のメッセージキューというのを利用してプロセス間通信しているのを発見したため、どんなものなのかさわってみた。

メッセージキューの概要/使い方

次の解説記事を参考にした。

Cコードコンパイル時の注意

コンパイル時に次のような警告メッセージが表示される場合、メッセージ通りにオプションを追加すること。

$ gcc list2.c
In file included from /usr/include/sys/msg.h:29,
from list2.c:2:
/usr/include/sys/ipc.h:25:3: warning: #warning "Files using this header must be compiled with _SVID_SOURCE or _XOPEN_SOURCE"
$ gcc -D_SVID_SOURCE list2.c

_SVID_SOURCE と _XOPEN_SOURCE は Feature test macros の一つ。
両方で動くことを確認したけど、SysV IPC 由来の機能なのだから、”_SVID_SOURCE”のほうが自然か。

_SVID_SOURCE : Defining this macro with any value causes header files to expose System V-derived definitions.

キューまちメッセージの確認

キュー状態のメッセージは ipcs コマンドで確認出来る。

ipcs は標準で次の3つの情報を表示する

  • Shared Memory Segments
  • Semaphore Arrays
  • Message Queues
$ ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
0x2a006adf 0          jsmith     666        0            0
0x0000002d 360449     jsmith     600        6            3
0xffffffff 229378     jsmith     666        224          2
0x0000002a 393219     jsmith     666        30           2

Message Queues のみを表示させるのであれば -q オプションを追加する。

$ ipcs -q
------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
0x2a006adf 0          jsmith     666        0            0
0x0000002d 360449     jsmith     600        6            3
0xffffffff 229378     jsmith     666        224          2
0x0000002a 393219     jsmith     666        30           2

メッセージの送信だけして受信を止めていると、messages の数がどんどん増えていくのを確認できる。

Python バインディング

Cは読むことこそ(担当しているシステムでのみ)たまにあるものの、書くことは無いので、Python でライブラリを探してみると、python-list でピッタリのものを見つけた。

ドキュメントはしっかりしており、コードも非常に読みやすい。

メッセージキューを利用したサンプルも demo2 ディレクトリ内にあるので使ってみる。

コンパイル方法

PyPI ページ : http://pypi.python.org/pypi/sysv_ipc/
ファイルを拾ってきて、展開して INSTALL ファイルに従い $ sudo python setup.py install

Python を起動して sysv_ipc をインポート出来るか確認。

サンプルコード

# IBM DW の記事を移植したプログラム

# mq_server.py

import sysv_ipc
mq = sysv_ipc.MessageQueue(42, sysv_ipc.IPC_CREAT | 0666)
print "id :", mq.id
mq.send("Hello world!")

# mq_client.py

import sysv_ipc
mq = sysv_ipc.MessageQueue(42)
print "id:", mq.id
mtext, mtype = mq.receive()
print mtext

# beej の記事を移植したプログラム

Geek らしくスタートレックが題材に取られている。

# kirk.py

import sysv_ipc

def main():
    mq = sysv_ipc.MessageQueue(ord('B'), sysv_ipc.IPC_CREAT | 0644)
    print "id :", mq.id
    while True:
        try:
            mtext = raw_input("Enter lines of text, ^D to quit:\n")
            mq.send(mtext, type=1)
        except EOFError:
            break
    sysv_ipc.remove_message_queue(mq.id)

if __name__ == '__main__':
    main()

# spock.py

import sysv_ipc

def main():
    mq = sysv_ipc.MessageQueue(ord('B'))
    print "id:", mq.id
    print "spock: ready to receive messages, captain."
    while True:
        mtext, mtype = mq.receive(type=1)
        print 'spock: "%s"'%mtext

if __name__ == '__main__':
    main()

Pythonバインディングの注意点

#1 ftok の注意点
C のコードでは ftok で生成したキーを msgget に渡しているが、Python バインディングでは、MessageQueue に渡されたキーをそのまま msgget に渡している。

著者は ftok を使わない理由を次のように説明

Most sample code that you see involving the use of System V semaphores/shared memory recommends ftok() to generate an integer key that’s guaranteed to be unique on that machine.

…[snip]…

However, most modern implementations of ftok don’t guarantee that it returns a unique key

上記の理由から、プログラマー側がメッセージの種類ごとに衝突しないキーを生成して、MessageQueue に渡すようにという設計の模様。

ftok の man ページをみても、

The value returned should be different when the (simultaneously existing) files or the project IDs differ.

…[snip]…
Of course no guarantee can be given that the resulting key_t is unique.

shouldRFC2119 的には RECOMMENDED なので、まぁ、そういうことだ。

また IBM AIX のマニュアルでは次のように記載されている。

Attention: The ftok subroutine does not guarantee unique key generation. However, the occurrence of key duplication is very rare and mostly for across file systems.

#2 msgget

C のコードでは ftok のあと msgget するが、Python バインディングでは MessageQueue のコンストラクターのなかで、msgget を行っている。
ftok は上記の通り。

#3 msgctl

C のコードでは msqid_ds 型のメンバーは msgctl 経由でIPC_STAT/IPC_SETをつかって set/get するが、Python バインディングでは MessageQueue オブジェクトをそのまま操作する。

obj.attr, obj.attr = value

#4 メッセージのクリーンアップ

C のコードではメッセージのクリーンアップを msgctl 経由でIPC_RMIDをつかって掃除するが、Python バインディングでは MessageQueue のメソッドとして操作する。

サンプルは Beej’s Guide to Unix Interprocess Communication から

o C 版

if (msgctl(msqid, IPC_RMID, NULL) == -1) {
    perror("msgctl");
    exit(1);
}

o Python 版

mq.remove()
OR
sysv_ipc.remove_message_queue(mq.id)
Advertisements
Tagged with: , , ,
Posted in linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
%d bloggers like this: