消息队列(msgget - msgsnd - msgrcv)Linux - EIDRM

时间:2018-03-30 08:24:37

标签: c ipc message-queue shared-memory

这是我的问题: 我试图在服务器和客户端之间实现消息队列。 为此,我有两个文件msq-server.cmsq-client.c

我使用函数msgctl(msqid, IPC_RMID, &buf)退出服务器(当我们要求他读取消息队列3次,每秒一次时,它会这样做)。

像往常一样,msqid由msgget函数设置,buf由struct msqid_ds buf定义。

官方的msgctl文档说errno被设置为读者(客户端)的EIDRM(43),并且我想在它发生时显示自定义错误。但是当我尝试从已关闭的服务器读取消息时,该功能 msgrcv(msqid, &message, 64, 0, IPC_NOWAIT)返回EINVAL错误。我认为msqid是有罪的

对于函数msgget

  • 在服务器上:我使用IPC_CREAT | IPC_EXCL |0666标志
  • 在客户端上:我使用IPC_EXCL | 0666标志

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

当您在通过msgctl()删除队列时读取消息队列时,msgrcv()将返回EIDRM(43)。

当您尝试从不再存在的消息队列中读取时,msgrcv()将返回EINVAL(22)(因为您已将其删除)。

请参阅下面的示例。

启动服务器并将一条消息放入队列。然后等待。

启动客户端并读取第一条消息,然后阻塞等待从未到达的第二条消息。

服务器在客户端等待第二条消息时删除队列,并看到EIDRM返回码。

然后客户端再次尝试读取,因为没有可用的队列,所以可以看到EINVAL。

msg_server.c

#include <sys/msg.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct msgbuf {
   long mType;
   char mText[50];
};

int main() {
   char txtBuf[50];
   int qId;
   key_t key;
   struct msgbuf msg, buf;
   struct msqid_ds msgCtlBuf;

   if ( ( key = ftok( "/tmp", 'C' ) ) == -1 ) {
      perror( "server: ftok failed:" );
      exit( 1 );
   }

   printf( "server: System V IPC key = %u\n", key );

   if ( ( qId = msgget( key, IPC_CREAT | 0666 ) ) == -1 ) {
      perror( "server: Failed to create message queue:" );
      exit( 2 );
   }

   printf( "server: Message queue id = %u\n", qId );

   strcpy( msg.mText, "This is a message" );
   msg.mType = 1;

   if ( msgsnd( qId, &msg, sizeof msg.mText, 0 ) == -1 ) {
      perror( "server: msgsnd failed:" );
      exit( 3 );
   }

   printf( "server: Message sent successfully\n" );

   printf( "server: waiting..." );
   sleep( 15 );
   printf( "server: done waiting. removing message queue...\n" );

   if ( msgctl( qId, IPC_RMID, &msgCtlBuf ) == -1 ) {
      perror( "server: msgctl failed:" );
      exit( 4 );
   }

   printf( "server: Message queue removed OK\n" );
}

msg_client.c

#include <sys/msg.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

struct msgbuf {
   long mType;
   char mText[50];
};

int main() {
   char txtBuf[50];
   int qId;
   key_t key;
   struct msgbuf msg, buf;
   struct msqid_ds msgCtlBuf;

   if ( ( key = ftok( "/tmp", 'C' ) ) == -1 ) {
      perror( "client: ftok failed:" );
      exit( 1 );
   }

   printf( "client: System V IPC key = %u\n", key );

   if ( ( qId = msgget( key, IPC_CREAT | 0666 ) ) == -1 ) {
      perror( "client: Failed to create message queue:" );
      exit( 2 );
   }

   printf( "client: Message queue id = %u\n", qId );

   if ( msgrcv( qId, &buf, sizeof msg.mText, 1, 0 ) == -1 )
      perror( "client: msgrcv failed:" );
   else
      printf( "client: Message received = %s\n", buf.mText );

   //
   // attempt read again and block on queue waiting for server to IPC_RMID
   //
   if ( msgrcv( qId, &buf, sizeof msg.mText, 1, 0 ) == -1 )
      perror( "client: msgrcv failed:" );
   else
      printf( "client: Message received = %s\n", buf.mText );

   printf( "client: errno = %d\n", errno );

   //
   // attempt read again but message queue should now be gone
   //
   if ( msgrcv( qId, &buf, sizeof msg.mText, 1, 0 ) == -1 )
      perror( "client: msgrcv failed:" );
   else
      printf( "client: Message received = %s\n", buf.mText );

   printf( "client: errno = %d\n", errno );
}

./ msg_server&amp;

[1] 668

服务器:System V IPC key = 1124335618

服务器:消息队列标识= 262144

服务器:邮件已成功发送

./ msg_client

客户:System V IPC key = 1124335618

客户端:消息队列标识= 262144

客户端:收到消息=这是一条消息

服务器:等待...服务器:完成等待。删除邮件队列...

服务器:删除消息队列确定

客户端:msgrcv失败::已删除标识符

客户:errno = 43

客户端:msgrcv失败::参数无效

客户:errno = 22

[1] +退出33 ./msg_server