共享内存中的链接列表

时间:2017-12-21 05:46:58

标签: c struct linked-list shared-memory

我正在尝试将其各自节点的结构推送到共享内存中,其中另一个程序将读取节点内容以进行一些验证(只是读取,不进行修改)。链表的每个节点都包含几个变量,以及许多节点

我的结构:

typedef struct DNode {
    char *polname;
    char *devname;
    char *status;
    char *srczone;
    char *dstzone;
    char *srcaddr;
    char *dstaddr;
    char *srcuser;
    char *app;
    char *service;
    char *urlcategory;
    char *action;
    char *vulnerability;
    int isok;
    struct DNode *next;
} Current;
struct DNode *head = NULL;

int list_insert_front(struct DNode* new_node) {
    struct DNode *temp;
    temp = malloc(sizeof *temp);
    if (temp && new_node) {
        memcpy(temp, new_node, sizeof(struct DNode));
        temp->next = head;
        head = temp;
        return 1;
    }
    return 0;
}

此结构使用函数list_insert_front从XML文件中获取数据并填充列表。此链接列表现在存储在共享内存中,以便更快地处理和轻松读取其他程序。

但是,我无法这样做(因为指针错误)。我能够向客户端发送一个易于读取的整数数据,但是当我对列表进行相同的尝试时,会发生BAM Segmentation fault

MAIN.C

int main(int argc, char **argv)
{
    Current aaron;
    Current *dlist;
    int key = 5555;
    int shmid;
    xmlDocPtr doc;
    xmlNode *root_element = NULL;
    dlist = &aaron;

    if (argc != 2)
    {
        printf("\nInvalid argument\n");
        return(1);
    }

    doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
    if (doc == NULL)
    {
        fprintf(stderr, "Document not parsed successfully.\n");
        return 0;
    }

    root_element = xmlDocGetRootElement(doc);

    if (root_element == NULL)
    {
        fprintf(stderr, "empty document\n");
        xmlFreeDoc(doc);
        return 0;
    }

    printf("Root Node is %s\n", root_element->name);
    traverse_dom_trees(root_element);

    shmid = shmget(key, sizeof(aaron), IPC_CREAT | 0660);
    if (shmid < 0) exit (1);

    dlist = shmat(shmid, NULL, 0);
    if (dlist == (void *) (-1))
        exit(1);

    printf("dlist alloc\n");
    (*dlist).isok = 10;
    printf("dlist val: %d\n", (*dlist).isok);
    //This integer value is printed and read by the client, but not the linked list

    while (Current.next != NULL){
        (*dlist).polname = aaron.polname;
        (*dlist).devname = aaron.devname;
        (*dlist).status = aaron.status;
        (*dlist).srczone = aaron.srczone;
        (*dlist).dstzone = aaron.dstzone;
        (*dlist).srcaddr = aaron.srcaddr;
        (*dlist).dstaddr = aaron.dstaddr;
        (*dlist).srcuser = aaron.srcuser;
        (*dlist).app = aaron.app;
        (*dlist).service = aaron.service;
        (*dlist).urlcategory = aaron.urlcategory;
        (*dlist).action = aaron.action;
        (*dlist).vulnerability =  aaron.vulnerability;
        Current = Current.next;
    }
    printf("printing list: ");

    shmdt(dlist);
    xmlFreeDoc(doc);       
    xmlCleanupParser();    
    return 0;
}

我意识到我可能犯了很多愚蠢的错误,比如在while循环中,以及我尝试在共享内存段中插入结构的方式,但这就是我要求你们所有人。为了帮助我为此建立一个更好的逻辑。欢迎提出所有建议。

2 个答案:

答案 0 :(得分:3)

您不能在共享内存段中使用指针,因为它们仅在您的进程中有效。这可能是您获得段错误的原因。您可以在共享内存段中使用偏移量。

答案 1 :(得分:3)

你展示的并不是真正的MCVE。您在结构中有13个char *成员;对于MCVE来说,3将是充足的。您还使用XML解析函数,这些函数基本上与问题相关;你可以简化很多事情。

您不会显示将在共享内存中使用该列表的任何其他进程;拥有其中一个(它只需要附加到共享内存并遍历列表,打印结果)会很有帮助。

基本的obervation:

  • 如果您要将列表存储在共享内存中,则列表中的每个用户都需要能够查看数据,这些数据必须 all 位于共享内存中。

您明显无法确保所有数据都在共享内存中。

您的作业如:

(*dlist).polname = aaron.polname;

至少有四项伪造。首先,aaron.polname是此进程的每进程(非共享)内存中的指针。因此,指针赋值给其他进程提供了一个伪造的地址。它指向一些随机位置,因为其他进程会占用空间 - 或者,如果您幸运的话,可以指向地址空间之外的某个位置,这样它们就会快速崩溃而不是缓慢崩溃。

其次,你还没有复制字符串;你只是分配了一个指针。这是一个问题。

第三,您将共享内存中的所有指针指向相同的位置,以便多个条目指向相同的数据。

第四,您应该使用dlist->polname表示法。是的,你有什么工作;它不能很好地运作。检查(编写,想到)dlist->next->next(*(*dlist).next).next更容易。 (我甚至不能在没有逐渐增加的情况下写出来。而且我并没有声称在这种情况下这是一个很好的表达;我只是指出链接访问更容易使用箭头ptr->member符号而不是星点(*ptr).member。)

您必须确保共享结构中的指针指向共享内存。

您还必须确保所有进程在同一地址加载共享内存段。如果你不能这样做,那么你根本就不能可靠地使用指针;您必须使用基址(共享内存段的起始地址)的偏移量。链接指针也需要小心处理。

您没有创建足够大的共享内存块。您正在使用:

shmid = shmget(key, sizeof(aaron), IPC_CREAT | 0660);

为一组指针创建了足够的空间,但没有空间让指针指向。您似乎也想要创建链接列表,但您只需为单个元素分配足够的空间。这必须重做。共享内存必须足够大,以包含所有共享数据 - 结构和结构指向的字符串。

所以,你需要:

  1. 分配更多共享内存。
  2. 确保所有进程在同一地址加载共享内存。
  3. 确保共享内存中结构的所有数据引用都在共享内存中的内存位置。
  4. 将进程本地内存中的字符串复制到共享内存中。
  5. 确保在进程之间正确同步读/写访问权。
  6. 除非您希望成为新手程序员,否则请使用dlist->polname而不是(*dlist).polname