mq_open() - 打开的文件太多了

时间:2014-02-27 21:57:40

标签: c linux posix message-queue

我正在尝试编写一个客户端和服务器,它将使用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);

...

你能帮我弄清问题是什么吗?提前谢谢..

5 个答案:

答案 0 :(得分: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用于创建新消息队列的空间不足。这可能是因为queues_max限制是遇到;请参阅mq_overview(7)*)您还需要以同样的方式检查fs.mqueue.queues_max

的值
/proc/sys/fs/mqueue/queues_max

获取当前值和

sysctl fs.mqueue.queues_max = new_value

改变它。

答案 1 :(得分:2)

本周我遇到了这个问题 - 我最多只能打开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 :(得分:1)

您可能在这里遇到了许多限制。

假设您使用的是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删除队列,否则它们将在两次运行之间保持不变。

答案 3 :(得分:0)

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

// 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
}

答案 4 :(得分:0)

您可以尝试关注

    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));