核心計算模組用 C 實現 (效能),業務邏輯層用 Perl 實現 (開發效率),兩者透過 System V 消息隊列 (IPC) 通訊,實現異語言進程協作。
#!/usr/bin/perl
use strict; use warnings;
use IPC::SysV qw(IPC_PRIVATE S_IRWXU IPC_CREAT IPC_NOWAIT);
use IPC::Msg;
my $key = IPC::SysV::ftok(".", '1'); # 需存在的檔案產生 key
my $msg = IPC::Msg->new($key, 0666 | IPC_CREAT) or die "create: $!";
my $msgid = $msg->id;
print "MSG_ID: $msgid\n";
$msg->snd(1, "test", IPC_NOWAIT) or die "send: $!";
$msg->rcv(my $buf, 1024) or die "recv: $!";
print "BUFFER: $buf\n";
$msg->remove(); # 刪除隊列
msg_snd.pl
my $msg = IPC::Msg->new($key, 0666 | IPC_CREAT);
my $msgtype = 1;
foreach my $pal (qw(Tom Dick Harry Pete Hank)) {
$msg->snd($msgtype, "Hi, $pal", IPC_NOWAIT) or die "send: $!";
print "SENT: $pal\n";
}
$msg->snd($msgtype, "end", IPC_NOWAIT); # 結束信號
msg_rcv.pl
my $msg = IPC::Msg->new($key, 0666 | IPC_CREAT);
my $running = 1;
while ($running) {
$msg->rcv(my $buf, 1024) or die "recv: $!";
print "RECV: $buf\n";
$running = 0 if $buf eq "end";
}
$msg->remove();
關鍵:雙方使用相同的 key (此處固定為 1234),消息結構體定義一致。
my $key = 1234; # 不再用 ftok
my $msg = IPC::Msg->new($key, 0666 | IPC_CREAT);
# ... 同前 ...
msg_snd.c
#include
#include
#include
#include
#include
#define MAX_TEXT 512
struct my_msg_st {
long int my_msg_type; // 必須為 long,且 > 0
char some_text[MAX_TEXT];
};
int main() {
int msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) { perror("msgget"); exit(1); }
struct my_msg_st data;
for (int i = 0; i < 10; i++) {
data.my_msg_type = 1;
snprintf(data.some_text, MAX_TEXT, "index~%d", i);
if (msgsnd(msgid, &data, MAX_TEXT, 0) == -1) { perror("msgsnd"); exit(1); }
}
// 發送結束信號
data.my_msg_type = 1;
strcpy(data.some_text, "end");
msgsnd(msgid, &data, MAX_TEXT, 0);
return 0;
}
gcc -o msg_snd msg_snd.c
./msg_rcv.pl & # 後台運行接收端
./msg_snd # 運行發送端
MSG_ID: 393219 BUFFER: index~0 BUFFER: index~1 ... BUFFER: index~9 BUFFER: end
| 項目 | 要求 |
|---|---|
| 消息類型 | long 且 > 0 (Perl/C 一致) |
| 資料長度 | msgsnd 第三參數為資料長度 (不含 long type),雙方約定一致 |
| key 產生 | C 用 ftok 或固定整數;Perl 用 IPC::SysV::ftok 或相同整數 |
| 權限 | 0666 | IPC_CREAT 雙方一致 |
| 隊列清理 | 接收端最後呼叫 $msg->remove() 或 C 端 msgctl(msgid, IPC_RMID, NULL) |