Очереди сообщений IPC не работают должным образом

этот код реализует простую систему связи клиент-сервер с использованием очередей сообщений на языке C.

local.h

#include <stdio.h>
#include <sys/types.h>
#include "sys/ipc.h"
#include <sys/msg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

#define SEED 'g'    /* seed for ftok */
#define SERVER 1L   /* message for the server */

typedef struct{
    long    msg_to; /* placed in the queue for */
    long    msg_fm;  /* placed in the queue by */
    char    buffer[BUFSIZ];
}MESSAGE;

клиент.с:

#include "local.h" 

int main(int argc, char const *argv[])
{
    key_t       key;
    pid_t       cli_pid;
    int         mid, n;
    MESSAGE     msg;
    static char m_key[10];

    cli_pid = getpid();
    
    if ((key = ftok(".", SEED)) == -1){
        perror("Client: key generation");
        exit(1);
    }

    if ((mid = msgget(key, 0)) == -1){
        mid = msgget(key, IPC_CREAT | 0660);
        printf("%d", mid);
        
        switch (fork()){
        case -1:
            perror("Client: fork");
            exit(3);
        case 0:
            sprintf(m_key, "%d", mid);
            execlp("./server", "server", m_key, NULL);
            perror("Client: exec");
            exit(4);
        }
    }
    while(1){
        msg.msg_to = SERVER;
        msg.msg_fm = cli_pid;

        write(fileno(stdout), "cmd>", 5);
        memset(msg.buffer, 0x0, BUFSIZ);
        n = read(fileno(stdin), msg.buffer, BUFSIZ);
        if (n == 0){
            break;
        }


        if (msgsnd(mid, &msg, sizeof(msg), 0) == -1){
            perror("Client: msgsend");
            exit(5);
        }
        if ((n = msgrcv(mid, &msg, sizeof(msg), cli_pid, 0)) != -1){
            write(fileno(stdout), msg.buffer, strlen(msg.buffer));
        }
    }
    msgsnd(mid, &msg, 0, 0);
    exit(0);
}

сервер.с:

#include "local.h"

int main(int argc, char const *argv[])
{
    int     mid, n;
    MESSAGE msg;
    void    process_msg(char *, int);

    if (argc != 3) {
        fprintf(stderr, "Usage: %s msq_id &\n", argv[0]);
        exit(1);
    }
    while (1) {
        if ((n=msgrcv(mid, &msg, sizeof(msg), SERVER, 0)) == -1 ) {
            perror("Server: msgrcv");
            exit(2);
        } else if (n == 0){
            break;
        } else {
            process_msg(msg.buffer, strlen(msg.buffer));
            msg.msg_to = msg.msg_fm;
            msg.msg_fm = SERVER;
            if (msgsnd(mid, &msg, sizeof(msg), 0) == -1 ) {
                perror("Server: msgsnd");
                exit(3);
            }
        }
    }
    msgctl(mid, IPC_RMID, (struct msqid_ds *) 0 );
    exit(0);
}

void process_msg(char *b, int len) {
    int i;
    for (i = 0; i < len; ++i){
        if (isalpha(*(b + i))){
            *(b + i) = toupper(*(b + i));
        }
    }
}

Если я попытаюсь скомпилировать эти файлы с помощью этих команд:

gcc -o сервер server.c
gcc -o клиент client.c

и запустите файлы:

./сервер 123 &
./клиент

Сервер запущен и ждет,

(базовый) user@PC:~/UNIX/mqueues$ ./server 123 &
[2] 93463
(базовый) user@PC:~/UNIX/mqueues$ Использование: ./server msq_id &
/жду сообщения здесь/

затем я пытаюсь отправить сообщение от клиента. Однако я получаю это сообщение об ошибке от клиента:

(базовый) user@PC:~/UNIX/mqueues$ ./client
cmd>привет
Клиент: msgsend: неверный аргумент

Наверное я что-то делаю не так, буду очень признателен, если вы мне поможете. Спасибо.

Я заметил одну проблему: вы передаете sizeof(MESSAGE) в качестве размера сообщения, но размер не должен включать часть mtype (в вашем случае часть msg_to), поэтому между процессами копируются случайные байты. Насколько я понимаю, это не имеет отношения к вашей проблеме. Но просто чтобы вы знали.

ariel marcovitch 05.05.2024 15:56

Где server.c инициализирует mid?

Joseph Sible-Reinstate Monica 05.05.2024 18:27

Можете ли вы добавить в client.c код, который выполняет perror, если mid = msgget(key, IPC_CREAT | 0660); равно -1?

Joseph Sible-Reinstate Monica 05.05.2024 18:27

Я перепробовал все предложения здесь, но все равно. Я получаю ту же ошибку «Неверный аргумент». Спасибо за ваш ответ.

kaanyvz 05.05.2024 21:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

в строках кода ниже для msg_to не установлено значение SERVER. Кажется, это проблема.

        process_msg(msg.buffer, strlen(msg.buffer));
        msg.msg_to = msg.msg_fm;
        msg.msg_fm = SERVER;

Если msg_to не установлен, msg_type недействителен для вызова msgsend() и может произойти сбой.

Спасибо за ваш ответ, однако он все тот же.

kaanyvz 05.05.2024 21:50

БУФСИЗ нигде не устанавливается. Или это пропущено при копировании кода? Можно ли использовать жестко закодированное сообщение, а не стандартный ввод, чтобы проверить, в чем проблема.

mr.anand 05.05.2024 21:57

BUFSIZ нигде не установлен, вы правы. Потому что это происходит из-под stdio.h. Также я попробовал жестко закодированное сообщение, однако получаю то же сообщение об ошибке.

kaanyvz 05.05.2024 22:08

BUFSIZ имеет размер 8 КБ. Пожалуйста, проверьте максимальный размер сообщения, которое можно использовать при вызове msgsend(). Я считаю, что это также 8k. на данный момент просто проверяйте с помощью 20 байтов или небольшого размера буфера вместо BUFSIZ на случай, если мы сможем сузить эту проблему

mr.anand 05.05.2024 22:24
Ответ принят как подходящий

Видеть:

(base) user@PC:~/UNIX/mqueues$ ./server 123 &
[2] 93463
(base) user@PC:~/UNIX/mqueues$ Usage: ./server msq_id &
/waiting for message here/

Это означает, что сервер вышел из строя (сообщение usage...). Первая ошибка заключается в том, что вам необходимо передать на сервер 3 аргумента, но последний & не является частью аргументов команды, а используется оболочкой для запуска команды в фоновом режиме.

Вторая ошибка заключается в том, что вы должны сначала создать очередь сообщений на сервере, прежде чем вызывать msgrcv. Если нет, то как сервер сможет что-то прочитать?

В-третьих, какая логика стоит за всем этим? Клиент разветвляет сервер, но кажется, что вы тоже хотите запустить сервер вручную. Забудьте о запуске сервера с клиента.

Другие вопросы по теме

Как разветвить процесс на другой виртуальный терминал
Сценарий оболочки – как отображать имена переменных и их значения в цикле
Почему Listen() (до вызова Accept()) достаточно, чтобы приложение завершило трехстороннее рукопожатие?
Попытка передать «указатель на структуру данных» обработчику сигнала с помощью функции sigqueue из одного процесса в другой, используя структуру siginfo_t
Awk: попробуйте преобразовать строку временной метки во время эпохи Unix
Как уничтожить/освободить объект FILE, не закрывая базовый файловый дескриптор?
Синтаксис для извлечения имени файла.ext*, но не имени файла.ext*.*
Обработать текстовый файл, чтобы изменить значение столбца на основе максимального значения из другого столбца
Почему getchar() зависает, несмотря на то, что poll() возвращает «хорошее» значение?
Необходимо ли использовать fflush более одного раза?