如何从消息队列接收动态长度数据? [英] How to receive dynamic length data from a message queue?

查看:257
本文介绍了如何从消息队列接收动态长度数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须使用大学项目的SysV消息队列发送和接收动态数据。

I have to send and receive dynamic data using a SysV message queue for a university project.

数据的长度以单独的消息 size 是已知的。

The length of the data is transmitted in a separate message, size is therefor already known.

这是我如何尝试接收数据。我必须承认我不是C ++专家,特别是在内存分配方面。

And this is how I try to receive the data. I have to admit that I'm not a C++ specialist, especially when it comes to memory allocation.

struct {
    long mtype;
    char *mdata;
} msg;

msg.mdata = (char *)malloc(size * sizeof(char));

msgrcv(MSGQ_ID, &msg, size, MSG_ID, 0);

问题似乎是 malloc ,但我不知道该如何做。

The problem seems to be the malloc call, but I don't know how to do this right.

EDIT

我试着在邮件队列周围的一个OO包装中有一个 read 方法。我想读取消息队列中的数据到 char [] std :: string 。我现在看起来(简化)像这样。

What I try is to have a some sort of read method in a OO wrapper around the message queues. I'd like to read the data in the message queue into a char[] or a std::string. What I have now looks (simplified) like this.

bool Wrapper::read(char *data, int length)
{
    struct Message {
        long mtype;
        std::string mdata;
    };

    Message msg;
    msg.mdata = std::string(size, '\0');

    if(msgrcv(MSGQ_ID, &msg, size, MSG_ID, 0) < 0)
    {
        return false;
    }

    memcpy(data, msg.mdata.c_str(), msg.mdata.size());

    return true;
}



所有我得到的是分段错误或完全损坏的数据

All I get is segmentation faults or completely corrupt data (although this data sometimes contains what I want).

推荐答案

不能将指针传递给包含 std :: string 成员到 msgrcv ,这违反了接口契约。

You can't pass a pointer to a structure that contains a std::string member to msgrcv, this violates the interface contract.

传递给 msgrcv 的参数需要指向一个具有足够空间的缓冲区,以存储 struct {long mtype; char mdata [size]; }; 其中size是 msgrcv 的第三个参数。

The second parameter passed to msgrcv needs to point to a buffer with sufficient space to store a 'plain' C struct of the form struct { long mtype; char mdata[size]; }; where size is the third parameter to msgrcv.

这个缓冲区的大小可能取决于 size ,因为可能的对齐问题,但是你必须假定它不在提供这种接口的系统上。您可以使用标准的 offsetof 宏来帮助确定此大小。

Unfortunately, determining the size of this buffer might depend on size due to possible alignment issues but you have to assume that it doesn't on a system that provides this sort of interface. You can use the standard offsetof macro to help determine this size.

作为 连续存储其组件,一旦知道缓冲区的大小,就可以调整 char 向量 c $ c>并使用它来保存缓冲区。使用向量可以免除您免费 delete [] 手动。

As a vector stores its components contiguously, once you know the size of the buffer, you can resize a vector of char and use this to hold the buffer. Using a vector relieves you of the obligation to free or delete[] a buffer manually.

您需要这样做。

std::string RecvMessage()
{
    extern size_t size; // maximum size, should be a parameter??
    extern int MSGQ_ID; // message queue id, should be a parameter??
    extern long MSG_ID; // message type, should be a parameter??

    // ugly struct hack required by msgrcv
    struct RawMessage {
        long mtype;
        char mdata[1];
    };

    size_t data_offset = offsetof(RawMessage, mdata);

    // Allocate a buffer of the correct size for message
    std::vector<char> msgbuf(size + data_offset);

    ssize_t bytes_read;

    // Read raw message
    if((bytes_read = msgrcv(MSGQ_ID, &msgbuf[0], size, MSG_ID, 0)) < 0)
    {
        throw MsgRecvFailedException();
    }

    // a string encapsulates the data and the size, why not just return one
    return std::string(msgbuf.begin() + data_offset, msgbuf.begin() + data_offset + bytes_read);
}

换句话说,你只需将数据打包到 struct hack兼容数据数组,如msgsnd接口所需。因为其他人有指针,它不是一个好的界面,但掩盖了实现定义的行为和对齐的关注,这样的东西应该工作。

To go the other way, you just have to pack the data into a struct hack compatible data array as required by the msgsnd interface. As others have pointer out, it's not a good interface, but glossing over the implementation defined behaviour and alignment concerns, something like this should work.

例如

void SendMessage(const std::string& data)
{
    extern int MSGQ_ID; // message queue id, should be a parameter??
    extern long MSG_ID; // message type, should be a parameter??

    // ugly struct hack required by msgsnd
    struct RawMessage {
        long mtype;
        char mdata[1];
    };

    size_t data_offset = offsetof(RawMessage, mdata);

    // Allocate a buffer of the required size for message
    std::vector<char> msgbuf(data.size() + data_offset);

    long mtype = MSG_ID;
    const char* mtypeptr = reinterpret_cast<char*>(&mtype);

    std::copy(mtypeptr, mtypeptr + sizeof mtype, &msgbuf[0]);
    std::copy(data.begin(), data.end(), &msgbuf[data_offset]);

    int result = msgsnd(MSGQ_ID, &msgbuf[0], msgbuf.size(), 0);
    if (result != 0)
    {
        throw MsgSendFailedException();
    }
}

这篇关于如何从消息队列接收动态长度数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆