共享内存中的链表

Linked list inside 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 循环中,以及我试图将结构插入共享内存段的方式,但这就是我要问的你的。帮助我为此建立更好的逻辑。欢迎所有建议。

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

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

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

基本观察:

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

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

您的作业如下:

(*dlist).polname = aaron.polname;

至少有四项是伪造的。首先,aaron.polname 是该进程的每个进程(非共享)内存中的指针。所以指针赋值给了其他进程一个伪造的地址来使用。它指向其他进程地址 space 中的某个随机位置——或者,如果你幸运的话,指向它们地址 space 之外的某个位置,因此它们崩溃得很快而不是很慢。

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

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

第四,你应该使用dlist->polname表示法。是的,你所拥有的是有效的;它不能很好地工作。 dlist->next->next(*(*dlist).next).next更容易查(写,想)。 (如果不逐步进行,我什至无法写出它。而且我并不是说在这种情况下这是一个很好的表达方式;我只是指出使用箭头 ptr->member 链式访问要容易得多符号比星点 (*ptr).member.)

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

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

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

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

这为一组指针创建了足够的 space,但没有为指向的指针创建 space。您似乎还想创建一个 linked 列表,但您只为单个元素分配了足够的 space。这必须返工。共享内存必须足够大以包含所有共享数据——结构和结构指向的字符串。

因此,您需要:

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