个人餐饮网站模板,域名网站建设,做网站都能用什么做,零售网站制作Linux多进程通信总结——进程间通信看这一篇足够啦#xff01;
1.基本介绍
1#xff09;消息队列的本质其实是一个内核提供的链表#xff0c;内核基于这个链表#xff0c;实现了一个数据结构#xff0c;向消息队列中写数据#xff0c;实际上是向这个数据结构中插入一个…Linux多进程通信总结——进程间通信看这一篇足够啦
1.基本介绍
1消息队列的本质其实是一个内核提供的链表内核基于这个链表实现了一个数据结构向消息队列中写数据实际上是向这个数据结构中插入一个新结点从消息队列汇总读数据实际上是从这个数据结构中删除一个结点 2消息队列独立于发送与接收进程进程终止时消息队列中的内容不会被删除所以要记得删除消息队列 3消息队列可以实现消息的随机查询消息不一定要以先进先出的次序读取也可以按照消息的类型读取 4Linux环境中最多有256个消息队列每个消息最大为8K字节总大小不能超过16K否则在send时会阻塞可以通过更改内核设置的方式更改大小。
2.API介绍
1获取消息队列键值
#include sys/types.h
#include sys/ipc.h
key_t ftok(char *pathname, char proj);pathname路径名是必须存在的ftok只是根据文件inode在系统内的唯一性来取一个数值和文件的权限无关。 proj1-255之间的数字 返回值 生成一个独有的数失败则返回-1 key 31-24 proj_id 低8位 key 23-16 pathname的st_dev属性的低8位 key 15-0 pathname的st_ino属性的低16位32位组合而成一个int值就是我们的ftok的返回值了 根据路径名以及数字合成系统中唯一的Key值
2创建/获取消息队列
#include sys/types.h
#include sys/ipc.h
#include sys/msg.h
int msgget(key_t key, int msgflg);key使用ftok获取到的唯一Key值 msgflag 和其他的IPC通信一样IPC_CREAT如果消息队列对象不存在则创建之否则则进行打开操作。IPC_EXCL如果消息对象不存在则创建之否则产生一个错误并返回可同时用IPC_CREATE | 0666 返回值成功返回消息队列ID失败则返回-1
3msgsend发送消息
int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);msgid 消息队列ID msgptr消息体消息体的类型是一个结构体 msg_sz 消息长度 消息体中的消息长度不是一整个结构体的长度只是mtext消息数据的长度 msgflag 发送flag 一般设置为0阻塞式等待消息队列满也可以设置为 IPC_NOWAIT则立刻返回 返回值成功返回0失败返回-1 调用成功后发送内容的一个备份会被放到消息队列中这里会有个硬拷贝的过程
4msgrecv接收消息
ssize_t msgrcv(int msgid, const void *msgp, size_t msgsz int msgtype, int msgflag)msgid消息队列ID msgp 接收到的消息体 msgsz 接收消息的长度 msgtype 消息类型 对应发送时的m_type。 值为0代表接收一个任意类型的消息 值大于0获取消息类型为msgtype的第一个消息 值小于0获取消息类型小于等于msgtype的第一个消息 msgflag 接收的flag一般设置为0阻塞式等待 msgflgIPC_NOWAIT队列没有可读消息不等待返回ENOMSG错误。 msgflgMSG_NOERROR消息大小超过msgsz时被截断 msgtype0且msgflgMSC_EXCEPT接收类型不等于msgtype的第一条消息。 返回值调用成功时返回接收到消息的字节数失败返回-1
调用成功时消息被复制到由msg_ptr指向的用户分配的缓存区中然后删除消息队列中的对应消息这里会有个硬拷贝的过程
5控制消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);msgid消息队列id cmd控制消息队列的命令选项 IPC_STAT把msgid_ds结构中的数据设置为消息队列的当前关联值即用消息队列的当前关联值覆盖msgid_ds的值。 IPC_SET如果进程有足够的权限就把消息列队的当前关联值设置为msgid_ds结构中给出的值 IPC_RMID删除消息队列
其实对于IPC通信来说这些基本都是通用的~
3.例程
1服务端
#include stdio.h
#include string.h
#include sys/types.h
#include sys/ipc.h
#include sys/msg.h
#include pthread.h#define MSGQ_PATH ./
#define MSGQ_PRI 100typedef struct {long mtype;char mtext[256];
} MSGQ_T;int iMsgId 0;int main(int argc, char **argv)
{key_t msgkey 0;msgkey ftok(MSGQ_PATH, MSGQ_PRI);if (msgkey -1){printf(ftok error, pid:%d\n, getpid());return -1;}iMsgId msgget(msgkey, IPC_CREAT | 0644);if (iMsgId -1){printf(msgget error, pid:%d\n, getpid());return -1;}printf(msgget success, pid:%d, key:%d, msgid:%d\n, getpid(), msgkey, iMsgId);while (1){MSGQ_T msgBuf {0};int iMsgType 0;printf(input message type:\n);//输入消息类型scanf(%d, iMsgType);if (iMsgType 0){printf(message type 0, break\n);break;}char acBuf[256] {0};printf(input message to be send:\n);//输入消息信息scanf(%s, acBuf);msgBuf.mtype iMsgType;strncpy(msgBuf.mtext, acBuf, sizeof(msgBuf.mtext) - 1);msgsnd(iMsgId, msgBuf, sizeof(msgBuf), IPC_NOWAIT);printf(msgq:%d, send msgtype:%d, msgtext:%s \n, iMsgId, msgBuf.mtype, msgBuf.mtext);}msgctl(iMsgId, IPC_RMID, NULL);return 0;
}2客户端
#include stdio.h
#include string.h
#include sys/types.h
#include sys/ipc.h
#include sys/msg.h
#include pthread.h#define MSGQ_PATH ./
#define MSGQ_PRI 100typedef struct {long mtype;char mtext[256];
} MSGQ_T;int iMsgId 0;
pthread_t msgqRecvThread 0; void *msgqRecvThreadTask(void *arg)
{while (1){MSGQ_T msgBuf {0};int ret msgrcv(iMsgId, msgBuf, sizeof(msgBuf), 0, 0);if (ret 0){return NULL;}printf(msgq:%d, recv msgtype:%d, msgtext:%s, ret:%d \n, iMsgId, msgBuf.mtype, msgBuf.mtext, ret);}return NULL;
}int main(int argc, char **argv)
{key_t msgkey 0;msgkey ftok(MSGQ_PATH, MSGQ_PRI);if (msgkey -1){printf(ftok error, pid:%d\n, getpid());perror(....);return -1;}iMsgId msgget(msgkey, IPC_CREAT | 0644);if (iMsgId -1){printf(msgget error, pid:%d\n, getpid());perror(....);return -1;}printf(msgget success, pid:%d, key:%d, msgid:%d\n, getpid(), msgkey, iMsgId);pthread_create(msgqRecvThread, NULL, msgqRecvThreadTask, NULL);pthread_join(msgqRecvThread, NULL);return 0;
}可以通过指令分别编译客户端和服务端并执行
gcc server.c -o server -lpthread
gcc client.c -o client -lpthread
./server
./client在输入框输入消息后便可以在client观察到消息接收啦 此时输入ipcs -q后能看到创建的消息队列 这里我显示有两个消息队列因为上一个没有用msgctl删除。
当服务端和客户端程序都正常退出时调用msgctl则会正常删除消息队列在例程中的server端输入0即可