Maison  >  Article  >  Tutoriel système  >  Linux IPC System V Message Queuing : un moyen classique de livraison fiable des messages

Linux IPC System V Message Queuing : un moyen classique de livraison fiable des messages

王林
王林avant
2024-02-12 15:33:151051parcourir

Le système Linux est un système d'exploitation qui prend en charge l'exécution simultanée de tâches multiples. Il peut exécuter plusieurs processus en même temps, améliorant ainsi l'utilisation et l'efficacité du système. Cependant, si l'échange de données et la collaboration sont requis entre ces processus, certaines méthodes de communication inter-processus (IPC) doivent être utilisées, telles que les signaux, la mémoire partagée, les sémaphores, etc. Parmi eux, la file d'attente de messages System V est une méthode IPC relativement classique et fiable. Elle permet à deux processus ou plus de transmettre des messages via une file d'attente sans se soucier du contenu et du format du message. Cet article présentera la méthode de file d'attente de messages System V dans le système Linux, y compris la création, l'ouverture, l'envoi, la réception, la fermeture et la suppression de la file d'attente de messages.

Linux IPC System V 消息队列:一种实现可靠消息传递的经典方式

Modèle

#include 
#include 
#include 
ftok()               //获取key值                               
msgget()             //创建/获取消息队列                        
msgsnd()/msgrcv()    //发消息到消息队列/从消息队列收信息        
msgctl()             //删除消息队列                           

ftok()

//获取key值, key值是System V IPC的标识符,成功返回key,失败返回-1设errno
//同pathname+同 proj_id==>同key_t;
key_t ftok(const char *pathname, int proj_id);

pathname : nom du fichier
proj_id : un nombre de 1 à 255, représentant project_id

key_t key=ftok(".",100);    //“.”就是一个存在且可访问的路径, 100是假设的proj_id
    if(-1==key)
        perror("ftok"),exit(-1);

msgget()

//创建/获取消息队列,成功返回shmid,失败返回-1
int msgget(key_t key, int msgflg);  //ATTENTION:用int msqid=msgget()比较好看

msgflg : drapeau d'opération spécifique

  • IPC_CREAT S'il n'existe pas, créez-le. Vous avez besoin de "|Permission Information" dans msgflg ; s'il existe, ouvrez-le
  • .
  • IPC_EXCLS'il existe, la création échoue
  • 0 Obtenez une file d'attente de messages existante

La capacité de la file d'attente des messages est contrôlée par msg_qbytes Lors du processus de création de la file d'attente des messages, cette taille est initialisée à MSGMNB. Cette limite peut être modifiée via msgctl()

.
int msqid=msgget(key,IPC_CREAT|IPC_EXCL|0664);
if(-1==msqid)
    perror("msgget"),exit(-1);

msgsnd()

//向指定的消息队列发送指定的消息,如果消息队列已经满了,默认的行为是堵塞,直到队列有空间容纳新的消息,成

功返回0,失败返回-1设errno
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid L'ID de la file d'attente des messages renvoyé par msgget()
msgpLa première adresse du message Le type de données de référence du message est le suivant

.
struct msgbuf {
    long mtype;       /* message type, must be > 0 */   //消息的类型
    char mtext[1];    /* message data */                //消息的内容
};
ATTENTION:The  mtext field is an array (or other structure) whose size is
 specified by msgsz, a nonnegative integer value. 

msgszLa taille du message. Ce paramètre permet de spécifier la taille du contenu du message, hors le type du message. Il ne peut s'agir que de sizeof(Msgbuf.mtext), pas sizeof(Msgbuf)
msgflgLe drapeau envoyé, la valeur par défaut est 0

Msg msg1={1,"hello"};//消息的类型是1,内容是hello
int res=msgsnd(msqid,&msg2,sizeof(msg2.buf),0);
if(-1==res)
    perror("msgsnd"),exit(-1);

msgrcv()

//向指定的消息队列取出指定的消息,成功返回实际接受到的byte数,失败返回-1设errno
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msqid : L'ID de la file d'attente des messages (renvoyé par msgget)
msgp : La première adresse du tampon où est stocké le message reçu
msgsz : La taille maximale du message, excluant le type de message ==> uniquement sizeof( Msgbuf.mtext), impossible sizeof(Msgbuf)

  • Si la longueur du message est > msgsz et qu'il y a MSG_NOERROR dans msgflg, le message sera tronqué et la partie tronquée sera perdue
  • Si la longueur du message est >msgsz et qu'il n'y a pas de MSG_NOERROR dans msgflg, une erreur se produira et E2BIG sera signalé.

msgtyp : Type de message

  • 0 : Lisez le premier message dans la file d'attente des messages
  • >0 : Lisez le premier message de type msgtype dans la file d'attente des messages. À moins qu'il n'y ait MSG_EXCEPT dans msg_flg, le premier message de la file d'attente qui n'est pas msgtyp sera lu
  • .
  • Lisez le type dans la file d'attente des messages

msgflg : indicateur à envoyer, par défaut 0

Msg msg1;
int res=msgrcv(msqid,&msg1,sizeof(msg1.buf),1,0);
if(-1==res)
    perror("msgrcv"),exit(-1);

msgctl()

// 消息操作,成功返回0,失败返回-1设errno
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msqid :消息队列的ID,由msgget()
buf 结构体指针

struct msqid_ds {
    struct ipc_perm msg_perm;       /* Ownership and permissions */
    time_t          msg_stime;      /*Time of last msgsnd(2) */
    time_t          msg_rtime;      /* Time of last msgrcv(2) */
    time_t          msg_ctime;      /* Time of last change */
    unsigned long   __msg_cbytes;   /* Current number of bytes in queue (nonstandard) */
    msgqnum_t       msg_qnum;       /* Current number of messages in queue */
    msglen_t        msg_qbytes;     /* Maximum number of bytes allowed in queue */
    pid_t           msg_lspid;      /* PID of last msgsnd(2) */
    pid_t           msg_lrpid;      /* PID of last msgrcv(2) */
};
struct ipc_perm {
    key_t           __key;      /* Key supplied to msgget(2) */
    uid_t           uid;        /* Effective UID of owner */
    gid_t           gid;        /* Effective GID of owner */
    uid_t           cuid;       /* Effective UID of creator */
    gid_t           cgid;       /* Effective GID of creator */
    unsigned short  mode;       /* Permissions */
    unsigned short  __seq;      /* Sequence number */
};

cmd

  • IPC_STAT从内核相关结构体中拷贝消息队列相关的信息到buf指向的结构体中

  • IPC_SET把buf指向的结构体的内容写入到内核相关的结构体中,同时更显msg_ctimer成员,同时以下成员也会被更新:msg_qbytes, msg_perm.uid, msg_perm.gid, msg_perm.mode。调用队列的进程的effective UID必须匹配队列所有者或创建者的msg_perm.uid或msg_perm.cuid或者该进程拥有特权级别,

  • IPC_RMID立即销毁消息队列,唤醒所有正在等待读取或写入该消息队列进程,调用的进程的UID必须匹配队列所有者或创建者或者该进程拥有足够的特权级别

  • IPC_INFO (Linux-specific)返回整个系统对与消息队列的限制信息到buf指向的结构体中

    //_GNU_SOURCE
    //
    struct msginfo {
        int msgpool;/*Size in kibibytes of buffer pool used to hold message
     data; unused within kernel*/
        int msgmap; /*Maximum number of entries in message map; unused within 
    kernel*/
        int msgmax; /*Maximum number of bytes that can be written in a single
     message*/
        int msgmnb; /*Maximum number of bytes that can be written to queue; 
    used to initialize msg_qbytes  during queue creation*/
        int msgmni; /*Maximum number of message queues*/
        int msgssz; /*Message segment size; unused within kernel*/
        int msgtql; /*Maximum number of messages on all queues in system; unused
     within kernel*/
        unsigned short int  msgseg; /*Maximum number of segments; unused
     within kernel*/
    };
    
    int res=msgctl(msqid,IPC_RMID,NULL);
    if(-1==res)
    perror("msgctl"),exit(-1);
    

例子

//Sys V IPC msg
#include
#include
#include
#include
#include
typedef struct{
    long mtype;     //消息的类型
    char buf[20];       //消息的内容
}Msg;
int msqid;          //使用全局变量,这样就可以在fa中使用msqid了
void fa(int signo){
    printf("deleting..\n");
    sleep(3);
    int res=msgctl(msqid,IPC_RMID,NULL);
    if(-1==res)
        perror("msgctl"),exit(-1);
    exit(0);
}
int main(){
    //ftok()
    key_t key=ftok(".",150);
    if(-1==key)
        perror("ftok"),exit(-1);
    printf("key%#x\n",key);
    //msgget()
    msqid=msgget(key,IPC_CREAT|IPC_EXCL|0664);
    if(-1==msqid)
        perror("msgget"),exit(-1);
    printf("msqid%d\n",msqid);
    //msgsnd()
    Msg msg1={1,"hello"};//消息的类型是1,内容是hello
    Msg msg2={2,"world"};
    int res=msgsnd(msqid,&msg2,sizeof(msg2.buf),0);
    if(-1==res)
        perror("msgsnd"),exit(-1);
    res=msgsnd(msqid,&msg1,sizeof(msg1.buf),0);
    if(-1==res)
        perror("msgsnd"),exit(-1);
    //msgctl()
    //Ctrl+C delete msq
    printf("Press CTRL+C to delete msq\n");
    if(SIG_ERR==signal(SIGINT,fa))
        perror("signal"),exit(-1);
    while(1);
    return 0;
}

本文介绍了Linux系统中System V 消息队列的方法,包括消息队列的创建、打开、发送、接收、关闭和删除等方面。通过了解和掌握这些知识,我们可以更好地使用System V 消息队列来实现进程间通信,提高系统的稳定性和效率。当然,Linux系统中System V 消息队列还有很多其他的特性和用法,需要我们不断地学习和研究。希望本文能给你带来一些启发和帮助。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer