Linux进程学习之:消息队列

消息队列是一个链式队列

创建消息队列需要用到msgget函数,函数声明在“sys/msg.h”头文件里
函数声明如下:

int msgget(key_t key, int msgflg);

msgget 函数有两个参数,第一个是key,可以传入宏 IPC_PRIVATE或者有ftok函数生成的key值,如果传入的是IPC_PRIVATE宏,消息队列将用于具有亲缘关系的进程间通信,如果是ftok函数生成的key值,则可以用于非亲缘关系的进程间通信,第二个参数是生成的消息队列的读写权限,一般使用0777

下面贴一段生成消息队列的代码

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>

using namespace std;

int main() {
	int msgid = msgget(IPC_PRIVATE, 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

最后的system(“ipcs -q”)的作用是将系统中所有的消息的队列信息打印出来,包括刚才创建的消息队列

删除消息队列用的msgctl函数,同样声明在“sys/msg.h”头文件中
声明如下:

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

第一个参数是告诉函数要操作的msg对象的id,第二个参数是告诉函数要怎么做,因为我们要删除创建的消息队列,所以传入的IPC_RMID宏,第三个参数直接传入空就可以

贴一个创建之后又删除消息队列的问题

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>

using namespace std;

int main() {
	int msgid = msgget(IPC_PRIVATE, 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully, msgid = " << msgid <<endl;
	system("ipcs -q");
	// do something ...
	//delete msg
	int ret = msgctl(msgid, IPC_RMID, NULL);
	if (ret == -1) {
		cout << "delete msg failed ..." << endl;
		return -2;
	}
	else
		cout << "delete msg successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

接下来说消息队列的消息发送和接受,消息发送用的msgsnd函数,接受用的是msgrcv函数,两个函数声明分别如下:

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

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

1、msgsnd函数第一个参数是消息队列的id,第二个参数是一个指向用户自定义结构体的指针,不过这个结构体必须具有如下格式,第一个是参数类型,必须大于0,第二个是一个字符数组,大小可以自己定,不过也必须大于0:

struct msgbuf {
	 long mtype;       /* message type, must be > 0 */
     char mtext[1];    /* message data */
};

msgsnd函数的第三个参数是阻塞标志,0表示阻塞,还有其他的各种标志,可以自己去看

2、msgrcv函数和msgsnd函数的区别是只有第四个参数不一样,第四个参数是意思是当前队列消息的类型,需要明确才可以,如果输入的消息类型有误,程序就会被阻塞

接下来贴一个消息队列发送和接受消息的代码:

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>

using namespace std;

struct msgBuff {
	long type;
	char voltage[124];
};

int main() {
	int msgid = msgget(IPC_PRIVATE, 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully, msgid = " << msgid <<endl;
	system("ipcs -q");

	msgBuff sendBuf, rcvBuf;
	sendBuf.type = 100;
	cout << "please input message: ";
	cin >> sendBuf.voltage;
	msgsnd(msgid, (void *)&sendBuf, sizeof(sendBuf.voltage), 0);
	memset(rcvBuf.voltage, 0, sizeof(rcvBuf.voltage));
	int ret = msgrcv(msgid, (void *)&rcvBuf, sizeof(rcvBuf.voltage), 100, 0);
	if (ret == -1){
		cout << "read rcvBuf failed ..." << endl;
	}
	else {
		cout << "read rcvBuf successfully, rcvBuf = " << rcvBuf.voltage << endl;
	}
	//delete msg
	ret = msgctl(msgid, IPC_RMID, NULL);
	if (ret == -1) {
		cout << "delete msg failed ..." << endl;
		return -2;
	}
	else
		cout << "delete msg successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

运行以上代码,可以实现先往消息队列写入信息,接着从消息队列读取信息

接下来贴一个两个无亲缘关系的进程间通过消息队列通信的代码:

首先是写进程代码:

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>

using namespace std;

struct msgBuff {
	long type;
	char voltage[124];
};

int main() {
	int key = ftok("./a", 1);
	if (key < 0) {
		cout << "Create key failed" << endl;
		return -1;
	}
	else
		cout << "Create key successfully, key = " << key << endl;
	int msgid = msgget(key, IPC_CREAT | 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully, msgid = " << msgid <<endl;
	system("ipcs -q");

	msgBuff sendBuf;
	sendBuf.type = 100;
	while(1) {
		cout << "please input message: ";
		cin >> sendBuf.voltage;
		msgsnd(msgid, (void *)&sendBuf, sizeof(sendBuf.voltage), 0);
	}
	int ret = msgctl(msgid, IPC_RMID, NULL);
	if (ret == -1) {
		cout << "delete msg failed ..." << endl;
		return -2;
	}
	else
		cout << "delete msg successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

然后是读进程的代码

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>

using namespace std;

struct msgBuff {
	long type;
	char voltage[124];
};

int main() {
	int key = ftok("./a", 1);
	if (key < 0) {
		cout << "Create key failed" << endl;
		return -1;
	}
	else
		cout << "Create key successfully, key = " << key << endl;
	int msgid = msgget(key, IPC_CREAT | 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully, msgid = " << msgid <<endl;
	system("ipcs -q");

	msgBuff rcvBuf;
	while(1) {
		memset(rcvBuf.voltage, 0, sizeof(rcvBuf.voltage));
		msgrcv(msgid, (void *)&rcvBuf, sizeof(rcvBuf.voltage), 100, 0);
		cout << "read buff:" << rcvBuf.voltage << endl;
	}
	int ret = msgctl(msgid, IPC_RMID, NULL);
	if (ret == -1) {
		cout << "delete msg failed ..." << endl;
		return -2;
	}
	else
		cout << "delete msg successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

运行以上代码:可以实现在写进程写入消息,在读进程读取信息的功能

接下里贴一个可以在server进程和client进程双向通信的代码:

首先是server代码:

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <unistd.h>

using namespace std;

struct msgBuff {
	long type;
	char voltage[124];
};

int main() {
	int key = ftok("./a", 1);
	if (key < 0) {
		cout << "Create key failed" << endl;
		return -1;
	}
	else
		cout << "Create key successfully, key = " << key << endl;
	int msgid = msgget(key, IPC_CREAT | 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully, msgid = " << msgid <<endl;
	system("ipcs -q");

	int pid = fork();
	if (pid > 0) {
		msgBuff sendBuf;
		sendBuf.type = 100;
		while(1) {
			cout << "please input message: ";
			cin >> sendBuf.voltage;
			msgsnd(msgid, (void *)&sendBuf, sizeof(sendBuf.voltage), 0);
		}
	}
	else if (pid == 0){
		msgBuff rcvBuf;
		while(1) {
			memset(rcvBuf.voltage, 0, sizeof(rcvBuf.voltage));
			msgrcv(msgid, (void *)&rcvBuf, sizeof(rcvBuf.voltage), 200, 0);
			cout << "server recive: " << rcvBuf.voltage << endl;
		}
	}
	int ret = msgctl(msgid, IPC_RMID, NULL);
	if (ret == -1) {
		cout << "delete msg failed ..." << endl;
		return -2;
	}
	else
		cout << "delete msg successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

然后是client代码:

#include <iostream>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <unistd.h>

using namespace std;

struct msgBuff {
	long type;
	char voltage[124];
};

int main() {
	int key = ftok("./a", 1);
	if (key < 0) {
		cout << "Create key failed" << endl;
		return -1;
	}
	else
		cout << "Create key successfully, key = " << key << endl;
	int msgid = msgget(key, IPC_CREAT | 0777);
	if ( msgid == -1) {
		cout << "Create msgid failed ..." << endl;
		return -1;
	}
	else
		cout << "Create msgid successfully, msgid = " << msgid <<endl;
	system("ipcs -q");

	int pid = fork();
	if (pid > 0) {
		msgBuff sendBuf;
		sendBuf.type = 200;
		while(1) {
			cout << "please input message: ";
			cin >> sendBuf.voltage;
			msgsnd(msgid, (void *)&sendBuf, sizeof(sendBuf.voltage), 0);
		}
	}
	else if (pid == 0){
		msgBuff rcvBuf;
		while(1) {
			memset(rcvBuf.voltage, 0, sizeof(rcvBuf.voltage));
			msgrcv(msgid, (void *)&rcvBuf, sizeof(rcvBuf.voltage), 100, 0);
			cout << "server recive: " << rcvBuf.voltage << endl;
		}
	}
	int ret = msgctl(msgid, IPC_RMID, NULL);
	if (ret == -1) {
		cout << "delete msg failed ..." << endl;
		return -2;
	}
	else
		cout << "delete msg successfully ..." << endl;
	system("ipcs -q");
	return 0;
} 

运行以上代码,可以实现两个非亲缘关系进程间的双向通信,其中server进程写入消息的类型是100,读取消息的类型是200,而client进程读取消息的类型是100,写入消息的类型是200,这样双方就可以正常通信了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值