w_num=write(fd,w_buf,strlen(w_buf)); printf(\ if(strcmp(w_buf,\ } }
/****************************************************** * namedPipeDemo2.c * ******************************************************/ #include
#define FIFO_NAME \main() {
char r_buf[50]; int fd; int r_num;
// 若fifo已存在,则直接使用,否则创建它 if((mkfifo(FIFO_NAME,0777)<0)&&(errno!=EEXIST)) {
printf(\ exit(1); }
//以阻塞型只读方式打开fifo
fd=open(FIFO_NAME,O_RDONLY,0); if(fd==-1) {
printf(\ exit(1); }
// 通过键盘输入字符串,再将其写入fifo,直到输入\为止 while(1) {
memset(r_buf,0,sizeof(r_buf)); r_num=read(fd,r_buf,50); if(r_num==-1)
if(errno==EAGAIN)
printf(\
printf(\
if(strcmp(r_buf,\ sleep(1); }
unlink(FIFO_NAME);//删除fifo }
程序编译和运行结果:
<二>Linux消息队列通信机制
Linux系统中,若干个进程可以共享一个消息队列,系统允许其中的一个或多个进程向消息队列写入消息,同时也允许一个或多个进程从消息队列中读取消息,从而完成进程之间的信息交换,这种通信机制被称作消息队列通信机制。
1.数据结构
(1)消息缓冲区struct msgbuf
消息缓冲区是用来存放消息内容的结构体,而且这个结构体的第一个成员必须是一个大于0的长整数,表示对应消息的类型;不过,系统对结构体中其余成员的类型不做任何限制。include/linux/msg.h中给出的消息缓冲格式如下:
struct msgbuf{ /* 消息定义的参照格式 */
long mtype; /* 消息类型(大于0的长整数) */ char mtext[1]; /*消息正文*/ }; 应用程序员可以重新定义消息缓冲区结构体,其中,成员(mtext)不仅能定义为长度为1的字符数组,也可以定义成长度大于1的字符数组,或定义成其他的数据类型,Linux也允许消息正文的长度为0,即结构体中没有mtext域。
虽然,Linux没限定mtext的类型,但却限定了消息的长度,一个消息的最大长度由宏MSGMAX决定,根据版本的不同,其取值可能为8192或其他值。
(2)消息结构struct msg
消息队列中的每个消息节点中不仅包含了消息内容,还包含了一些其他信息,消息节点由消息结构来描述。include/linux/msg.h中给出的消息结构格式如下:
struct msg {
struct msg *msg_next; /*消息队列链接指针,指向队列中的下一条消息 */ long msg_type; /*消息类型,同struct msgbuf中的mtype*/ char *msg_spot; /* 消息正文的地址,指向msgbuf的消息正文 */
time_t msg_stime; /* 消息发送的时间 */ short msg_ts; /* 消息正文的大小 */ };
(3)IPC对象访问权限struct ipc_perm struct ipc_perm{
key_t key; /* IPC对象键值 */
ushort uid; /* owner euid and egid */ ushort gid;
ushort cuid; /* creator euid and egid */ ushort cgid;
ushort mode; /* 访问权限 */
ushort seq; /* slot usage sequence number,即IPC对象使用频率信息 */ };
其中:
key 是IPC对象(例如消息队列,共享存储器等)的键值,每个IPC对象都关联着
一个唯一的长整型的键值,不同的进程通过相同的键值可访问到同一个IPC对象。用户进程在创建IPC对象时可以指定key为某个大于0的整数,此时,需要用户自己保证该key值不与系统中存在的其他IPC键值相冲突。更常用的方式是通过函数调用ftok(pathname,proj_jd)请求系统为用户进程生成一个键值,其中的pathname是一个实际存在的文件的路径名,而且用户进程具有对该文件的访问权限,proj_jd是一个整数,但ftok只会用到其低8位的值(该值不能为0),只要路径名访问到的是同一个文件,而且proj_jd的低8位的值相同,则ftok()调用便将产生相同的键值;如果使用不同的文件路径名和proj_jd,虽然系统不能保证、但通常生成的键值是不同的。
mode 中给出了该IPC对象的访问权限,它可以是下列权限的组合: 访问权限 八进制整数 拥有者可读 0400 拥有者可写 0200 同组用户可读 0040 同组用户可写 0020 其他用户可读 0004 用户用户可写 0002 (3)消息队列结构体struct msqid_ds 系统中每个消息队列由一个struct msqid_ds类型的变量来描述,struct msqid_ds的格式如下:
struct msqid_ds {
struct ipc_perm msg_perm; /* 消息队列访问权限*/
struct msg *msg_first; /* 队列上第一条消息,即链表头*/ struct msg *msg_last; /* 队列中的最后一条消息,即链表尾 */ time_t msg_stime; /* 发送给队列的最后一条消息的时间 */
time_t msg_rtime; /* 从消息队列接收到最后一条消息的时间 */ time_t msg_ctime; /* 最后修改队列的时间*/
?
ushort msg_cbytes; /*队列上所有消息总的字节数 */
ushort msg_qnum; /*当前队列上消息的个数 */ ushort msg_qbytes; /* 队列允许的最大的字节数 */
ushort msg_lspid; /* 发送最后一条消息的进程的pid */ ushort msg_lrpid; /* 接收最后一条消息的进程的pid */ };
Linux还通过宏MSGMNB限定了一个消息队列的最大长度(队列中所有消息总的字节数)。
2.消息队列相关的系统调用
Linux提供了一组消息队列相关的系统调用来方便用户进行消息通信。 (1)msgget系统调用
①函数原型:
#include
int msgget(key_t key, int msgflg); ②参数: key key为0(IPC_PRIVATE),则创建一个新的消息队列;否则,key为
一个大于0的长整数,它对应于消息队列的键值,通常是通过ftok()函数生成的。
msgflg 对消息队列的访问权限和控制命令的组合。其中访问权限见“IPC
对象访问权限struct ipc_perm”部分的说明。而控制命令IPC_CREAT表示,如果key对应的消息队列不存在,则创建它;而IPC_EXCL必须与IPC_CREATT一起使用,它表示:如果key对应的消息队列不存在,则创建一个新的队列,否则返回-1。 ③功能: 如果IPC_CREAT单独使用,semget()为一个新创建的消息队列返回标
识数,或者返回具有相同键值的已存在消息队列标识数。如果IPC_EXCL与IPC_CREAT一起使用,要么创建一个新的队列并返回它的标识数,如果队列已存在,则返回-1。
④返回值: 成功,返回消息队列的标识数;出错,返回-1,同时将错误代码存放
在error中。对于新创建的消息队列,其msqid_ds结构成员变量的初值设置如下:
msg_qnum、msg_lspid、msg_lrpid设置为0;
msg_stime、msg_rtime设置为0; msg_ctime设置为当前时间;
msg_qbytes设成系统的限制值,即宏MSGMNB; msgflg的读写权限写入msg_perm.mode中;
msg_perm结构的uid和cuid成员被设置成当前进程的有效用ID,id和cuid成员被设置成当前进程的有效组ID。
⑤错误代码:EACCES:指定的消息队列已存在,但调用进程没有权限访问它
EEXIST:key指定的消息队列已存在,而msgflg中同时指定
IPC_CREAT和IPC_EXCL标志
ENOENT:key指定的消息队列不存在同时msgflg中没有指定
IPC_CREAT标志
ENOMEM:需要建立消息队列,但内存不足
ENOSPC:需要建立消息队列,但已达到系统的限制
(2)msgsnd系统调用
①函数原型:
#include
②参数:
msqid 消息队列的标识数
msgp 存放欲发送消息内容的消息缓冲区指针 msgsz 消息正文(而非整个消息结构)的长度
msgflg 0 ——消息队列满时,msgsnd将会阻塞 IPC_NOWAIT ——消息队列满时,msgsnd立即返回-1
MSG_NOERROR——消息正文长度超过msgsz字节时,不报错,而是
直接截去其中多余的部分,并只将前面的msgsz字节发送出去 ③功能: 在标识数为msqid的消息队列中添加一个消息,即向标识数为msqid
的消息队列发送一个消息。
④返回值: 消息发送成功,返回0;否则返回-1,同时error中存有错误代码 ⑤错误代码:EAGAIN ——参数msgflg设为IPC_NOWAIT,而消息队列已满
EACCESS——无权限写入消息队列
EFAULT ——参数msgp指向的地址无法访问
EIDRM ——标识符为msqid的消息队列已被删除
EINTR ——队列已满而处于阻塞的情况下,被信号唤醒
EINVAL ——无效的参数msqid、或消息类型type小于等于0、或
msgsz为负数或超过系统限制值MSGMAX
ENOMEM ——系统无足够内存空间存放msgbuf消息的副本
(3)msgrcv系统调用
①函数原型:
#include
ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long
msgtyp, int msgflg);
②参数:
msqid 消息队列的标识数
msgp 存放欲接收消息内容的消息缓冲区指针 msgsz 消息正文(而非整个消息结构)的长度 msg-typ 0 ——接收消息队列中的第一个消息 >0 ——接收第一个类型为msgtyp的消息
<0 ——接收第一个类型小于等于msgtyp的绝对值的消息 msgflg 0 ——没有可以接收的消息时,msgrcv阻塞