C Unix msgsnd 不发送一些消息

C Unix msgsnd not sending some messages

我用 c 编写了一个程序,它创建一个子进程来接收消息,父进程发送消息。它不会从其父进程接收消息,这是设计使然,也是我使用 MSG_EXCEPT 的原因。所以它打算有2个程序实例运行,它们可以发送和接收消息。问题是程序只发送一些消息,不是全部,我不知道为什么...

另外,我必须用gcc -D_GNU_SOURCE chat.c -o chat编译,否则会出现关于MSG_EXCEPT的错误。有谁知道在不使用这些编译器标志的情况下让 MSG_EXCEPT 工作的更好方法吗?代码中的东西会更可取,这样它就可以移植。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <time.h>
#include <signal.h>
#include <errno.h>

typedef struct messageBuffer {
    long type;
    char text[256];
} MsgBuf;

typedef struct MessageStruct {
    MsgBuf message;
    int success;
} Message;

void handler(int sig){
    _exit(0);
}

int open_queue( key_t keyval )
{
    int qid;
        
    if((qid = msgget( keyval, IPC_CREAT | 0666 )) == -1)
    {
        return(-1);
    }
        
    return qid;
}

void SendMessage(int qid, int msgtype, char* msgtxt)
{
    MsgBuf msg;
    time_t t;

    msg.type = msgtype;

    snprintf(msg.text, sizeof(msg.text), "%s", msgtxt);

    time(&t);

    if(msgsnd(qid, (void*)&msg, sizeof(msg.text), IPC_NOWAIT) == -1)
    {
        perror("msgsnd error");
        exit(EXIT_FAILURE);
    }
}

Message ReceiveMessage(int qid, int msgtype)
{
    Message msg;
    msg.success = 1;

    if(msgrcv(qid, (void*)&msg.message, sizeof(msg.message.text), msgtype, IPC_NOWAIT | MSG_NOERROR | MSG_EXCEPT) == -1)
    {
        if (errno != ENOMSG)
        {
            perror("msgrcv");
            exit(EXIT_FAILURE);
        }
        else
            msg.success = 0;
    }

    return msg;
}

void ClearCurrentConsoleLine()
{
    printf("\x1b[1F"); // Move to beginning of previous line
    printf("\x1b[2K"); // Clear entire line
}

int main(void)
{
    pid_t pid;
    pid_t ppid = getpid();
    int msgkey = 6666;
    char str[256];
    Message msg;
    char* writemsg = "Write your message below:\n";

    pid = fork();

    int qid = open_queue(msgkey);

    if(qid == -1)
    {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    if(pid < 0)
    {
        perror("Forking error!");
        abort();
    }
    else if(pid == 0)
    {
        signal(SIGCONT,handler);
        while(1)
        {
            msg = ReceiveMessage(qid, ppid);
            if(msg.success)
            {
                ClearCurrentConsoleLine();
                printf("message: %ld: %s\n", msg.message.type, msg.message.text);
                printf("%s", writemsg);
            }
        }
        exit(0);
    }

    while(1)
    {
        printf("%s", writemsg);
        fgets(str, sizeof(str), stdin);

        int n = strlen(str);
        if(str[n-1] == '\n')
            str[n-1] = '[=10=]';
        
        ClearCurrentConsoleLine();
        ClearCurrentConsoleLine();
        printf("Me: %s\n", str);

        if(strcmp(str, "exit") == 0)
        {
            printf("exiting\n");
            break;
        }
        
        SendMessage(qid, ppid, str);
    }

    printf("Killing: %d\n", pid);
    kill(pid,SIGCONT);
    exit(0);
}
这里不要用

MSG_EXCEPT,去掉这个flag就可以了

MSG_EXCEPT Used with msgtyp greater than 0 to read the first message in the queue with message type that differs from msgtyp.

原来只是那个特定的消息队列有问题。所以我只是关闭了消息队列并开始了一个新的队列并且全部修复了。关于 MSG_EXCEPT,我需要使用它,因为我不想只获取队列中当前的任何消息,就像使用 0 一样,我想获取任何不是由我自己提交的消息,除了我用来发送它们的密钥之外的任何消息。我可以这样做的另一种方法是每个进程有 2 个消息队列,一个用于获取另一个聊天进程的密钥和消息队列,一个用于在另一个聊天进程之间发送消息,但这会增加复杂性,这只是意味着成为一个简单的实现。