尝试访问时带有结构的 C mq_receive() 会导致段错误

Posted

技术标签:

【中文标题】尝试访问时带有结构的 C mq_receive() 会导致段错误【英文标题】:C mq_receive() with struct causes seg fault when trying to access 【发布时间】:2020-07-16 06:10:16 【问题描述】:

所以我有两个连接到消息队列的程序,一个以结构的形式向另一个发送消息。但是,当我在收到该结构后尝试访问它时,会出现分段错误。

我不知道在结构发送后我需要做什么才能访问它。

这是我的发件人代码:

#include <stdio.h>
#include <mqueue.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

typedef struct 
  char path[2048];
  char shm_name[50];
  size_t shm_s;
  char sem_send_name[50];
    char sem_recv_name[50];
 cache_request;

static void showAttr(mqd_t fd)

    struct mq_attr attr;
    mq_getattr(fd, &attr);
    printf("maxmsg = %ld\n", attr.mq_maxmsg);
    printf("msgsize = %ld\n", attr.mq_msgsize);
    printf("curmsgs = %ld\n", attr.mq_curmsgs);


int main()

    mqd_t fd;
    int ret;

    struct mq_attr attr;
    int flags = O_RDWR | O_CREAT;
    attr.mq_flags = 0;
    attr.mq_maxmsg = 3;
    attr.mq_msgsize = 2216;
    attr.mq_curmsgs = 0;
    fd = mq_open("/mq", flags,(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH),&attr );
    if (fd < 0) 
        printf("open failed %d\n", fd);
        exit(EXIT_FAILURE);
    
    printf("open ok\n");
    sleep(1);
    showAttr(fd);
    cache_request* msg = (cache_request*)malloc(sizeof(cache_request));
    strcpy(msg->path,"ok\n");
    strcpy(msg->shm_name, "ex1\n");
    msg->shm_s = 250;
    strcpy(msg->sem_send_name," ex2");
    strcpy(msg->sem_recv_name, "ex3");
    printf("hmm %s\n", msg->shm_name);
    printf("hmm %ld\n", msg->shm_s);
    //res = mq_receive(fd, (char*) &msg, sizeof(cache_request), NULL);
    int res = mq_send(fd, (const char*) &msg, sizeof(cache_request), 0);
    if (res < 0) 
          printf ("   Error %d (%s) on server mq_send.\n",
              errno, strerror (errno));
          mq_close(fd);
          mq_unlink("/mq");
          exit (1);
      
    sleep(10);
    ret = mq_close(fd);
    if (ret != 0) 
        printf("open failed\n");
        exit(EXIT_FAILURE);
    
    printf("close ok\n");
    sleep(20);
    mq_unlink("/mq");
    return 0;


这是接收器:

#include <stdio.h>
#include <mqueue.h> // for message queue
#include <sys/stat.h>
#include <stdlib.h> // for EXIT_FAILURE
#include <string.h>
#include <errno.h>
#include <unistd.h>

/*
gcc [file] -lrt
*/

typedef struct 
  char path[2048];
  char shm_name[50];
  size_t shm_s;
  char sem_send_name[50];
    char sem_recv_name[50];
 cache_request;


static void showAttr(mqd_t fd)

    struct mq_attr attr;

    mq_getattr(fd, &attr);

    printf("maxmsg = %ld\n", attr.mq_maxmsg);
    printf("msgsize = %ld\n", attr.mq_msgsize);
    printf("curmsgs = %ld\n", attr.mq_curmsgs);



int main()

    mqd_t fd;
    int ret;




    mq_unlink("/mq");
    struct mq_attr attr;
    int flags = O_RDWR;
    attr.mq_flags = 0;
    attr.mq_maxmsg = 3; // ***
    attr.mq_msgsize = 141;
    attr.mq_curmsgs = 0;

    while((fd = mq_open("/mq", O_RDWR)) == -1)
      printf("Couldnt connect to message queue in cache\n");
      sleep(2);
    

    if (fd < 0) 
        printf("open failed %d\n", fd);
        exit(EXIT_FAILURE);
    
    printf("open ok\n");

    //sleep(5);

    showAttr(fd);
    char* rsp_msg = (char*)malloc(2216);
    int res = mq_receive(fd, (char*) &rsp_msg, 2216, NULL);
    printf("recieved: %d\n", res);
        printf("should be %ld\n", sizeof(cache_request));
    if (res < 0) 
          printf ("   Error %d (%s) on server mq_receive.\n",
              errno, strerror (errno));
          mq_close(fd);
          mq_unlink("/mq");
          exit (1);
      
    cache_request* msg = (cache_request*)rsp_msg;
    printf("shm_s: %ld\n", msg->shm_s); //THIS is where the seg fault happens
        printf("shm_name: %s\n", msg->shm_name);
    ret = mq_close(fd);
    if (ret != 0) 
        printf("close failed\n");
        exit(EXIT_FAILURE);
    
    printf("close ok\n");

    return 0;


【问题讨论】:

OT:关于:cache_request* msg = (cache_request*)malloc(sizeof(cache_request)); 1) 在 C 中,返回的类型是 void*,可以分配给任何指针。强制转换只会使代码混乱并且容易出错。 2) 始终检查 (!=NULL) 返回值以确保操作成功。如果不成功,请致电:perror( "malloc failed" ); exit( EXIT_FAILURE ); 关于:printf("open failed %d\n", fd); 1) 错误消息应该输出到stderr,而不是stdout 2) 当错误来自 C 库函数时,还应该输出错误发生的文本原因到stderr。函数:perror() 正确处理这两个动作 关于:while((fd = mq_open("/mq", O_RDWR)) == -1) printf("Couldnt connect to message queue in cache\n"); sleep(2); 1) 错误消息发给stderr,而不是stdout。 2)如果它失败了一次,它会继续失败,所以最好调用exit( EXIT_FAILURE );而不是循环 关于:int res = mq_receive(fd, (char*) &amp;rsp_msg, 2216, NULL); 这是为rsp_msg 传递“地址的地址”。强烈建议去掉rsp_msg参数前导的&amp;;注意:rsp_msg 已经是一个指针。 关于:attr.mq_msgsize = 141;int res = mq_receive(fd, (char*) &amp;rsp_msg, 2216, NULL); 最大消息大小仅为 141,但代码试图传递 2216 消息大小。建议最大消息大小为(至少)2216 【参考方案1】:
int res = mq_send(fd, (const char*) &msg, sizeof(cache_request), 0);

应该是msg,而不是&amp;msg。您要发送msg 指向的数据,而不是指针本身。

int res = mq_receive(fd, (char*) &rsp_msg, 2216, NULL);

同样。

另外,最好使用sizeof(cache_request) 而不是硬编码2216

【讨论】:

以上是关于尝试访问时带有结构的 C mq_receive() 会导致段错误的主要内容,如果未能解决你的问题,请参考以下文章

“错误:分配给带有数组类型错误的表达式”当我分配结构字段时(C)

C中的结构访问

mq_receive()

mq_receive 在 NASM 中给出“消息太长”错误

强制 GCC 访问带有单词的结构

带有 JNA 的 C 回调使 JRE 崩溃