[linux操作系统实验]消息的发送与接收(消息发送中英文都乱码/变长消息结构体/msgget()一直失败返回-1)

/ 0评论 / 1307阅读 / 3点赞

问题

msgget()一直失败返回-1

消息发送中英文都乱码

struct msg_s{
    long  mtype;       //消息类型
    char  mtext[1024]; //消息的文本
    //char* mtext;     //这样是错的!!
};

msg_send.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <iostream>
#include <string>
#include <cstring>
#include <time.h>
#include <fstream>
using namespace std;

/*发送进程*/
struct msg_s
{
        long mtype;
        char* mtext;
};

int main()
{
        cout << "<< 我是进程1!" << endl;
        int msgqid = 0;
        //搞一个消息队列描述符
        while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);
        msg_s* msgp = new msg_s();
        msgp->mtype = 2;
        msgp->mtext = new char[1024];
        cout << "指针大小:" << sizeof(int*) << endl;
        cout << "进程1:mtext内容地址: " << (int*)(msgp->mtext) << endl;
        memset(msgp->mtext, 0, 1024);
        memset(msgp->mtext, 48 + msgp->mtype - 1, 10);
        msgsnd(msgqid, msgp, 1024, 0);
        cout << "进程1 发送内容:" << msgp->mtext << endl;
        delete[]msgp;
        return 0;
}

msg_rev.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <signal.h>
#include <sys/ipc.h>
#include <iostream>
#include <cstring>
#include <fstream>
#include <unistd.h>
using namespace std;

/*接收进程*/
struct msg_s
{
        long mtype;
        char mtext[];
};

int main()
{
        cout << "进程2:我是进程2!" << endl;
        int msgqid = 0;
        //搞一个消息队列描述符
        while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);
        msg_s* msgp =  (msg_s*)malloc(sizeof(long) + sizeof(char) * 1025);
        memset(msgp->mtext, 0, 1025);
        msgrcv(msgqid, msgp, 1024, 0, 0);
        cout << "int 大小:" << sizeof(int) << " | long 大小:" << sizeof(long) << endl;
        cout << "进程2:" << msgp->mtype - 1 << " | " << msgp->mtext << endl;
        cout << "mtext: " << (int*)(*((long*)(msgp->mtext))) << endl;
        msgctl(msgqid,IPC_RMID,0);
        return 0;
}

可变长度的消息结构体

如上所述,如果只能在结构体内定义数组,则消息的大小必须是固定的吗?

看这一小节的标题就知道显然不是的,我们可以使用柔性数组来实现变长消息结构体,使得mtext的内存空间即与结构体连续,又是可变长度。这实际上在上一小节的举例中msg_rev.cpp中已经用到了。

struct msg_s {
        long mtype;
        char mtext[];   //mtext必须放在最后
};
int main()
{
    //使用malloc动态申请空间
    msg_s* coolmsg = (msg_s*)malloc(sizeof(long) + sizeof(char) * 长度);
    //然后就可以初始化并使用它了
    coolmsg->mtype = 1;
    //将mtext的内容全部置为 'A'
    memset(coolmsg->mtext, 'A', 长度);
}

获取消息的信息

使用msgctl()可以获取到消息缓冲区地址,由此可以查询消息队列中消息数目,最后一个发送消息的进程的pid,发送时间,队列中的最大字节数等等。

struct  msqid_ds
{  
      struct  ipc_perm  msg_perm; /*许可权结构*/
      short  pad1[7];    /*由系统使用*/
      ushort msg_qnum;   /*队列上消息数*/
      ushort msg_qbytes; /*队列上最大字节数*/
      ushort msg_lspid;  /*最后发送消息的PID*/
      ushort msg_lrpid;  /*最后接收消息的PID*/
      time_t msg_stime;  /*最后发送消息的时间*/
      time_t msg_rtime;  /*最后接收消息的时间*/
      time_t msg_ctime;  /*最后更改时间*/
};
struct  ipc_perm
{  
      ushort uid;  /*当前用户*/
      ushort gid;  /*当前进程组*/
      ushort cuid; /*创建用户*/
      ushort cgid; /*创建进程组*/
      ushort mode; /*存取许可权*/
      { short pid1; long pad2;} /*由系统使用*/  
}
struct msg_s
{
        long mtype;
        char mtext[];
};

void tempfun()
{
    int msgqid = 0;
    //搞一个消息队列描述符
    while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);
    //申请一个消息长度1025的消息
    msg_s* msgp =  (msg_s*)malloc(sizeof(long) + sizeof(char) * 1025);
    memset(msgp->mtext, 0, 1025);

    //接收一次信息
    msgrcv(msgqid, msgp, 1024, 0, 0);
    msqid_ds cool_msgDs;

    //查询缓冲区
    msgctl(msgqid, IPC_STAT, &cool_msgDs);
    //获取缓冲区中记录的最后发送消息的进程pid
    int send_pid = cool_msgDs.msg_lspid;
    cout << "已经最后一个发送消息的进程pid:" << send_pid << endl;
    return 0;
}

具体实验内容

实验内容

消息的创建、发送和接收。使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序

概念

消息(message)是一个格式化的可变长的信息单元。消息机制允许由一个进程给其它任意的进程发送一个消息。当一个进程收到多个消息时,可将它们排成一个消息队列。消息使用二种重要的数据结构:一是消息首部,其中记录了一些与消息有关的信息,如消息数据的字节数;二个消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关信息。

涉及函数

msgget()

msgsnd()

msgrcv()

msgctl()

struct  msqid_ds
{  
      struct  ipc_perm  msg_perm;     /*许可权结构*/
      short  pad1[7];                 /*由系统使用*/
      ushort msg_qnum;                /*队列上消息数*/
      ushort msg_qbytes;              /*队列上最大字节数*/
      ushort msg_lspid;               /*最后发送消息的PID*/
      ushort msg_lrpid;               /*最后接收消息的PID*/
      time_t msg_stime;               /*最后发送消息的时间*/
      time_t msg_rtime;               /*最后接收消息的时间*/
      time_t msg_ctime;               /*最后更改时间*/
};
struct  ipc_perm
{  
      ushort uid;                     /*当前用户*/
      ushort gid;                     /*当前进程组*/
      ushort cuid;                    /*创建用户*/
      ushort cgid;                    /*创建进程组*/
      ushort mode;                    /*存取许可权*/
      { short pid1; long pad2;}       /*由系统使用*/  
}

源代码

msg_send.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <iostream>
#include <string>
#include <cstring>
#include <time.h>
#include <fstream>
using namespace std;

/*发送进程*/
struct msg_s
{
        long mtype;
        char mtext[];
};

int main()
{
        cout << "<< 我是进程1!" << endl;
        int msgqid = 0;
        while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);    //搞一个消息队列描述符

        msg_s* msgp = (msg_s*)malloc(sizeof(long) + sizeof(char) * 1025);
        msgp->mtype = 10;
        while(msgp->mtype > 0)
        {
                memset(msgp->mtext, 0, 1024);
                memset(msgp->mtext, 48 + msgp->mtype - 1, 10);
                msgsnd(msgqid, msgp, 1024, 0);
                cout << "进程1 :" << msgp->mtype - 1 << " | " << msgp->mtext << endl;
                --(msgp->mtype);
        }
        delete[]msgp;
        return 0;
}

msg_rev.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <iostream>
#include <cstring>
#include <fstream>
#include <unistd.h>
using namespace std;

/*接收进程*/
struct msg_s
{
        long mtype;
        char mtext[1025];
        msg_s(long in_mtype)
        {
                mtype = in_mtype;
        }
};

int main()
{
        cout << "<<  我是进程2!" << endl;
        int msgqid = 0;
        while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);  //搞一个消息队列描述符

        cout << "<< 进程2开始等待接收消息..."<<endl;
        msg_s* msgp = new msg_s(10);
        do{
                memset(msgp->mtext, 0, 1025);
                msgrcv(msgqid, msgp, 1024, 0, 0);
                cout << "<< 进程2:" << msgp->mtype - 1 << " | " << msgp->mtext << endl;
        }while(msgp->mtype > 1);

        msgctl(msgqid,IPC_RMID,0);
        return 0;
}

运行结果截图

思考

msg_send.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <iostream>
#include <string>
#include <cstring>
#include <time.h>
#include <fstream>
#include <signal.h>
#include <unistd.h>
using namespace std;

/*发送进程*/
struct msg_s
{
        long mtype;
        char mtext[];
};

/*指示是否接收*/
bool is_rev = false;

void setRev(int)
{
        is_rev = true;
}
int main()
{
        if(fork() == 0)
        {
                execl("./msg_rev", "msg_rev",NULL);
        }else{
                cout << "<< 我是进程1!" << endl;
                int msgqid = 0;
//搞一个消息队列描述符
                while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);    
                signal(16, setRev);
                msg_s* msgp = (msg_s*)malloc(sizeof(long) + sizeof(char) * 1025);
                msgp->mtype = 10;
                (msgp->mtext)[0] =  'a';
                msgsnd(msgqid, msgp, 1, 0);
                cout << "<< 进程1:等待进程2连接..." << endl;
                msgp->mtype = 10;
                while(msgp->mtype > 0)
                {
                        while(is_rev == false)
                                usleep(1000 * 100);
                        is_rev = false;
                        memset(msgp->mtext, 0, 1024);
                        memset(msgp->mtext, 48 + msgp->mtype - 1, 10);
                        msgsnd(msgqid, msgp, 1024, 0);
                        cout << "<< 进程1 :" << msgp->mtype - 1 << " | " << msgp->mtext << endl;
                        --(msgp->mtype);
                cout << "<< 进程1:发送结束" << endl;
                delete[]msgp;
        }
        return 0;
}

msg_rev.cpp

#include <sys/types.h>
#include <sys/msg.h>
#include <signal.h>
#include <sys/ipc.h>
#include <iostream>
#include <cstring>
#include <fstream>
#include <unistd.h>
using namespace std;

/*接收进程*/
struct msg_s
{
        long mtype;
        char mtext[];
};

int main()
{
        cout << "进程2:我是进程2!" << endl;
        int msgqid = 0;
//搞一个消息队列描述符
        while((msgqid = msgget(key_t(77), 0777 | IPC_CREAT)) == -1);  
        msg_s* msgp =  (msg_s*)malloc(sizeof(long) + sizeof(char) * 1025);
        cout << "进程2:正在等待进程1连接" << endl;
        int send_pid = 0;
        memset(msgp->mtext, 0, 1025);
        msgrcv(msgqid, msgp, 1024, 0, 0);
        msqid_ds cool_msgDs;
        msgctl(msgqid, IPC_STAT, &cool_msgDs);
        send_pid = cool_msgDs.msg_lspid;
        cout << "进程2:已经获取到进程1的pid:" << send_pid << endl;
        kill(send_pid, 16);
        cout << "进程2:开始等待接收消息..."<<endl;
        do{
                memset(msgp->mtext, 0, 1025);
                msgrcv(msgqid, msgp, 1024, 0, 0);
                cout << "进程2:" << msgp->mtype - 1 << " | " << msgp->mtext << endl;
                kill(send_pid, 16);
        }while(msgp->mtype > 1);

        msgctl(msgqid,IPC_RMID,0);
        return 0;
}

发表回复

您的电子邮箱地址不会被公开。