1.匿名管道和有名管道
匿名管道
匿名管道是一种进程之间进行单向通信的方式,由于其通信只是单方向的,所以起有以下缺点:
1.通信只是单方向的,通信太局限
2.其缓冲区大小是一定的,缓冲区满了之后就无法继续再写入数据。
3.通过管道传输的只能是无格式的字节流。
4.只能用于具有亲缘关系的进程之间,如父子进程,兄弟进程。
有名管道
顾名思义,有名管道就是拥有名字的管道,当然,他与匿名管道的区别就是他拥有了名字,与此同时,他也克服了匿名管道的部分缺陷与不足,如它可以在任意两个进程之间进行通信,当然也只能局限于单向的。
匿名管道的创建和使用
#include<unistd.h>
int pipe(int pipefd[2]);
函数参数pipefd[2]为整形的数组,可作为一般的文件描述符使用,管道读端用pipefd[0]表示,管道写端用pipefd[1]表示,通过close函数关闭读写端,创建成功,则返回0,失败返回-1,管道创建后,就可以作为一般的文件对待,对一般的I/O操作同样适用,如read,write等(一般通过fork函数创建父子进程,在父子进程间通信)。
有名管道的创建和使用
用于创建管道的函数有两个分别为:mknod和mkfifo,这两个函数原型分别为:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);
说明:pathname指的是创建的有名管道的全文件路径名,mode为创建的有名管道的模式,既存权限,一般都为S_IFIFO|0666,dev指的是设备值(可选),该值取决创建的文件的种类,只有在创建设备文件时才用得到。函数调用成功反或0失败返回-1
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
说明:pathname指的是创建的有名管道的全文件路径名,mode为创建有名管道的模式,既存权限,一般都为S_IFIFO|0666 使用mknod创建有名管道
使用mknod创建有名管道:
umask(0);
if(mknod(“fifo”,S_IFIFO|0666))
{
perror(“mkfifo error!”);
exit(0);
}
使用mknod创建有名管道:
umask(0);
if(mkfifo(“fifo”,S_IFIFO|0666))
{
perror(“mkfifo error !”);
exit(0);
}
说明:创建管道时,要特别注意,pathname必须是你有读写权限的路径,因为管道实质上就是一些特殊的文件,管道创建时自动创建,结束后自动删除。还有关于mode,必须在前面使用umask修饰,表面上权限是由mode决定的,但真正权限是mode&~umask得到的。还有,有名管道在进行读写时,得像文件一样先打开,读写完毕后关闭。
2.消息队列和有名管道
与命名管道相比,消息队列的优势在于,1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。
1)消息队列的创建
int msgget(key_t, key, int msgflg);
与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。
它返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1
2)消息队列的发送
该函数用来把消息添加到消息队列中。它的原型为:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
msgid是由msgget函数返回的消息队列标识符。
msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体,接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:
struct my_message{
long int message_type;
/* The data you wish to transfer*/
};
msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。
msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。
如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1
3)消息队列的接收
该函数用来从一个消息队列获取消息,它的原型为
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
msgid, msg_ptr, msg_st的作用也函数msgsnd函数的一样。
msgtype可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。
msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情。
调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1.
注意:调用msgrcv函数后msgid会变为0,需要调用msgget重新获取msgid,否则msgrcv会报错。
4)控制消息队列
msgctl函数
该函数用来控制消息队列,它与共享内存的shmctl函数相似,它的原型为:
int msgctl(int msgid, int command, struct msgid_ds *buf);
command是将要采取的动作,它可以取3个值,
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET :如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列
buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:
struct msgid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};
成功时返回0,失败时返回-1.