linux消息队列

ftok()

#include <sys/types.h>

#include <sys/ipc.h>

函数原型:

        key_t  ftok( const  char * pathname , int   proj_id  );

参数:

       pathname 就时你指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽         然为int,但是只有8个比特被使用(0-255)。

返回值: 成功时候返回key_t 类型的key值,失败返回-1

 

msgget

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数原型: int    msgget ( key_t  key , int  msgflg );

函数描述:建立消息队列

参数:

       msgget()函数的第一个参数是消息队列对象的关键字(key),函数将它与已有的消息队
       列对象的关键字进行比较来判断消息队列对象是否已经创建。而函数进行的具体操作是  由第二个参数,msgflg 控制的。它可以取下面的几个值:
       IPC_CREAT :如果消息队列对象不存在,则创建之,否则则进行打开操作;
       IPC_EXCL:和IPC_CREAT 一起使用(用”|”连接),如果消息对象不存在则创建之,否     则产生一个错误并返回。

返回值:

       成功时返回队列ID,失败返回-1,错误原因存于error中

       EEXIST (Queue exists, cannot create)
       EIDRM (Queue is marked for deletion)
       ENOENT (Queue does not exist)
       ENOMEM (Not enough memory to create queue)
       ENOSPC (Maximum queue limit exceeded)

 

 

 

msgsnd函数:将消息送入消息队列

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h

函数原型:int  msgsnd ( int msgid ,  struct msgbuf*msgp , int msgsz, int msgflg );

参数说明:

       传给msgsnd()函数的第一个参数msqid 是消息队列对象的标识符(由msgget()函数得

       到),第二个参数msgp 指向要发送的消息所在的内存,第三个参数msgsz 是要发送信息     的长度(字节数),可以用以下的公式计算:
       msgsz = sizeof(struct mymsgbuf) - sizeof(long);
       第四个参数是控制函数行为的标志,可以取以下的值:
       0,忽略标志位;
       IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线
       程。如果不指定这个参数,线程将被阻塞直到消息被可以被写入。

       smgbuf结构体定义如下:

       struct smgbuf

       {

                     long   mtype;

                    char   mtext [x] ;  //长度由msgsz决定

       }

 

       msgflg 可设置为 IPC_NOWAIT 。如果消息队列已满或其他情况无法送入消息,则立即   返回 EAGIN

返回: 0 on success

       -1 on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted)
       EACCES (permission denied, no write permission)
       EFAULT (msgp address isn't accessable – invalid)
       EIDRM (The message queue has been removed)
       EINTR (Received a signal while waiting to write)
       EINVAL (Invalid message queue identifier, nonpositive
       message type, or invalid message size)
       ENOMEM (Not enough memory to copy message buffer)

 

msgrcv函数:从消息队列中读取消息

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数定义:int  msgrcv( int  msgid , struct   msgbuf*  msgp ,  int msgsz ,  long msgtyp, int msgflg);

参数:

       函数的前三个参数和msgsnd()函数中对应的参数的含义是相同的。第四个参数mtype

       指定了函数从队列中所取的消息的类型。函数将从队列中搜索类型与之匹配的消息并将  之返回。不过这里有一个例外。如果mtype 的值是零的话,函数将不做类型检查而自动返     回队列中的最旧的消息。第五个参数依然是是控制函数行为的标志,取值可以是:
       0,表示忽略;
       IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数
       的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件  的消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果     进程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
       MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,
       剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不     被取出。
       当消息从队列内取出后,相应的消息就从队列中删除了。

msgbuf:结构体,定义如下:

struct msgbuf

{

                      long  mtype ;  //信息种类

                       char   mtest[x];//信息内容   ,长度由msgsz指定

}

 

msgtyp:  信息类型。 取值如下:

 msgtyp = 0 ,不分类型,直接返回消息队列中的第一项

 msgtyp > 0 ,返回第一项 msgtyp与 msgbuf结构体中的mtype相同的信息

msgtyp <0 , 返回第一项 mtype小于等于msgtyp绝对值的信息

 

msgflg:取值如下:

IPC_NOWAIT ,不阻塞

IPC_NOERROR ,若信息长度超过参数msgsz,则截断信息而不报错。

 

 

返回值:

       成功时返回所获取信息的长度,失败返回-1,错误信息存于error

       Number of bytes copied into message buffer
       -1 on error: errno = E2BIG (Message length is greater than
       msgsz,no MSG_NOERROR)
       EACCES (No read permission)
       EFAULT (Address pointed to by msgp is invalid)
       EIDRM (Queue was removed during retrieval)
       EINTR (Interrupted by arriving signal)
       EINVAL (msgqid invalid, or msgsz less than 0)
       ENOMSG (IPC_NOWAIT asserted, and no message exists in the queue to satisfy the request)

 例子:

server.c

 

C代码

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/stat.h>

#include <sys/msg.h>

#define MSG_FILE "server.c"

#define BUFFER 255

#define PERM S_IRUSR|S_IWUSR

struct msgtype {

long mtype;

char buffer[BUFFER+1];

};

int main()

{

struct msgtype msg;

key_t key;

int msgid;

if((key=ftok(MSG_FILE,'a'))==-1)

{

fprintf(stderr,"Creat Key Error:%s\a\n",strerror(errno));

exit(1);

}

if((msgid=msgget(key,PERM|IPC_CREAT|IPC_EXCL))==-1)

{

fprintf(stderr,"Creat Message Error:%s\a\n",strerror(errno));

exit(1);

}

while(1)

{

msgrcv(msgid,&msg,sizeof(structmsgtype),1,0);

fprintf(stderr,"Server Receive:%s\n",msg.buffer);

msg.mtype=2;

msgsnd(msgid,&msg,sizeof(structmsgtype),0);

}

exit(0);

}

 client.c

C代码

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <sys/stat.h>

#define MSG_FILE "server.c"

#define BUFFER 255

#define PERM S_IRUSR|S_IWUSR

struct msgtype {

long mtype;

char buffer[BUFFER+1];

};

int main(int argc,char **argv)

{

struct msgtype msg;

key_t key;

int msgid;

if(argc!=2)

{

fprintf(stderr,"Usage:%sstring\n\a",argv[0]);

exit(1);

}

if((key=ftok(MSG_FILE,'a'))==-1)

{

fprintf(stderr,"Creat Key Error:%s\a\n",strerror(errno));

exit(1);

}

if((msgid=msgget(key,PERM))==-1)

{

fprintf(stderr,"Creat Message Error:%s\a\n",strerror(errno));

exit(1);

}

msg.mtype=1;

strncpy(msg.buffer,argv[1],BUFFER);

msgsnd(msgid,&msg,sizeof(structmsgtype),0);

memset(&msg,'\0',sizeof(structmsgtype));

msgrcv(msgid,&msg,sizeof(structmsgtype),2,0);

fprintf(stderr,"Client receive:%s\n",msg.buffer);

exit(0);

}

 

Linux系统中的消息队列是一种进程间通信(IPC)机制,允许不同进程之间通过发送和接收消息进行数据交换。它广泛应用于分布式系统、消息中间件等场景中,例如 RabbitMQ 和 Kafka。 ### 消息队列的基本使用 Linux 提供了 System V 消息队列和 POSIX 消息队列两种实现方式。System V 消息队列是较早的实现方式,使用 `msgget`、`msgsnd`、`msgrcv` 等系统调用来操作消息队列。以下是一个简单的使用示例: ```c #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <string.h> struct my_msg { long mtype; char mtext[200]; }; int main() { struct my_msg msg; int msqid; key_t key = ftok("msgqueue", 'B'); msqid = msgget(key, 0666 | IPC_CREAT); if (msqid == -1) { perror("msgget"); return 1; } while (1) { msgrcv(msqid, &msg, sizeof(msg.mtext), 0, 0); printf("Received: %s\n", msg.mtext); } return 0; } ``` 在上述代码中,首先使用 `msgget` 创建或获取一个消息队列标识符,然后使用 `msgrcv` 接收消息。发送端则使用 `msgsnd` 发送消息。 ### 消息队列的配置 Linux 提供了几个关键的配置参数用于控制消息队列的行为: - `/proc/sys/kernel/msgmax`:指定单个消息的最大长度,默认值为 8192 字节。 - `/proc/sys/kernel/msgmnb`:指定一个消息队列的最大字节数,默认值为 16384 字节。 - `/proc/sys/kernel/msgmni`:指定消息队列标识的最大数目,默认值为 16[^2]。 这些参数可以通过 `sysctl` 命令进行修改。例如,要修改 `msgmax` 的值,可以使用以下命令: ```bash sudo sysctl -w kernel.msgmax=16384 ``` 如果需要永久生效,可以将配置写入 `/etc/sysctl.conf` 文件中: ```bash echo "kernel.msgmax = 16384" | sudo tee -a /etc/sysctl.conf sudo sysctl -p ``` ### 消息队列的管理 在 Linux 中,可以使用 `ipcs` 命令查看当前系统中的消息队列信息: ```bash ipcs -q ``` 该命令会列出所有当前存在的消息队列,包括它们的标识符、权限、所有者等信息。 要删除一个消息队列,可以使用 `ipcrm` 命令。例如,要删除一个标识符为 `123456` 的消息队列,可以执行以下命令: ```bash ipcrm -q 123456 ``` ### 消息队列的应用 除了传统的 System V 消息队列,现代系统中还常用一些高级消息队列系统,如 RabbitMQ 和 Kafka。 RabbitMQ 是一个基于 AMQP 协议的企业级消息队列系统,适用于需要高可靠性和复杂路由规则的场景。安装 RabbitMQ 通常需要先安装 Erlang 环境,然后通过包管理工具安装 RabbitMQ 服务器并启动服务。 Kafka 是一种高吞吐量的分布式消息队列系统,适用于大数据实时处理场景。Kafka 的安装相对简单,下载解压后即可启动服务。以下是一个消费 Kafka 消息的示例命令: ```bash ./bin/kafka-console-consumer.sh --topic test-topic --from-beginning --bootstrap-server localhost:9092 ``` 该命令会从指定的主题中消费消息,并从头开始读取。 ### 消息队列的优势与适用场景 消息队列的优势在于能够解耦生产者和消费者,提高系统的可扩展性和可靠性。它适用于需要异步处理、流量削峰、日志收集等场景。例如,在电商系统中,订单服务可以将订单信息发送到消息队列,库存服务和物流服务则分别从队列中获取订单信息进行处理。 ### 消息队列的注意事项 在使用消息队列时,需要注意以下几点: 1. **消息丢失**:确保消息在传输过程中不会丢失,可以通过持久化、确认机制等方式实现。 2. **消息重复**:消费者在处理消息时可能会遇到重复的消息,需要保证幂等性。 3. **消息顺序**:某些场景下需要保证消息的顺序性,这需要消息队列系统支持。 4. **性能调优**:根据实际需求调整消息队列的配置,以获得最佳性能。 ### 总结 Linux 消息队列是一种强大的进程间通信机制,适用于多种应用场景。无论是传统的 System V 消息队列,还是现代的 RabbitMQ 和 Kafka,都提供了丰富的功能和灵活的配置选项。通过合理配置和使用消息队列,可以有效提升系统的可靠性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值