linux下基于Posix message queue的同步消息队列的实现



/* 发送同步消息队列 */
_api int crtl_msgq_sync_send(crtl_mqd_t dst_mqd, const char *m_ptr, const size_t m_len, 
                            void *ack, size_t *ack_len, int timeout_sec, long timeout_nanosec)
{
    /* 入参有误 */
    if(unlikely(!m_ptr) || unlikely(!m_len) || unlikely(!ack) || unlikely(!ack_len)) {
        crtl_print_err("wrong params error.\n");
        crtl_assert_fp(stderr, 0);
        return CRTL_ERROR;
    }
    
    /* 为同步消息队列申请内存 */
    struct __crtl_msgq_sync_msg_body _unused *__msgq_sync_msg = crtl_malloc1(1, sizeof(struct __crtl_msgq_sync_msg_body)+m_len);
    if(unlikely(!__msgq_sync_msg)) {
        /* 申请失败,退出 */
        crtl_print_err("null pointer error.\n");
        crtl_assert_fp(stderr, 0);
        return CRTL_ERROR;
    }

    int _unused ret = CRTL_ERROR;
    crtl_msgq_name_t __ack_snd_mq_name;
    
    /* 消息队列名称 */
    sprintf(__ack_snd_mq_name, "%s", __CRTL_MSGQ_NAME_GEN("TMP", "ACK"));

    __crtl_dbg("MSGQ: %s\n", __ack_snd_mq_name);

    /* 创建消息队列 -     非阻塞-需要提供超时机制 */
    __msgq_sync_msg->__ack_snd_mqd = crtl_mq_open_nonblk(__ack_snd_mq_name, 
                                                                     __CRTL_MSGQ_SYNC_TMP_MSGQ_MAXMSG, 
                                                                     __CRTL_MSGQ_SYNC_TMP_MSGQ_MAXMSGSIZE);
    if(__msgq_sync_msg->__ack_snd_mqd == CRTL_ERROR) {
        /* 创建消息队列失败,释放内存,并退出 */
        crtl_print_err("Create tmp msgq error.\n");
        sleep(1);
        crtl_mfree1(__msgq_sync_msg);
        crtl_assert_fp(stderr, 0);
        return CRTL_ERROR;
    }
    
    __crtl_dbg("OPEN: mqd %d, \n", __msgq_sync_msg->__ack_snd_mqd);

    /* 创建临时消息队列成功,拷贝需要发送的数据 */
    __msgq_sync_msg->msg_size = m_len;
    memcpy(__msgq_sync_msg->msg_body, m_ptr, m_len);

    __crtl_dbg("SEND: mqd %d, \n", dst_mqd);

    /* 发送消息队列 */
    int ready_to_send_len = sizeof(struct __crtl_msgq_sync_msg_body)+m_len;
    int send_size = crtl_mq_send(dst_mqd, (char*)__msgq_sync_msg, ready_to_send_len, 10, 0,0,0);
    if(send_size < ready_to_send_len) {
        /* 如果失败,清空消息队列,删除文件,退出 */
        crtl_print_err("send size not equal, need %d, but is %d, error(mqd %d).\n", ready_to_send_len, send_size, dst_mqd);
        crtl_assert_fp(stderr, 0);
        crtl_mq_close(__msgq_sync_msg->__ack_snd_mqd);
        crtl_mq_unlink(__ack_snd_mq_name);
        crtl_mfree1(__msgq_sync_msg);
        return CRTL_ERROR;
    }

    __crtl_dbg("SEND: mqd %d, send_size %d , ready_to_send_len %d\n", dst_mqd, send_size, ready_to_send_len);

    /* 从临时消息队列接收消息(等待消息接收端调用 crtl_msgq_sync_send_ack ) */
    char __buf[__CRTL_MSGQ_SYNC_TMP_MSGQ_MAXMSGSIZE] = {0};
    unsigned int m_prio;
    int recv_ack_size = crtl_mq_receive(__msgq_sync_msg->__ack_snd_mqd, 
                                        __buf, __CRTL_MSGQ_SYNC_TMP_MSGQ_MAXMSGSIZE, 
                                        &m_prio, 1, timeout_sec, timeout_nanosec);
    if(recv_ack_size <= 0) {
        /* 如果接收失败或者超时,关闭临时消息队列,清空临时消息队列文件,释放内存 */
        crtl_print_err("recv ack error: recv %d error.\n", recv_ack_size);
        crtl_assert_fp(stderr, 0);
        crtl_mq_close(__msgq_sync_msg->__ack_snd_mqd);
        crtl_mq_unlink(__ack_snd_mq_name);
        crtl_mfree1(__msgq_sync_msg);
        return CRTL_ERROR;
    }
    
    __crtl_dbg("RECV ACK: mqd %d, ack_len %d\n", __msgq_sync_msg->__ack_snd_mqd, recv_ack_size);

    /* 如果从临时消息队列接收消息成功,向ack赋值, */
    *ack_len = recv_ack_size;
    memcpy(ack, __buf, recv_ack_size);

    __crtl_dbg("RECV ACK: mqd %d, ack_len %d\n", __msgq_sync_msg->__ack_snd_mqd, recv_ack_size);

    /* 整体流程结束,释放资源 */
    __crtl_dbg("MSGQ Close: %s\n", __ack_snd_mq_name);
    crtl_mq_close(__msgq_sync_msg->__ack_snd_mqd);
    crtl_mq_unlink(__ack_snd_mq_name);
    crtl_mfree1(__msgq_sync_msg);
    
    return send_size-sizeof(struct __crtl_msgq_sync_msg_body);
}


/* 发送同步消息队列ack */
_api int crtl_msgq_sync_send_ack(const void *const src_sync_msg, const void *ack_msg, size_t ack_len)
{
    /* 入参有误 */
    if(unlikely(!src_sync_msg) || unlikely(!ack_msg) || unlikely(!ack_len)) {
        crtl_print_err("wrong params error.\n");
        crtl_assert_fp(stderr, 0);
        return CRTL_ERROR;
    }

    /* 解析同步消息中的msgq ID */
    struct __crtl_msgq_sync_msg_body *sync_msgq_msg = (struct __crtl_msgq_sync_msg_body *)src_sync_msg;
    crtl_mqd_t __tmp_mqd = sync_msgq_msg->__ack_snd_mqd;
    
    /* 向临时消息队列发送ACK消息 */
    int send_ack_size = crtl_mq_send(__tmp_mqd, (char*)ack_msg, ack_len, 0, 0,0,0);
    if(send_ack_size < ack_len) {
        crtl_print_err("send ack size not equal, need %d, but is %d, error.\n", ack_len, send_ack_size);
        crtl_assert_fp(stderr, 0);
        return CRTL_ERROR;
    }
    
    __crtl_dbg("MSGQ ACK SEND: mqd %d\n", __tmp_mqd);

    return send_ack_size;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值