You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言消息队列进程通信问题:Analyzer无法完整打印文件名

消息队列进程通信:文件名无法完整接收打印的问题排查

问题背景

用C语言实现基于System V消息队列的进程通信程序,包含Scanner和Analyzer两个子进程:

  • Scanner进程扫描指定目录,将普通文件名发送给Analyzer
  • Analyzer进程接收文件名并打印,但实际输出中文件名被截断,无法完整显示

原始代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <dirent.h>

#define MAX_DIM 2048

typedef struct
{
    char eof;
    long mtype; // 0 Analyzer 
    long count;
    char mtext[MAX_DIM];
} msg;

void child_scanner(const char *directory, int coda)
{

    DIR *dp;
    struct dirent *entry;
    msg messaggio;          // struct dove salvare le informazioni
    struct stat statBuffer; // buffer su dove scrivere le informazioni

    // apro la directory
    if ((dp = opendir(directory)) == NULL)
    {
        perror(directory);
        exit(1);
    }

    // cambia la directory corrente
    if (chdir(directory) == -1)
    {
        perror(directory);
        exit(1);
    }

    while ((entry = readdir(dp)) != NULL)
    {
        // prendo le informazioni
        lstat(entry->d_name, &statBuffer);
        if (S_ISREG(statBuffer.st_mode))
        {
            strcpy(messaggio.mtext, entry->d_name);
            messaggio.mtype = 0;   
            messaggio.eof = 0;
            messaggio.count = 0;
            if (msgsnd(coda, &messaggio, sizeof(char) + strlen(messaggio.mtext) + 1, 0) == -1)
            {
                perror("msgsnd");
                exit(1);
            }
            printf("Scanner: %s\n", messaggio.mtext); // stampa il nome del file
        }
    }

    strcpy(messaggio.mtext, "quit\n");
    messaggio.eof = 1;
    messaggio.mtype = 0;
    messaggio.count=0;
    if (msgsnd(coda, &messaggio, sizeof(char) + strlen(messaggio.mtext) + 1, 0) == -1)
    {
        perror("msgsnd");
        exit(1);
    }

    closedir(dp);
    exit(0);
}

void child_analyzer(int coda)
{
    printf("\n");
    msg messaggio;

    do
    {
        if (msgrcv(coda, &messaggio, sizeof(messaggio) - sizeof(long), 0, 0) == -1)
        {
            perror("msgrcv");
            exit(1);
        }

        printf("Analyzer: %s\n", messaggio.mtext);

    } while (messaggio.eof != 1);

    exit(0);
}

int main(int argc, char const *argv[])
{
    int ds_coda;            // coda
    struct stat statBuffer; // buffer di tipo struct stat su cui scrivere le informazioni

    if (argc > 2)
    {
        fprintf(stderr, "uso: %s <directory>\n", argv[0]);
        exit(1);
    }

    if ((ds_coda = msgget(IPC_PRIVATE, IPC_CREAT | 0600)) == -1)
    {
        perror("coda msgget");
        exit(1);
    }

    if (((stat(argv[1], &statBuffer)) == -1 || (!S_ISDIR(statBuffer.st_mode))))
    {
        fprintf(stderr, "Problema con parametro: '%s'\n", argv[1]);
        exit(1);
    }

    if (fork() == 0)
    {
        // Figlio Scanner
        child_scanner(argv[1], ds_coda);
    }
    else if (fork() == 0)
    {
        sleep(1);
        child_analyzer(ds_coda);
    }
    
    wait(NULL);
    wait(NULL);

    msgctl(ds_coda, IPC_RMID, NULL);

    return 0;
}

输入命令

./alpha-usage /Users/valentinofabrisvalenti/Desktop/Sistemi\ Operativi\ \(Laboratorio\)/Esami/Code/12-02-2016

实际输出

Scanner: palindrome-filter.c
Scanner: dictionary.txt
Scanner: palindrome-filter
Scanner: compito_2016-02-12 (1).pdf

Analyzer: palin
Analyzer: palin
Analyzer: palin
Analyzer: compito_2016
Analyzer: compito_2016

问题原因分析

1. 消息结构体违反System V消息队列规范

System V消息队列要求消息结构体的第一个成员必须是long类型的mtype,内核通过该字段识别消息类型。你的结构体把eof放在mtype前面,导致内核解析时:

  • 错误将eof及后续字节当作mtype值
  • 消息的eof、count、mtext字段全部错位,接收时无法正确映射到结构体成员

2. 消息长度参数不匹配

  • 发送端(msgsnd):传入的长度sizeof(char) + strlen(messaggio.mtext) + 1仅包含部分数据,未覆盖eof和count字段,不符合消息队列对“mtype之后所有数据长度”的要求
  • 接收端(msgrcv):传入的长度sizeof(messaggio) - sizeof(long)基于“mtype是第一个成员”的错误假设计算,导致接收数据长度错误,截断了文件名

修复方案

步骤1:修正消息结构体顺序

将mtype移到结构体第一个位置:

typedef struct
{
    long mtype; // 必须是第一个成员,用于消息类型识别
    char eof;
    long count;
    char mtext[MAX_DIM];
} msg;

步骤2:统一消息长度参数

发送和接收时,使用sizeof(msg) - sizeof(long)作为消息长度(即mtype之后所有数据的字节数):

  • 修正Scanner中的msgsnd调用(两处都要改):
// 替换原来的msgsnd长度参数
if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long), 0) == -1)
  • Analyzer中的msgrcv参数保持sizeof(msg) - sizeof(long)即可(现在计算正确)

步骤3:移除冗余的sleep

Analyzer进程中的sleep(1)是不必要的,消息队列本身会同步进程间的收发操作,移除后可避免不必要的延迟。

修复后预期输出

Scanner: palindrome-filter.c
Scanner: dictionary.txt
Scanner: palindrome-filter
Scanner: compito_2016-02-12 (1).pdf

Analyzer: palindrome-filter.c
Analyzer: dictionary.txt
Analyzer: palindrome-filter
Analyzer: compito_2016-02-12 (1).pdf
Analyzer: quit

内容的提问来源于stack exchange,提问作者Valentino Fabris Valenti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 05:01:35