IPC对象,既我们所说的进程间通信,下面就来总结一下都有哪些方式以及怎么使用。
一 消息队列
1 消息队列的创建:
int msgget(key_t key, int msgflg);
功能:获取指定的key值的消息队列ID
参数:
@key
<1>IPC_PRIVATE:每次都会创建一个新的消息队列 [用在亲缘关系的进程间痛惜]
<2>ftok函数获的key [用在非亲缘关系进程间通信]
key_t ftok(const char *pathname, int proj_id);
功能:根据文件的ID 和 proj_id的低8bit产生一个key值
参数:
@pathname 一个文件名
@proj_id 一个字符
返回值:
成功返回key,失败返回-1
@msgflg :IPC_CREAT , IPC_EXCL
IPC_CREAT | 0666 -> 如果执行的key的消息队列不存在,则创建新的消息队列
IPC_CREAT | IPC_EXCL -> 判别指定key的消息队列是否存在,如果存在则报错
返回值:
成功返回消息队列ID,失败返回-1
2 添加消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
@msqid 消息队列的ID
@msgp 消息存放的地址
@msgsz 消息正文的大小
@msgflg 0:阻塞的方式调用 IPC_NOWAIT:非阻塞的方式调用
返回值:成功返回0,失败返回-1
消息结构体:
typedef struct
{
//第一个字段必须是消息类型
long type;
//消息正文部分
char buf[1024];
int pid;
..
}MSG;
//计算消息正文的大小
#define MTXT_SIZE (sizeof(MSG) - sizeof(long))
3 接受消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
@msqid 消息队列的ID
@msgp 消息存放的地址
@msgsz 消息正文的大小
@msgtyp 消息的类型
@msgflg 0:阻塞的方式调用 IPC_NOWAIT:非阻塞的方式调用
返回值:成功返回接受的消息正文大小,失败返回-1
我们可以通过下面的一个例子来了解消息队列的具体通信方式:
就是对于不是亲缘关系的两个进程A B进行通信:
都可以实现双方的收发:
#include <head.h>
//the struct of mesage
typedef struct
{
long type;
char buf[1024];
int pid;
}MSG;
#define MTXT_SIZE (sizeof(MSG) - sizeof(long))
#define TYPEA 100
#define TYPEB 200
// ./a.out filename
int main(int argc, const char *argv[])
{
if(argc < 2)
{
fprintf(stderr,"Usage : %s argv[1]\n",argv[0]);
exit(EXIT_FAILURE);
}
int key;
key = ftok(argv[1],'A'); //get key
if(key < 0)
{
fprintf(stderr,"Fail to ftok \n",strerror(errno));
exit(EXIT_FAILURE);
}
printf("key : %#x\n",key);
int msg_id;
msg_id = msgget(key,IPC_CREAT | 0666); //create mesage queue
if(msg_id < 0)
{
perror("Fail to msgget");
exit(EXIT_FAILURE);
}
printf("msg_id :%d\n",msg_id);
MSG msg;
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("Fail to fork");
exit(EXIT_FAILURE);
}
if(pid == 0)
{
while(1)
{
ssize_t ret;
ret = msgrcv(msg_id,&msg,MTXT_SIZE,TYPEA,0);
if(ret < 0)
{
perror("Fail to msgrcv");
exit(EXIT_FAILURE);
}
printf("TYPE :%ld\n",msg.type);
printf("PID :%d\n",msg.pid);
printf("MTXT :%s\n",msg.buf);
if(strncmp(msg.buf,"quit",4) == 0)
{
kill(getppid(),SIGUSR1);
break;
}
}
}
if(pid > 0)
{
msg.pid = getpid();
msg.type = TYPEB;
while(1)
{
printf(">");
fgets(msg.buf,sizeof(msg.buf),stdin);
msg.buf[strlen(msg.buf)-1] = '\0';
if(msgsnd(msg_id,&msg,MTXT_SIZE,0)< 0)
{
perror("Fail to msgsnd");
exit(EXIT_FAILURE);
}
if(strncmp(msg.buf,"quit",4) == 0)
{
kill(getpid(),SIGUSR1);//使退出一个时全都退出进程
break;
}
}
}
return 0;
}
另一个:
#include <head.h>
//the struct of mesage
typedef struct
{
long type;
char buf[1024];
int pid;
}MSG;
#define MTXT_SIZE (sizeof(MSG) - sizeof(long))
#define TYPEA 200
#define TYPEB 100
// ./a.out filename
int main(int argc, const char *argv[])
{
MSG msg;
int key;
int msg_id;
pid_t pid;
if(argc < 2)
{
fprintf(stderr,"Usage : %s argv[1]\n",argv[0]);
exit(EXIT_FAILURE);
}
key = ftok(argv[1],'A'); //get key
if(key < 0)
{
fprintf(stderr,"Fail to ftok \n",strerror(errno));
exit(EXIT_FAILURE);
}
printf("key : %#x\n",key);
msg_id = msgget(key,IPC_CREAT | 0666); //create mesage queue
if(msg_id < 0)
{
perror("Fail to msgget");
exit(EXIT_FAILURE);
}
printf("msg_id :%d\n",msg_id);
pid = fork();
if(pid < 0)
{
perror("Fail to fork");
exit(EXIT_FAILURE);
}
if(pid == 0)
{
while(1)
{
ssize_t ret;
ret = msgrcv(msg_id,&msg,MTXT_SIZE,TYPEA,0);
if(ret < 0)
{
perror("Fail to msgrcv");
exit(EXIT_FAILURE);
}
printf("TYPE :%ld\n",msg.type);
printf("PID :%d\n",msg.pid);
printf("MTXT :%s\n",msg.buf);
if(strncmp(msg.buf,"quit",4) == 0)
{
kill(getppid(),SIGUSR1);
break;
}
}
}
if(pid > 0)
{
msg.pid = getpid();
msg.type = TYPEB;
while(1)
{
printf(">");
fgets(msg.buf,sizeof(msg.buf),stdin);
msg.buf[strlen(msg.buf)-1] = '\0';
if(msgsnd(msg_id,&msg,MTXT_SIZE,0)< 0)
{
perror("Fail to msgsnd");
exit(EXIT_FAILURE);
}
if(strncmp(msg.buf,"quit",4) == 0)
{
kill(getpid(),SIGUSR1);
if(msgctl(msg_id,IPC_RMID,NULL) < 0)
{
perror("Fail to msgctl");
exit(EXIT_FAILURE);
}
break;
}
}
}
return 0;
}
好了,上面就是有关消息队列的相关了解。