Linux C 消息队列实现简单的聊天功能

消息队列是提供一种带有数据标识的特殊管道,使得每一段被写入的数据都变成带标识的消息,读取该段消息的进程只要指定这个标识就可以正确地读取,而不会受到其他消息的干扰,。一个带标识的消息队列,就像并存的管道一样。这里主要介绍的是利用线程和消息队列,写两个进程,实现两个进程之间的聊天功能。

使用方法:

       发送者:首先要获取消息队列的ID号,然后将数据放入一个带有标识的结构体内,最后把消息发送到消息队列中。

       接收者:首先也是要获取到消息队列的ID号,然后把带有指定标识的数据读出来。

所需要用到的函数有:

#include <sys/types.h>

#include <sys/ipc.h>

 key_t ftok(const char *pathname, int proj_id);    第一个参数是一个已存在的路径,第二个参数可以自定义。只要两个进程中的两个参数是相同的,那么生成的key值也是相同的。

include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

返回值:成功则返回合法的key值;失败返回-1。

 

int msgget(key_t key, int msgflg);

第一个参数就是通过ftok函数生成的key值,第二个参数:

IPC_CREAT 如果在内核中不存在该队列,则创建它。 IPC_EXCL 当与IPC_CREAT一起使用时,如果队列早已存在则将出错。同时可以指定MSG的访问权限,如(0666);

返回值:成功则返回消息队列的ID,失败就返回-1;

如msgget(key,IPC_CREATE | 0666 )就表示,如果key值对应的消息队列不存在就创建,存在就获取消息队列的ID。权限只有读写,所以0777和0666是一样的。没有执行的权限。

发送和接收函数:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

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);

 

msgsnd();第一个参数为消息队列的ID号;第二个参数为要发送数据的存储区指针。

第三个参数为要接收数据的大小。

最有一个参数:msgflg

  MSG_NOERROR    若返回的消息比msgsz字节多,则消息会截断到msgsz字节,且不通知消息发送进程

IPC_NOWAIT 若消息队列中无对应类型的消息接收则立即返回

  1. 阻塞等待直至接收到一条相应类型的消息为止

一般都写0,阻塞等待。

msgrcv()函数与magsnd()函数的参数相同,除了mystype。这个是接收函数独有的。代表要接收消息的标识。

发送消息的时候,消息必须要被组织为以下的形态:

struct massage

{

       long type;       //消息的标识

       char text[80];     //消息的正文,大小可自定义。

 

};

发送的消息必须要有一个标识在前面,后面的数据则没有要求。

msgctl()

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

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

第一个参数为消息队列的ID;

第二个参数:

IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。

    IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值

IPC_RMID:删除消息队列

IPC_INFO:获得当前系统中MSG的限制值信息

MSG_INFO:获得当前系统中MSG的相关资源消耗的信息

MSG_STAT:获取系统中所有消息队列的信息。

最后一个参数为相关结构体缓存区。

具体代码如下。需要注意的是,发送数据的函数需要写在主线程中,接收函数写在创建线程中,这样才能做到随时进行数据的传输。分别编译a.c和b.c,然后同时运行两个可执行文件就可以了。编译时记得链接线程库。两个程序的主要区别就在于接收和发送的信息标识。

a.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
#include<stdlib.h>
#include <pthread.h> 
struct massage
{
	long type;
	char text[80];

};
struct massage buf;

int msgid;

void *recive(void *p)
{

	struct massage buf2;
	
	while (1)
	{
		bzero(&buf2,sizeof(buf2));
		msgrcv(msgid,&buf2,sizeof(buf2),100,0);   //阻塞等待mytype为100的值
		printf("%s",buf2.text);
	}

	return 0;
}


int main()
{
	key_t key=ftok("/home/rchris520/haha",300);
	msgid=msgget(key, IPC_CREAT|0666);
	
	pthread_t pid;
	pthread_create(&pid,NULL,recive,NULL);    //创建一个线程运行接收函数
	
	while(1)
	{
		bzero(&buf,sizeof(buf));
		buf.type = 200;
		fgets(buf.text,sizeof(buf.text),stdin);
		
		msgsnd(msgid,&buf,sizeof(buf),0);
		
	}
	
	msgctl(msgid, IPC_RMID, 0);
	return 0;
}

b.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
#include<stdlib.h>
#include <pthread.h> 
struct massage
{
	long type;
	char text[80];

};
struct massage buf;

int msgid;


void *recive(void *p)
{
	struct massage buf2;
	while(1)
	
	{
		bzero(&buf2,sizeof(buf2));
		msgrcv(msgid,&buf2,sizeof(buf2),200,0);   //阻塞等待mytype为200的值
		printf("%s",buf2.text);
	}
	
	
	return 0;
}
int main()
{
	key_t key=ftok("/home/rchris520/haha",300);
	msgid=msgget(key, IPC_CREAT|0666);    //  创建消息队列

	
	pthread_t pid;
	pthread_create(&pid,NULL,recive,NULL);   //    创建线程
	
	
	
	while(1)
	{
		bzero(&buf,sizeof(buf));
		buf.type=100;
		fgets(buf.text,sizeof(buf.text),stdin);    //主线程输入消息
		
		msgsnd(msgid,&buf,sizeof(buf),0);  //  发送消息
	}
	
	
	msgctl(msgid, IPC_RMID, 0);   
	return 0;

}

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值