本周学习了第八章的主要内容主要包括两大部分分别为:
一、有名管道FIFO
1.有名管道说明
- 定义:有名管道的出现突破了只能用于具有亲缘关系的进程之间,这就大大地限制了管道的使用限制,它可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出, 并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作, 使用非常方便。
- 注意:FIFO 是严格地遵循先进先出规则的,对管道及 FIFO 的读总是从开始 处返回数据,对它们的写则把数据添加到末尾,它们不支持如 lseek()等文件定位操作。 有名管道的创建可以使用函数 mkfifo(),该函数类似文件中的 open()操作,可以指定管道的路径和打开的模式。
- 对阻塞打开和非阻 塞打开的读写进行讨论:
(1)对于读进程。
若该管道是阻塞打开,且当前 FIFO 内没有数据,则对读进程而言将一直阻塞到有数据写入。
若该管道是非阻塞打开,则不论 FIFO 内是否有数据,读进程都会立即执行读操作。即如果 FIFO 内没有数据,则读函数将立刻返回 0。
(2)对于写进程。
若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。
若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。
2.mkfifo()函数格式
- mkfifo()函数语法要点
- FIFO 相关的出错信息
3.使用实例
- 以下是写管道的程序:
/* fifo_write.c */ #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #define MYFIFO "/tmp/myfifo" /* 有名管道文件名*/ #define MAX_BUFFER_SIZE PIPE_BUF /*定义在于 limits.h 中*/ int main(int argc, char * argv[]) /*参数为即将写入的字符串*/ { int fd; char buff[MAX_BUFFER_SIZE]; int nwrite; if(argc <= 1) { printf("Usage: ./fifo_write string\n"); exit(1); } sscanf(argv[1], "%s", buff); /* 以只写阻塞方式打开 FIFO 管道 */ fd = open(MYFIFO, O_WRONLY); if (fd == -1) { printf("Open fifo file error\n"); exit(1); } /*向管道中写入字符串*/ if ((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0) { printf("Write ‘%s‘ to FIFO\n", buff); } close(fd); exit(0); }
- 以下是读管道程序:
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #define MYFIFO "/tmp/myfifo" /* 有名管道文件名*/ #define MAX_BUFFER_SIZE PIPE_BUF /*定义在于 limits.h 中*/ int main() { char buff[MAX_BUFFER_SIZE]; int fd; int nread; /* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建*/ if (access(MYFIFO, F_OK) == -1) { if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST)) { printf("Cannot create fifo file\n"); exit(1); } } /* 以只读阻塞方式打开有名管道 */ fd = open(MYFIFO, O_RDONLY); if (fd == -1) { printf("Open fifo file error\n"); exit(1); } while (1) { memset(buff, 0, sizeof(buff)); if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0) { printf("Read ‘%s‘ from FIFO\n", buff); } } close(fd); exit(0); }
二、消息队列
1. 消息队列概述
- 顾名思义,消息队列就是一些消息的列表。用户可以从消息队列中添加消息和读取消息等。从这点上看, 消息队列具有一定的 FIFO 特性,但是它可以实现消息的随机查询,比 FIFO 具有更大的优势。同时,这些消息又是存在于内核中的,由“队列 ID”来标识。
2. 消息队列的应用
(1)函数说明
消息队列的实现包括创建或打开消息队列、添加消息、读取消息和控制消息队列这 4 种操作。其中创建 或打开消息队列使用的函数是 msgget(),这里创建的消息队列的数量会受到系统消息队列数量的限制; 添加消息使用的函数是 msgsnd()函数,它把消息添加到已打开的消息队列末尾;读取消息使用的函数是 msgrcv(),它把消息从消息队列中取走,与 FIFO 不同的是,这里可以指定取走某一条消息;最后控制消息队列使用的函数是 msgctl(),它可以完成多项功能。
(2)函数格式
- msgget()函数的语法要点。
- msgsnd()函数的语法要点。
3.使用实例
- 消息队列发送端的代码:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define BUFFER_SIZE 512 struct message { long msg_type; char msg_text[BUFFER_SIZE]; }; int main() { int qid; key_t key; struct message msg; /*根据不同的路径和关键字产生标准的 key*/ if ((key = ftok(".", ‘a‘)) == -1) { perror("ftok"); exit(1); } /*创建消息队列*/ if ((qid = msgget(key, IPC_CREAT|0666)) == -1) { perror("msgget"); exit(1); } printf("Open queue %d\n",qid); while(1) { printf("Enter some message to the queue:"); if ((fgets(msg.msg_text, BUFFER_SIZE, stdin)) == NULL) { puts("no message"); exit(1); } msg.msg_type = getpid(); /*添加消息到消息队列*/ if ((msgsnd(qid, &msg, strlen(msg.msg_text), 0)) < 0) { perror("message posted"); exit(1); } if (strncmp(msg.msg_text, "quit", 4) == 0) { break; } } exit(0); }
- 以下是消息队列接收端
#include <sys/types.h>#include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define BUFFER_SIZE 512 struct message { long msg_type; char msg_text[BUFFER_SIZE]; }; int main() { int qid; key_t key; struct message msg; /*根据不同的路径和关键字产生标准的 key*/ if ((key = ftok(".", ‘a‘)) == -1) { perror("ftok"); exit(1); } /*创建消息队列*/ if ((qid = msgget(key, IPC_CREAT|0666)) == -1) { perror("msgget"); exit(1); } printf("Open queue %d\n", qid); do { /*读取消息队列*/ memset(msg.msg_text, 0, BUFFER_SIZE); if (msgrcv(qid, (void*)&msg, BUFFER_SIZE, 0, 0) < 0) { perror("msgrcv"); exit(1); } printf("The message from process %d : %s", msg.msg_type, msg.msg_text); } while(strncmp(msg.msg_text, "quit", 4)); /*从系统内核中移走消息队列 */ if ((msgctl(qid, IPC_RMID, NULL)) < 0) { perror("msgctl"); exit(1); } exit(0); }
时间: 2024-10-13 03:09:31