msgsnd 中的错误 - msgrcv,我无法查看发送的第二个字符串

error in msgsnd - msgrcv, I can't view the second string sent

嗨(抱歉我的英语不好),我正在尝试练习 Linux 在 IPC 中操作消息队列。 我创建了一个程序,允许一个进程(子进程 1)发送队列中的消息,而另一个进程(子进程 2)读取该消息。 此消息被定义为由两个字符串(str1 和 str2)和一个类型(long)组成的结构。 我想实现的目标是读取两个字符串,但结果是程序中只读取了一个。 谢谢

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

typedef struct{
    long int type;
    char str1[255];
    char str2[255];
}msg;

void sender(int fd_msg){
    msg message;
    char *string1 = "Hello";
    char *string2 = "World"; 

    strcpy(message.str1,string1);
    strcpy(message.str2,string2);

    message.type = 1;
    if(msgsnd(fd_msg,&message,strlen(message.str1)+1,0) == -1){
        printf("Error sending message at message 1 queue %d --> %s\n",errno,strerror(errno));
        return;
    }

    message.type = 2;
    if(msgsnd(fd_msg,&message,strlen(message.str2)+1,0) == -1){
        printf("Error sending message at message 2 queue %d --> %s\n",errno,strerror(errno));
        return;
    }

    if(printf("Message sent at the queue: %s -- %s\n",message.str1,message.str2) < 0){
        printf("Error printing sent messages %d --> %s\n",errno,strerror(errno));
        msgctl(fd_msg,IPC_RMID,NULL);           
        return; 
    }
    return;
}

void receiver(int fd_msg){
    msg message;
    char string1[255];
    char string2[255];
    
    sleep(1);
    if(msgrcv(fd_msg,&message,sizeof(message)-sizeof(long int),1,0) == -1){
        printf("error reiceiving message type 1 %d --> %s\n",errno,strerror(errno));
        return;

    }
    if(msgrcv(fd_msg,&message,sizeof(message)-sizeof(long int),2 ,0) == -1){
        printf("error reiceiving message type2 %d --> %s\n",errno,strerror(errno));
        return;
    }   

    if(printf("Message reiceved! : %s -- %s\n",message.str1,message.str2) < 0){
        printf("Error printing received message %d --> %s\n",errno,strerror(errno));
        msgctl(fd_msg,IPC_RMID,NULL);
        return;
    }

    strcpy(string1,message.str1);
    strcpy(string2,message.str2);
    //printf("string2: %s\n",messaggio.str2);

    return;
}

int main(int argc, char* argv[]){
    int fd_msg = -1;
    int key_msg = -1;
    pid_t p1;
    pid_t p2;

    key_msg = ftok("../Example/in.txt",55);   
    if((fd_msg = msgget(key_msg,IPC_CREAT | 0770)) == -1){             
        printf("Error creation message queue %d --> %s\n",errno, strerror(errno));
        return -1;
    }

    if((p1 = fork()) == 0){
        //child 1 (writer)
        sender(fd_msg);
        exit(0);
    }

    waitpid(p1,NULL,0);

    if((p2 = fork()) == 0){
        //child 2 (reader)
        receiver(fd_msg);
        exit(0);
    }

    waitpid(p2,NULL,0);

    msgctl(fd_msg,IPC_RMID,NULL);      
    return 0;
} 

您应该只发送 一条 条消息,长度为 sizeof(message)-sizeof(long int) ,就像您接收消息时所做的那样。那是因为 str1str2 固定 长度为 255.

您只需要 一个 消息(在单个消息中发送 两个 字符串的数据)。

如您所见,您[应该]发送的“短”负载长度是 255 + 5 + 1 不是 5 + 1 + 5 + 1

有多种方法可以做到这一点:

  1. 使用完整的 sizeof(msg)
  2. 发送一条包含两个字符串的消息
  3. 发送一封完整大小为 str1 但长度为 str2
  4. 的消息
  5. str1str2 合并到一个缓冲区中,然后 [手动] concatenate/split 字符串
  6. 使用单个缓冲区并发送两条消息,每个字符串一个,仅使用每个字符串的短长度。

示例 #1:

这是使用完整消息大小的更正代码:

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

typedef struct {
    long int type;
    char str1[255];
    char str2[255];
} msg;

void
sender(int fd_msg)
{
    msg message;
    char *string1 = "Hello";
    char *string2 = "World";

    strcpy(message.str1, string1);
    strcpy(message.str2, string2);

    size_t len = sizeof(message) - sizeof(long);

    message.type = 1;
    printf("Sending length %zu\n",len);
    if (msgsnd(fd_msg, &message, len, 0) == -1) {
        printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
        return;
    }

    if (printf("Message sent at the queue: %s -- %s\n", message.str1, message.str2) < 0) {
        printf("Error printing sent messages %d --> %s\n", errno, strerror(errno));
        msgctl(fd_msg, IPC_RMID, NULL);
        return;
    }
    return;
}

void
receiver(int fd_msg)
{
    msg message;
    char string1[255];
    char string2[255];

    sleep(1);

    ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
    if (len == -1) {
        printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
        return;

    }

    printf("Received length: %zu\n",len);
    if (printf("Message received! : %s -- %s\n", message.str1, message.str2) < 0) {
        printf("Error printing received message %d --> %s\n", errno, strerror(errno));
        msgctl(fd_msg, IPC_RMID, NULL);
        return;
    }

    strcpy(string1, message.str1);
    strcpy(string2, message.str2);
    // printf("string2: %s\n",messaggio.str2);

    return;
}

int
main(int argc, char *argv[])
{
    int fd_msg = -1;
    int key_msg = -1;
    pid_t p1;
    pid_t p2;

    key_msg = ftok("../Example/in.txt", 55);
    if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
        printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
        return -1;
    }

    if ((p1 = fork()) == 0) {
        // child 1 (writer)
        sender(fd_msg);
        exit(0);
    }

    waitpid(p1, NULL, 0);

    if ((p2 = fork()) == 0) {
        // child 2 (reader)
        receiver(fd_msg);
        exit(0);
    }

    waitpid(p2, NULL, 0);

    msgctl(fd_msg, IPC_RMID, NULL);
    return 0;
}

程序输出如下:

Sending length 512
Message sent at the queue: Hello -- World
Received length: 512
Message received! : Hello -- World

示例 #2:

这是 str2 使用“短”长度的程序:

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

typedef struct {
    long int type;
    char str1[255];
    char str2[255];
} msg;

void
sender(int fd_msg)
{
    msg message;
    char *string1 = "Hello";
    char *string2 = "World";

    strcpy(message.str1, string1);
    strcpy(message.str2, string2);

    size_t len = sizeof(message.str1) + strlen(message.str2) + 1;

    message.type = 1;
    printf("Sending length %zu\n",len);
    if (msgsnd(fd_msg, &message, len, 0) == -1) {
        printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
        return;
    }

    if (printf("Message sent at the queue: %s -- %s\n", message.str1, message.str2) < 0) {
        printf("Error printing sent messages %d --> %s\n", errno, strerror(errno));
        msgctl(fd_msg, IPC_RMID, NULL);
        return;
    }
    return;
}

void
receiver(int fd_msg)
{
    msg message;
    char string1[255];
    char string2[255];

    sleep(1);

    ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
    if (len == -1) {
        printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
        return;

    }

    printf("Received length: %zu\n",len);
    if (printf("Message received! : %s -- %s\n", message.str1, message.str2) < 0) {
        printf("Error printing received message %d --> %s\n", errno, strerror(errno));
        msgctl(fd_msg, IPC_RMID, NULL);
        return;
    }

    strcpy(string1, message.str1);
    strcpy(string2, message.str2);
    // printf("string2: %s\n",messaggio.str2);

    return;
}

int
main(int argc, char *argv[])
{
    int fd_msg = -1;
    int key_msg = -1;
    pid_t p1;
    pid_t p2;

    key_msg = ftok("../Example/in.txt", 55);
    if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
        printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
        return -1;
    }

    if ((p1 = fork()) == 0) {
        // child 1 (writer)
        sender(fd_msg);
        exit(0);
    }

    waitpid(p1, NULL, 0);

    if ((p2 = fork()) == 0) {
        // child 2 (reader)
        receiver(fd_msg);
        exit(0);
    }

    waitpid(p2, NULL, 0);

    msgctl(fd_msg, IPC_RMID, NULL);
    return 0;
}

程序输出如下:

Sending length 261
Message sent at the queue: Hello -- World
Received length: 261
Message received! : Hello -- World

示例 #3:

使用 separate str1str2 强制我们发送 str1 的完整大小,即使实际字符串长度更短。

要发送一条 单个 消息,该消息具有 两个 字符串并发送 我们的长度需要将 str1str2 组合成一个 单个 缓冲区(例如 strs)。这需要我们将两个字符串连接到缓冲区中。

这还要求接收方恢复两个单独的字符串。

代码如下:

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

typedef struct {
    long int type;
    char strs[512];
} msg;

void
sender(int fd_msg)
{
    msg message;
    char *string1 = "Hello";
    char *string2 = "World";

    char *cp = message.strs;

    strcpy(cp, string1);
    cp += strlen(cp) + 1;

    strcpy(cp, string2);
    cp += strlen(cp) + 1;

    size_t len = cp - message.strs;

    message.type = 1;
    printf("Sending length %zu\n",len);
    if (msgsnd(fd_msg, &message, len, 0) == -1) {
        printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
        return;
    }
}

void
receiver(int fd_msg)
{
    msg message;
    char string1[255];
    char string2[255];

    sleep(1);

    ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
    if (len == -1) {
        printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
        return;

    }

    printf("Received length: %zu\n",len);

    char *cp = message.strs;

    strcpy(string1, cp);
    cp += strlen(cp) + 1;

    strcpy(string2, cp);
    cp += strlen(cp) + 1;

    printf("string1: %s\n",string1);
    printf("string2: %s\n",string2);

    return;
}

int
main(int argc, char *argv[])
{
    int fd_msg = -1;
    int key_msg = -1;
    pid_t p1;
    pid_t p2;

    key_msg = ftok("../Example/in.txt", 55);
    if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
        printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
        return -1;
    }

    if ((p1 = fork()) == 0) {
        // child 1 (writer)
        sender(fd_msg);
        exit(0);
    }

    waitpid(p1, NULL, 0);

    if ((p2 = fork()) == 0) {
        // child 2 (reader)
        receiver(fd_msg);
        exit(0);
    }

    waitpid(p2, NULL, 0);

    msgctl(fd_msg, IPC_RMID, NULL);
    return 0;
}

程序输出如下:

Sending length 12
Received length: 12
string1: Hello
string2: World

示例 #4:

我可能会执行示例 #1 并发送完整的结构长度。

或者,我将使用示例 #3 中的组合缓冲区,但会发送 两条 条单独的消息,每个字符串一条消息:

代码如下:

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

typedef struct {
    long int type;
    char str[255];
} msg;

void
sendone(int fd_msg,int type,const char *str)
{
    msg message;

    strcpy(message.str, str);
    size_t len = strlen(str) + 1;

    message.type = type;

    printf("Sending type %ld length %zu\n",message.type,len);
    if (msgsnd(fd_msg, &message, len, 0) == -1) {
        printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
        return;
    }

    printf("Message sent at the queue: %s\n", message.str);
}

void
sender(int fd_msg)
{
    char *string1 = "Hello";
    char *string2 = "World";

    sendone(fd_msg,2,string2);
    sendone(fd_msg,1,string1);

    return;
}

ssize_t
recvone(int fd_msg,msg *message)
{
    int type = 0;

    ssize_t len = msgrcv(fd_msg, message, sizeof(msg) - sizeof(long int), type, 0);
    if (len == -1) {
        printf("error receiving message %d --> %s\n", errno, strerror(errno));
        return len;
    }

    printf("Received type %ld message of length: %zu\n",message->type,len);
    printf("Message received! : %s\n",message->str);

    return len;
}

void
receiver(int fd_msg)
{
    msg message;
    char strings[2][255];

    sleep(1);

    // deliberately receive messages in any order
    for (int imsg = 1;  imsg <= 2;  ++imsg) {
        recvone(fd_msg,&message);
        strcpy(strings[message.type - 1],message.str);
    }

    for (int imsg = 1;  imsg <= 2;  ++imsg)
        printf("receiver: string %d: %s\n",imsg,strings[imsg - 1]);

    return;
}

int
main(int argc, char *argv[])
{
    int fd_msg = -1;
    int key_msg = -1;
    pid_t p1;
    pid_t p2;

    key_msg = ftok("../Example/in.txt", 55);
    if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
        printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
        return -1;
    }

    if ((p1 = fork()) == 0) {
        // child 1 (writer)
        sender(fd_msg);
        exit(0);
    }

    waitpid(p1, NULL, 0);

    if ((p2 = fork()) == 0) {
        // child 2 (reader)
        receiver(fd_msg);
        exit(0);
    }

    waitpid(p2, NULL, 0);

    msgctl(fd_msg, IPC_RMID, NULL);
    return 0;
}

程序输出如下:

Sending type 2 length 6
Message sent at the queue: World
Sending type 1 length 6
Message sent at the queue: Hello
Received type 2 message of length: 6
Message received! : World
Received type 1 message of length: 6
Message received! : Hello
receiver: string 1: Hello
receiver: string 2: World