进程"/>
Linux进程
进程的语言
进程间的通信 (IPC) 方式,总归起来主要有如下这些:
1,无名管道 (PIPE) 和有名管道 (FIFO) 。
2,信号 (signal) 。
3,system V-IPC 之共享内存。
4,system V-IPC 之消息队列。
5,system V-IPC 之信号量。
6,套接字
这些通信方式各有各的特点,无名管道是最简单的常用于一对一的亲缘进程间通信的方
式,有名管道存在于文件系统之中,提供写入原子性特征,信号是唯一一种异步通信方式, 共享内存的效率最高,但是要结合信号量等同步互斥机制一起使用,消息队列提供一种带简 单消息标识的通信方式,套接字是一种更为宽泛意义上的进程间通信方式——它允许进程间 跨网络。
无名管道
常说的管道通常指无名管道 (PIPE) 或者有名管道 (FIFO) ,但实际上套接字也都是 管道。这里先把 PIPE 和 FIFO 的相关接口摆出:
功能
创建无名管道:PIPE
头文件
#include <unistd.h>
原型
int pipe(int pipefd[2]);
参数
pipefd
一个至少具有 2 个 int 型数据的数组,用来存放 PIPE 的读写端描述符
返回值
成功
0
失败
- 1
备注
无
功能
创建有名管道:FIFO
头文件
#include <sys/types.h>
#include <sys/stat.h>
原型
int mkfifo(const char *pathname, mode_t mode);
参数
pathname
FIFO 的文件名
mode
文件权限
返回值
成功
0
失败
- 1
备注
无
表 创建无名管道和有名管道的函数接口规范
先来看看 PIPE 。既然叫管道,那么可以想象他就像一根水管,连接两个进程,一个进 程要给另一个进程数据,就好像将水灌进管道一样,另一方就可以读取出来了,反过来也一 样。这是我们对 PIPE 最简单的感官认识。
先来罗列 PIPE 的特征:
1,没有名字,因此无法使用 open( )。
2,只能用于亲缘进程间 (比如父子进程、兄弟进程、祖孙进程……) 通信。
3,半双工工作方式:读写端分开,一个只能用来读,一个只能用来写。
4,写入操作不具有原子性,因此只能用于一对一的简单通信情形。
5,不能使用 lseek( )来定位:因为他们的数据不能像普通文件那样按块的方式存储在硬盘,而是像一个看不见源头的水龙,无法定位。
6、管道都不可以在共享文件中创建。
PIPE的缺点是:
他对写操作不做任何保护!即:假如有多个进程或线程同时对 PIPE 进行写操作,那么这些数据很有可能会相互践踏。因此,PIPE 只能用于一对一的亲缘进程通信。
无名管道示例代码如下:
#include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <string.h>int main() {int fd[2];int ret = pipe(fd);if(-1 == ret){perror("open pipe failed");return -1;}char buf[128];char msg[128];pid_t pid = fork();if(pid == 0){read(fd[0],msg,sizeof(msg)-1);//阻塞等待printf("[from child]%s\n",msg);}if(pid > 0){fgets(buf,sizeof(buf),stdin);write(fd[1],buf,strlen(buf));}}
上述代码中,创建一个无名管道父进程负责管道的发送端,子进程负责管道的接受端。
有名管道
任何事物的优缺点都是相对的,PIPE 很简单,同时也适用场景比较单一,性能比较弱, 限制条件比较多,如果要在任意进程间通信,并且保证写入有原子性,那么你可以使用 FIFO --- 一种更加强大的管道。
有名管道 FIFO 的特征:
1,有名字,存储于普通文件系统之中。
2,任何具有相应权限的进程都可以使用 open( )来获取 FIFO 的文件描述符。
3,跟普通文件一样:使用统一的 read( )/write( )来读写。
4,跟普通文件不同:不能使用 lseek( )来定位,原因同 PIPE。
5,具有写入原子性,支持多写者同时进行写操作而数据不会互相践踏。
6,First In First Out,最先被写入 FIFO 的数据,最先被读出来。
代码示例:写端
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <fcntl.h> //ioctl() #include <unistd.h>#define PATH "/home/xwq/ls" //一个宏定义内容是管道存放路径int main() {//unlink(PATH); // 如果fifo文件已存在,则先删除// 判断文件是否存在,如果不存在,则创建fifo文件if (access(PATH, F_OK) != 0){int ret = mkfifo(PATH, 0777);if (ret == -1){perror("creat myfifo failed");return -1;}}// 打开fifo文件,返回文件描述符int fifo_fd = open(PATH, O_RDWR); //权限if (-1 == fifo_fd){perror("open myfifo failed");return -1;}pid_t pid = fork(); // 创建子进程char buf[128];while (1){memset(buf, 0, sizeof(buf)); //清零// 从标准输入获取用户输入fgets(buf, sizeof(buf), stdin);// 将用户输入写入fifo文件write(fifo_fd, buf, strlen(buf));if (strcmp(buf, "exit\n") == 0){break;}}// 关闭文件描述符close(fifo_fd);return 0; }
读端
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <fcntl.h> //ioctl() #include <unistd.h>#define PATH "/home/xwq/myfifo"int main() {if(access(PATH,F_OK) != 0)//判断文件是否存在{int ret = mkfifo(PATH, 0777); // 创建命名管道if(ret == -1){perror("creat myfifo failed");return -1;}}int fifo_fd = open(PATH,O_RDWR); // 打开命名管道if(-1 == fifo_fd){perror("open myfifo failed");return -1;}char buf[128];while(1){memset(buf, 0, sizeof(buf)); // 清空buf数组read(fifo_fd, buf, sizeof(buf)-1); // 读取命名管道中的数据printf("[from jack] %s",buf); //输出接收到的信息if(strcmp(buf,"exit\n") == 0) // 如果接收到了退出信号,则退出循环 strcmp 字符串的等式判断{break;}}close(fifo_fd); // 关闭命名管道return 0;}
上述代码中
所谓写者:持有文件可写权限的描述符的进程。
所谓读者:持有文件可读权限的描述符的进程
access函数通常用于检查文件或目录是否存在以及是否具有特定权限。它接受文件路径和权限参数,并返回一个整数值,表示访问权限的状态。常见的返回值包括0(表示有访问权限)、-1(表示访问被拒绝)和其他错误代码。
FIFO 跟 PIPE 区别的还有一个最大的不同点在于:FIFO 具有一种所谓写入原子性的特
征,这种特征使得我们可以同时对 FIFO 进行写操作而不怕数据遭受破坏,一个典型应用是 Linux 的日志系统。
日志
日志示例代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <fcntl.h>//ioctl() #include <unistd.h> #include <time.h>#define PATH "/home/gec/myfifo"int main() {if(access(PATH,F_OK) != 0){int ret = mkfifo(PATH,0777);if(-1 == ret){perror("creat\n");return -1;}}int fifo_fd = open(PATH, O_WRONLY);if(-1 == fifo_fd){perror("open\n");return -1;}char buf[128];while(1){memset(buf,0,sizeof(buf));time_t curTime;sleep(1);curTime++;time(&curTime);//把时间转换为当前的时间char *curDate = ctime(&curTime);//把时间转换为char *字符串snprintf(buf,sizeof(buf),"[%d]%s",getpid(),curDate);printf("%s\n",buf);write(fifo_fd,buf,strlen(buf));}close(fifo_fd);}
写端
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <fcntl.h>//ioctl() #include <unistd.h>#define PATH "/home/gec/myfifo"int main() {if(access(PATH,F_OK) != 0)//判断文件是否存在{int ret = mkfifo(PATH, 0777);if(ret == -1){perror("creat myfifo failed");return -1;}}int fifo_fd = open(PATH,O_RDWR);if(-1 == fifo_fd){perror("open myfifo failed");return -1;}int fd = open("./rizhi.txt", O_RDWR | O_CREAT ,0777);if(-1 == fd){perror("open fd failed");return -1;}char buf[128];while(1){memset(buf, 0, sizeof(buf));read(fifo_fd, buf, sizeof(buf)-1);write(fd,buf,strlen(buf));//printf("[from jack] %s",buf);}close(fifo_fd);close(fd);return 0;}
更多推荐
Linux进程
发布评论