[Message Queue] Message Queues communicate with processes

0. IPC object

        In addition to the most primitive inter-process communication methods, signals, unnamed pipes and named pipes, there are three inter-process communication methods, which are called IPC objects.

IPC object classification: message queue, shared memory, semaphore set

        The IPC object also opens up an area in the kernel space. After each IPC object is created, it will be set as global and assigned a number. As long as the unique number is found, communication can be carried out, so unrelated processes can pass IPC object communication.

        After the IPC object is created, it will be visible in the current system and will always exist as long as it is not deleted or the system is shut down.

View the created IPC object:

ipcs View all IPC objects created in the current system

ipcs -q View the created message queue

ipcs -m View the created shared memory

ipcs -s View the created semaphore

ipcrm deletes IPC objects

        For example: ipcs -q msqid deletes the message queue labeled msqid

 

1. Message queue overview

The message queue is a linked list of messages, stored in memory and maintained by the kernel.

Characteristics of message queue:

  • Messages in the message queue are typed.
  • Messages in the message queue are formatted.
  • The message queue can implement random query of messages . Messages do not have to be read in first-in, first-out order. You can read them according to the type of message during programming.
  • A message queue allows one or more processes to write or read messages to it.
  • Like unnamed pipes and named pipes, when messages are read from the message queue, the corresponding data in the message queue will be deleted.
  • Each message queue has a message queue identifier, and the message queue's identifier is unique throughout the system.
  • The message queue will only be deleted when the kernel is restarted or the message queue is manually deleted. If the message queue is not deleted manually, the message queue will always exist in the system.

The message queue restrictions in Ubuntu 12.04 are as follows: (Just understand it)

  • Each message content can be up to 8K bytes
  • Each message queue has a maximum capacity of 16K bytes
  • The maximum number of message queues in the system is 1609
  • The maximum number of messages in the system is 16384

2. Message queue related functions

2.1 Generate key value: ftok function

        The IPC communication mechanism provided by System V requires a key value, through which a unique message queue identifier can be obtained within the system.

        The key value can be manually specified or obtained through the ftok function.

        If multiple processes communicate through IPC objects, they must find a unique identifier, and the unique identifier is determined by the key, so as long as the key is known, multiple processes can communicate.

ftok function:

#include<sys/types.h>

#include<sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);

Function: Create a key value through the file name and the target value and return the value

parameter:

        pathname: any file name (file name or directory name)

        proj_id: target value, the range is generally 0~127 (lower eight bits)

return value:

        Success: key value

        Failure: -1

If you use the ftok function to obtain the key value, the key value obtained is the file corresponding to the first parameter of ftok.

The information is determined together with the second parameter.

 Code example:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>

int main()
{
    //使用ftok函数获取键值
    //只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管
    //程序运行多少遍或者多少个进程
    //键值一定是唯一的
    key_t mykey;
    if ((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    printf("key = %#x\n", mykey);
    return 0;
}

 Execution screenshot:

2.2 Create message queue: msgget function

msgget function:

#include<sys/msg.h>

int msgget(key_t key,  int msgflg);

Function:

        Create a message queue and get the id of the message queue

parameter:

        key: key value, the unique key value determines the unique message queue

                Method 1: Specify an arbitrary number

                Method 2: Use the ftok function to obtain the key value (recommended)

        msgflg: The access permission of the message queue, generally set to

                        IPC_CREAT | IPC_EXCL |0777

                        IPC_CREAT | 0777

return value:

        Success: message queue id

        Failure: -1

Code example:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<unistd.h>

int main()
{
    key_t mykey;
    if ((mykey = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }
    printf("mykey = %#x\n", mykey);

    int msqid;
    if ((msqid = msgget(mykey, IPC_CREAT | 0666)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    printf("msqid = %d\n", msqid);

    return 0;
}

Execution screenshot:

 2.3 Send message: msgsnd function

msgsnd function:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

Function: Send data to the specified message queue (write operation)

parameter:

        msqid: message queue id 

        msgp: The data to be written needs to be defined by yourself.

                struct struct msg{

                        long mtype; //Message number, must be greater than 0

                        char mtext[128]; //Message text, multiple members can be defined

                }MSG;

        msgsz: The size of the message body, excluding the number length of the message

        msgflg: flag bit

                0 blocking

                IPC_NOWAIT non-blocking

return value:

        Success: 0

        Failure: -1

Code example:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<unistd.h>

#define N 128
typedef struct {
    long msg_type;//必须要有,且必须是long类型
    char msg_text[N];//可以有多个,自己定义
}MSG;
#define MSGTEXT_SIZE (sizeof(MSG) - sizeof(long))
int main()
{
    key_t key;
    if ((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    int msgid;
    if ((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }

    MSG msg1 = { 1, "hello world" };
    MSG msg2 = { 2, "hello beijing" };
    MSG msg3 = { 3, "nihao zhangsan" };
    MSG msg4 = { 4, "lisi hello" };

    if (msgsnd(msgid, &msg1, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }
    if (msgsnd(msgid, &msg2, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }
    if (msgsnd(msgid, &msg3, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }
    if (msgsnd(msgid, &msg4, MSGTEXT_SIZE, 0) == -1)
    {
        perror("fail to msgsnd");
        exit(1);
    }

    return 0;
}

Execution screenshot:

2.4 Receive messages: msgrcv function

msgrcv function:

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

Function: Receive data from the message queue (read operation), the received data will be deleted from the message queue

parameter:

        msqid: message queue id

        msgp: structure to save received data

                struct struct_name{

                        long mytpe; //Message number, must be greater than 0

                        char metxt[128]; //Message text, multiple members can be defined        

                }

        msgsz: size of message body

        msgtype: Set which message to receive

                 0 Read once in the order written to the message queue

                >0 Read only the first message in the message queue with the message number of the current parameter

                <0 Only read the smallest first message in the message queue that is less than or equal to the absolute value of the current parameter

        msgflg: flag bit

                 0 blocking

                 IPC_NOWAIT non-blocking

return value:

        Success: Length of message body received

        Failure: -1

Code example:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

#define N 128
typedef struct {
    long msg_type;
    char msg_text[N];
}MSG;

#define MSGTEXT_SIZE (sizeof(MSG) - sizeof(long))

int main()
{
    key_t key;
    if ((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    int msgid;
    if ((msgid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    //通过msgrcv函数接收消息队列中的信息(读操作)
    //注意:如果没有第四个参数指定的消息时,,msgrcv函数会阻塞等待
    MSG msg;
    //如果第四个参数为>0,则获取当前值的消息类型的数据
    //if (msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == -1)
    // 如果第四个参数<0,则获取当前值的绝对值内消息类型最小的数据
    //if (msgrcv(msgid, &msg, MSGTEXT_SIZE, -3, 0) == -1)
    //如果第四个参数为0,则按照先进先出的方式读取数据
    if (msgrcv(msgid, &msg, MSGTEXT_SIZE, 0, 0) == -1)
    {
        perror("fail to msgrcv");
        exit(1);
    }
    printf("recv_msg = %s\n", msg.msg_text);

    return  0;
}

Execution screenshot:

 2.5 Message queue control: msgctl function

msgctl function:

#include<sys/mg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

Function:

        Perform various controls on the message queue, such as modifying the properties of the message queue or deleting the message queue

parameter:

        msqid: identifier of the message queue

        cmd: Control of function functions

                IPC_RMID: Delete the message queue indicated by msqid, removing it from the system and destroying related data structures.

                IPC_STAT: Store the current value of each element in the msqid-related data structure into the structure pointed to by buf.

                IPC_SET: Set the elements in the msqid-related data structure to the corresponding values ​​in the structure pointed to by buf.

        buf: The address of the msqid_ds data type, used to store or modify the attributes of the message queue.

return value:

        Success: 0

        Failure: -1

Code example:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/msg.h>


int main()
{
    key_t key;
    if ((key = ftok(".", 100)) == -1)
    {
        perror("fail to ftok");
        exit(1);
    }

    int msqid;
    if ((msqid = msgget(key, IPC_CREAT | 0777)) == -1)
    {
        perror("fail to msgget");
        exit(1);
    }
    printf("msqid = %d\n", msqid);
    system("ipcs -q");

    if ((msgctl(msqid, IPC_RMID, NULL)) == -1)
    {
        perror("fail to msgctl");
        exit(1);
    }
    system("ipcs -q");
    return 0;
}

Execution screenshot:

 Summarize:

        As an IPC mechanism, message queue provides powerful functions for sending and receiving messages between processes. By using message queues, complex multi-process applications can be built to achieve safe transmission and orderly communication of data, thus greatly improving the system's concurrent processing capabilities. However, you must also be aware of the limitations of the message queue, such as the size of the queue, the total number of stored messages, etc., which may have an impact on the performance of the application.

        Therefore, when using message queues, we need to weigh its advantages and potential challenges to ensure that we can maintain efficient performance and stable operation while meeting business needs.

 

Guess you like

Origin blog.csdn.net/crr411422/article/details/131421873