【问题标题】:mq_open() - too many open filesmq_open() - 打开的文件太多
【发布时间】:2014-03-31 15:24:16
【问题描述】:

我正在尝试编写一个客户端和服务器,它们将使用 POSIX 消息队列交换数据。我尝试通过查看我在互联网上看到的示例和课程文档来做到这一点。但是,我被困住了。当我运行它时,我得到“打开的文件太多”错误。这是我的代码:

客户:

int main( int argc, char *argv[]) {

    //Open its queue, which is client queue
    char cq_name[10];
    sprintf( cq_name, "/cq%i", getpid());
    printf( "Client Queue name: %s\n", cq_name);

    mqd_t cq_id = mq_open( cq_name, O_CREAT | O_RDWR, 0666, NULL);
    if( cq_id == -1) {

            printf( "Error in cq: %s\n", strerror( errno));
            return -1;
    }

    printf( "Name: %s\n", argv[1]);

    //Connect to the server message queue
    mqd_t sq_id = mq_open( argv[1], O_RDWR);

    if( sq_id == -1) {

            printf( "Error in sq: %s\n", strerror( errno));
            return -1;
    }

...

服务器:

int main( int argc, char *argv[]) {

    //The server message queue
    struct mq_attr attr;
    attr.mq_flags = 0;
    attr.mq_curmsgs = 0;

    printf( "Name: %s\n", argv[1]);

    mqd_t id = mq_open( argv[1], O_CREAT | O_RDWR, 0666, NULL);

    //Check the message queue
    if( id == -1) {

            printf( "Error: %s\n", strerror(errno));
    }

    printf( "Check Point 1 - %i\n", id);

...

你能帮我找出问题所在吗?提前谢谢..

【问题讨论】:

  • 我的回答能回答你的问题吗?

标签: c linux posix message-queue


【解决方案1】:

我这周遇到了这个问题 - 我最多只能打开 10 个 mqs。

我的意图是使用 mqs 将事件通知传递给线程。在我的情况下,event_id 只是一个 int。通过在对 mq_open 的调用中指定非默认属性,如下所示:

char mq_name[128];
sprintf(mq_name, "%s.%d", MQ_NAME, nnid);

struct mq_attr attrib;
attrib.mq_flags = 0;
attrib.mq_maxmsg = 4;
attrib.mq_msgsize = sizeof(int);
attrib.mq_curmsgs = 0;

retval = mq = mq_open(mq_name, O_RDWR | O_CREAT | O_EXCL, 0644, &attrib);

我现在可以在 mq_open() 失败之前打开多达 256 个 mq。

【讨论】:

    【解决方案2】:

    通常,打开文件过多意味着您在尝试打开文件描述符时已经打开了系统允许的最大文件数。

    cat /proc/sys/fs/file-max
    

    显示系统允许的最大文件描述符数。您可以尝试通过以下方式为当前正在运行的会话增加此值:

    sysctl fs.file-max = new_value
    

    或通过添加以下行来永久编辑/etc/sysctl.conf:

    fs.file-max = new_value
    

    为了确保这个限制是你可以达到的限制

    cat /proc/sys/fs/file-nr
    

    第三列nnumber与file-max报告的相同。第一列是分配的文件句柄数,第二列是未使用但已分配的文件句柄数。如果用第二个数字减去第一个数字得到第三个数字(或接近第三个数字),那么您就达到了极限。

    正如@nos 在评论中所建议的那样,在手册页指定的mq_open 的精确情况下(*ENOSPC Insufficient space for the creation of a new message queue。这可能是因为遇到了 queues_max 限制;请参阅 mq_overview(7)*) 您还需要以相同的方式检查 fs.mqueue.queues_max 的值

    /proc/sys/fs/mqueue/queues_max
    

    获取当前值和

    sysctl fs.mqueue.queues_max = new_value
    

    改变它。

    【讨论】:

    • 你也需要fs.mqueue.queues_max,它比 fs.file-max 低很多。下一个问题可能是文件描述符的每个进程限制(查看ulimit -n)
    • 读者收到消息后,消息是否为空?
    • 消息根本无法发送,因为 ms_send 函数需要 mq_open 返回的 mqd 失败
    【解决方案3】:

    您可能会遇到许多限制。

    假设您使用的是 Linux:

    由于您将 NULL 作为最后一个参数传递给 mq_open,因此您将获得默认的消息数量和每个队列的最大消息大小。这些是从

    /proc/sys/fs/mqueue/msg_default 和

    /proc/sys/fs/mqueue/msgsize_default
    

    您可以使用

    查看这些限制

    cat /proc/sys/fs/mqueue/msg_default

    并用

    更改它们

    sudo echo myNewLimit > /proc/sys/fs/mqueue/msg_default

    系统上可以创建的消息队列的总数也有限制。这存储在/proc/sys/fs/mqueue/queues_max 这些和其他限制的文档位于MQ_OVERVIEW(7)

    您的进程可以分配给消息队列的内存量也有限制。每个消息队列的内存至少为 (Num_Messages * Message_Length + 簿记开销)。此处提供了此限制的详细说明 GETRLIMIT(2)

    我建议编写一个小型测试程序来创建多个消息队列来试验这些限制。还记得在开始使用之前检查队列是否存在

    ls -l /dev/mqueue/ 
    

    还要记得在程序结束时使用mq_unlink 删除队列,否则它们会在运行之间持续存在。

    【讨论】:

      【解决方案4】:

      每次处理完客户端请求并发送响应后,您都需要在服务器代码中关闭客户端。像这样的东西。

      // close the client
      if (mq_close (qd_client) == -1) {
              perror ("Client: mq_close");
              exit (1);
      }
      

      这是一个完整的工作服务器示例。

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <sys/types.h>
      
      #include <fcntl.h>
      #include <sys/stat.h>
      #include <mqueue.h>
      
      #define SERVER_QUEUE_NAME   "/sp-example-server"
      #define QUEUE_PERMISSIONS 0666
      #define MAX_MESSAGES 10
      #define MAX_MSG_SIZE 8000
      #define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10
      
      int main (int argc, char **argv)
      {
          mqd_t qd_server, qd_client;   // queue descriptors
          long token_number = 1; // next token to be given to client
      
          struct mq_attr attr;
      
          attr.mq_flags = O_RDWR | O_CREAT;
          attr.mq_maxmsg = MAX_MESSAGES;
          attr.mq_msgsize = MAX_MSG_SIZE;
          attr.mq_curmsgs = 0;
      
          if ((qd_server = mq_open (SERVER_QUEUE_NAME, O_RDWR | O_CREAT, QUEUE_PERMISSIONS, &attr)) == -1) {
              perror ("Server: mq_open (server)");
              exit (1);
          }
      
          char in_buffer [MSG_BUFFER_SIZE];
          char out_buffer [MSG_BUFFER_SIZE];
      
          while (1) {     // while 1 starts
              // get the oldest message with highest priority
              if (mq_receive (qd_server, in_buffer, MSG_BUFFER_SIZE, NULL) == -1) {
              perror ("Server: mq_receive");
                  exit (1);
              }
                  // output message from client
              int iter001;
      
              printf("Message received from Client is following: \n");
              for (iter001 = 0; iter001 < MSG_BUFFER_SIZE; iter001++)
              {
                      printf("%c", in_buffer[iter001]);
              }
              printf("\n");
      
              printf ("Server: message received.\n");
      
              // send reply message to client
      
              if ((qd_client = mq_open (in_buffer, O_RDWR | O_CREAT)) == 1) {
              perror ("Server: Not able to open client queue");
              continue;
              }
              printf("Value of qd_client: \n");
              printf("%d\n", qd_client);
              sprintf (out_buffer, "%s", "hello world!");
      
              printf("Value of out_buffer: %s", out_buffer);
              if (mq_send (qd_client, out_buffer, strlen (out_buffer), 0) == -1) {
              perror ("Server: Not able to send message to client");
              continue;
              }
      
              printf ("Server: response sent to client.\n");
              token_number++;
      
              // close the client
              if (mq_close (qd_client) == -1) {
              perror ("Client: mq_close");
              exit (1);
              }
      
          }   // while 1 ends
      }
      

      【讨论】:

        【解决方案5】:

        您可以尝试关注

            struct rlimit r;
            r.rlim_cur = 99999999;
            r.rlim_max = 99999999;
            if (setrlimit(RLIMIT_MSGQUEUE, &r) == 0)
            {
                printf("set RLIMIT: %d\n", r.rlim_cur);
            }
            else printf("failed to set RLIMIT", strerror(errno));
        

        【讨论】:

          猜你喜欢
          • 2013-10-15
          • 1970-01-01
          • 2012-05-09
          • 2011-07-18
          • 2019-10-30
          • 2011-01-03
          • 2011-08-05
          • 2017-03-03
          相关资源
          最近更新 更多