Linux进程10-有名管道概述、创建、读写操作、两个管道进程间通信、读写规律(只读、只写、读写区别)、设置阻塞/非阻塞
目录
1.有名管道
1.1概述
1.2与无名管道的差异
2.有名管道的创建
2.1 直接用shell命令创建有名管道
2.2使用mkfifo函数创建有名管道
3.有名管道读写操作
3.1单次读写
3.2多次读写
4.有名管道进程间通信
4.1回合制通信
4.2父子进程通信
5.有名管道读写规律(默认阻塞)
5.1读写端都存在,只读不写
5.2读写端都存在,只写不读
5.3 在一个进程中,只有读端,没有写端
5.4 在一个进程中,只有写端,没有读端
5.5 一个进程只读,一个进程只写
5.5.1两个进程,一个只读一个只写
5.5.2两个进程,一个只读一个只写,关闭写端
5.5.3两个进程,一个只读一个只写,关闭读端
5.6读写端都存在,默认阻塞
6.有名管道的读写规律(设置:非阻塞)
6.1只读方式打开(设置非阻塞)
6.2只写方式打开(设置非阻塞)
6.3读写方式打开(设置非阻塞)
1.有名管道
1.1概述
1.2与无名管道的差异
特性 | 有名管道 | 无名管道 |
---|---|---|
进程关系 | 允许无亲缘关系的进程通信 | 仅限有亲缘关系的进程 |
存在形式 | 文件系统中的 FIFO 文件 | 内存中的临时缓冲区 |
持久性 | 文件删除前一直存在 | 进程终止后自动销毁 |
创建方式 | mkfifo() /mkfifoat() | pipe() |
2.有名管道的创建
2.1 直接用shell命令创建有名管道
在终端直接用shell命令mkfifo创建有名管道
使用ls -l命令查看 myfifo1文件的类型为p,表示该文件是一个管道文件。
2.2使用mkfifo函数创建有名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道,产生一个本地文件系统可见的文件pathname参数:
pathname:有名管道创建后生成的文件,可以带路径
mode:管道文件的权限,一般通过八进制数设置即可,例如0664返回值:成功:0失败:‐1
(1)管道文件不存在
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo("fifo_file", 0664) == -1){perror("fail to mkfifo");exit(1);}return 0;
}
运行结果:管道文件不存在,创建了fifo_file管道文件
(2)管道文件存在
再次运行程序,报错:文件已存在
程序修改:如果错误码不是 EEXIST,继续运行
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo("fifo_file", 0664) == -1){printf("errno = %d\n", errno);//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}return 0;
}
运行结果:
终端输入: sudo find /usr/include -name "errno-base.h" ,查找错误码文件
3.有名管道读写操作
由于有名管道在本地创建了一个管道文件,所以系统调用的IO函数基本都可以对有名管道
进行操作, 但是不能使用lseek修改管道文件的偏移量.
注意:有名管道创建的本地的文件只是起到标识作用,真正有名管道实现进程间通信还是在
内核空间开辟内存,所以本地产生的文件只是一个标识,没有其他作用,对本地管道文件的
操作实质就是对内核空间的操作。
3.1单次读写
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>#define FIFONAME "fifo_file" //管道文件int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo(FIFONAME, 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);}}//对有名管道进行读写操作//通过open函数打开管道文件并得到文件描述符int fd;fd = open(FIFONAME, O_RDWR);//权限:可读可写if(fd == -1){perror("fail to open");exit(1);}//通过write函数向管道中写入数据if(write(fd, "hello world", strlen("hello world")) == -1){perror("fail to write");exit(1);}//通过read函数读取管道中的数据char buf[32] = "";if(read(fd, buf, sizeof(buf)) == -1){perror("fail to read");exit(1);}printf("buf = [%s]\n", buf);//使用close函数关闭文件描述符close(fd);return 0;
}
运行结果:
3.2多次读写
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>#define FIFONAME "fifo_file"int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo(FIFONAME, 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);}}//对有名管道进行操作//管道后写入的数据会保存在之前写入数据的后面,不会替换//如果管道中没有数据了,读操作会阻塞//通过open函数打开管道文件并得到文件描述符int fd;fd = open(FIFONAME, O_RDWR);if(fd == -1){perror("fail to open");exit(1);}//第一次 通过write函数向管道中写入数据if(write(fd, "hello world", strlen("hello world")) == -1){perror("fail to write");exit(1);}//第2次 通过write函数向管道中写入数据if(write(fd, "nihao", strlen("nihao")) == -1){perror("fail to write");exit(1);}//第1次 通过read函数读取管道中的数据,已将管道中的所有数据读取char buf[32] = "";if(read(fd, buf, sizeof(buf)) == -1){perror("fail to read");exit(1);}printf("第1次读取 buf = [%s]\n", buf);//第2次 通过read函数读取管道中的数据,管道中已无数据if(read(fd, buf, sizeof(buf)) == -1){perror("fail to read");exit(1);}printf("第2次读取 buf = [%s]\n", buf);//使用close函数关闭文件描述符close(fd);return 0;
}
运行结果:第1次 通过read函数读取管道中的数据,已将管道中的所有数据读取;第2次 通过read函数读取管道中的数据,管道中已无数据,read函数执行阻塞;
4.有名管道进程间通信
4.1回合制通信
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{//如果没有创建有名管道,则创建有名管道//为了实现两个进程都可以收发数据,所以需要创建两个有名管道if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);//退出}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//打开两个有名管道并得到文件描述符//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,//另一个接收方正好相反int fd_w, fd_r;if((fd_w = open("myfifo1", O_WRONLY)) == -1){perror("fail to open");exit(1);}if((fd_r = open("myfifo2", O_RDONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;while(1){printf("发送端运行中:请输入向接收端要发送的内容\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据if((bytes = write(fd_w, buf, sizeof(buf))) == -1){perror("fail to write");exit(1);}//发送端从myfifo2读取数据if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1){perror("fail to read");exit(1);}printf("发送端:读取到接收端发送的数据: %s\n", buf1);memset(buf, 0, sizeof(buf));//buf清0memset(buf1, 0, sizeof(buf1));}return 0;
}
接收端程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//fd_w:向管道myfifo2写入数据,fd_r:从管道myfifo1读取数据,int fd_w, fd_r;if((fd_r = open("myfifo1", O_RDONLY)) == -1){perror("fail to open");exit(1);}if((fd_w = open("myfifo2", O_WRONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;while(1){//recv进程负责从myfifo1中读取数据,接着将终端输入数据写入myfifo2//接收端:读取myfifo1写入数据if((bytes = read(fd_r, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("接收端:读取到发送端发送的数据: %s\n", buf);printf("接收端运行中,清输入要发送的内容: \n");fgets(buf1, sizeof(buf1), stdin);buf1[strlen(buf1) - 1] = '\0';//接收端:向myfifo2写入数据,发送端:myfifo1会读取写入的数据if((bytes = write(fd_w, buf1, sizeof(buf1))) == -1){perror("fail to write");exit(1);}memset(buf, 0, sizeof(buf));//buf清0memset(buf1, 0, sizeof(buf1));}return 0;
}
运行结果:打开两个终端,分别运行发送端和接收端程序。发送和接收端程序运行时,发送端:先给接收端发送数据,保存在管道1;接着等待从管道2读取接收端发送的数据。接收端:从管道1读取发送端发送的数据;接着向发送端发送数据,保存在管道2。
程序缺点:只能一端输出后,等待另一端回复;回合制发送和接收。
优化:选择父子进程。一个用于发送,一个用于接收。
(1)发送端
(2)接收端
4.2父子进程通信
(1)发送端程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{//如果没有创建有名管道,则创建有名管道//为了实现两个进程都可以收发数据,所以需要创建两个有名管道if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);//退出}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//打开两个有名管道并得到文件描述符//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,//另一个接收方正好相反int fd_w, fd_r;if((fd_w = open("myfifo1", O_WRONLY)) == -1){perror("fail to open");exit(1);}if((fd_r = open("myfifo2", O_RDONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;//使用fork函数创建子进程pid_t pid;if((pid = fork()) < 0){perror("fail to fork");exit(1);}else if(pid > 0) // 父进程{while(1){printf("发送端运行中:请输入向接收端要发送的内容\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据if((bytes = write(fd_w, buf, sizeof(buf))) == -1){perror("fail to write");exit(1);}memset(buf, 0, sizeof(buf));//buf清0sleep(1);}}else // 子进程{while(1){//发送端从myfifo2读取数据if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1){perror("fail to read");exit(1);}printf("发送端:读取到接收端发送的数据: %s\n", buf1); if(strcmp("end_end",buf1) == 0){printf("发送端:读取到接收端发送的: 终止信号,退出\n");exit(1);}memset(buf1, 0, sizeof(buf1));sleep(1);}}return 0;
}
(2)接收端程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{//如果没有创建有名管道,则创建有名管道//为了实现两个进程都可以收发数据,所以需要创建两个有名管道if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);//退出}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//打开两个有名管道并得到文件描述符//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,//另一个接收方正好相反int fd_w, fd_r;if((fd_w = open("myfifo1", O_WRONLY)) == -1){perror("fail to open");exit(1);}if((fd_r = open("myfifo2", O_RDONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;//使用fork函数创建子进程pid_t pid;if((pid = fork()) < 0){perror("fail to fork");exit(1);}else if(pid > 0) // 父进程{while(1){printf("发送端运行中:请输入向接收端要发送的内容\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据if((bytes = write(fd_w, buf, sizeof(buf))) == -1){perror("fail to write");exit(1);}memset(buf, 0, sizeof(buf));//buf清0sleep(1);}}else // 子进程{while(1){//发送端从myfifo2读取数据if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1){perror("fail to read");exit(1);}printf("发送端:读取到接收端发送的数据: %s\n", buf1); if(strcmp("end_end",buf1) == 0){printf("发送端:读取到接收端发送的: 终止信号,退出\n");exit(1);}memset(buf1, 0, sizeof(buf1));sleep(1);}}return 0;
}
运行结果:打开两个终端,分别运行发送端和接收端程序。发送和接收端程序运行时,发送端既可以接收多次数据,也可以发送多次数据;接收端也支持同时发送和接收多次数据。发送特殊字符end_end退出运行。
(1)发送端
(2)接收端
5.有名管道读写规律(默认阻塞)
5.1读写端都存在,只读不写
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//读写端都存在,只读不写//如果原本管道中有数据,则正常读取//如果管道中没有数据,则read函数会阻塞等待int fd;if((fd = open("myfifo", O_RDWR)) == -1){perror("fail to open");exit(1);}//先写入数据验证,管道中有数据,则正常读取write(fd, "hello world", 11);char buf[128] = "";read(fd, buf, sizeof(buf));printf("buf = %s\n", buf);//管道中已无数据,读取会阻塞。read(fd, buf, sizeof(buf));printf("buf = %s\n", buf);return 0;
}
运行结果:读写端都存在,只读不写。
第一次读取,管道中有数据,正常读取;第二次读取,管道中已经无数据,在read处阻塞。
5.2读写端都存在,只写不读
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//读写端都存在,只写不读//当有名管道的缓冲区写满后,write函数会发生阻塞//默认有名管道的缓冲区为64K字节int fd;if((fd = open("myfifo", O_RDWR)) == -1){perror("fail to open");exit(1);}int num = 0;while(1){write(fd, "", 1024);num++;printf("num = %d\n", num);}return 0;
}
运行结果:读写端都存在,只写不读 ;当有名管道的缓冲区写满后,write函数会发生阻塞;默认有名管道的缓冲区为64K字节。
5.3 在一个进程中,只有读端,没有写端
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有读端,没有写端//会在open函数的位置阻塞printf("***********************\n");int fd;if((fd = open("myfifo", O_RDONLY)) == -1){perror("fail to open");exit(1);}printf("------------------------\n");char buf[128] = "";ssize_t bytes;if((bytes = read(fd, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("bytes = %ld\n", bytes);printf("buf = %s\n", buf);return 0;
}
运行结果:在一个进程中,只有读端,没有写端;会在open函数的位置阻塞(printf("------------------------\n"); 未执行)。
5.4 在一个进程中,只有写端,没有读端
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有写端,没有读端//会在open函数的位置阻塞printf("*****************************\n");int fd;if((fd = open("myfifo", O_WRONLY)) == -1){perror("fail to open");exit(1);}printf("-----------------------------\n");write(fd, "hello world", 11);printf("666\n");sleep(1);return 0;
}
运行结果:在一个进程中,只有写端,没有读端;会在open函数的位置阻塞
5.5 一个进程只读,一个进程只写
5.5.1两个进程,一个只读一个只写
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有读端,没有写端//会在open函数的位置阻塞printf("***********************\n");int fd;if((fd = open("myfifo", O_RDONLY)) == -1){perror("fail to open");exit(1);}printf("------------------------\n");char buf[128] = "";ssize_t bytes;if((bytes = read(fd, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("bytes = %ld\n", bytes);printf("buf = %s\n", buf);return 0;
}
(2)只写程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有写端,没有读端//会在open函数的位置阻塞printf("*****************************\n");int fd;if((fd = open("myfifo", O_WRONLY)) == -1){perror("fail to open");exit(1);}printf("-----------------------------\n");write(fd, "hello world", 11);printf("666\n");sleep(1);return 0;
}
运行结果:打开2个终端,对同一个管道进行读写操作,读写端同时存在,程序没有阻塞在open。
(1)只写端,程序没有阻塞在open,(printf("------------------------\n"); 已执行)
(2)只读端,程序没有阻塞在open,(printf("------------------------\n"); 已执行)
5.5.2两个进程,一个只读一个只写,关闭写端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有写端,没有读端//会在open函数的位置阻塞printf("*****************************\n");int fd;if((fd = open("myfifo", O_WRONLY)) == -1){perror("fail to open");exit(1);}printf("-----------------------------\n");while(1){write(fd, "hello world", 11);printf("666\n");sleep(1);}return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有读端,没有写端//会在open函数的位置阻塞printf("***********************\n");int fd;if((fd = open("myfifo", O_RDONLY)) == -1){perror("fail to open");exit(1);}printf("------------------------\n");char buf[128] = "";ssize_t bytes;while(1){if((bytes = read(fd, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("bytes = %ld\n", bytes);printf("buf = %s\n", buf);sleep(1);}return 0;
}
运行结果:打开两个终端运行。一个进程只读,一个进程只写,都运行后,如果关闭写端,读端read会返回0。
(1)写端,运行几次后,关闭写端,终止运行。
(2)读端,关闭写端,读端read会返回0。
5.5.3两个进程,一个只读一个只写,关闭读端


5.6读写端都存在,默认阻塞
有名管道默认读写状态为阻塞,读写端同时存在,不会再open函数处阻塞。
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open设置为可读可写,默认:阻塞效果char send[100] = "nihao world";fd = open("myfifo", O_RDWR);//读写打开if(fd < 0){perror("fail open fifo");exit(1);}write(fd, send, strlen(send));char recv[100] = "";read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);return 0;
}

6.有名管道的读写规律(设置:非阻塞)
6.1只读方式打开(设置非阻塞)
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open标志位设置为非阻塞,并且以只读的方式打开管道文件//open函数和read函数都不会阻塞fd = open("myfifo", O_RDONLY | O_NONBLOCK);if(fd < 0){perror("fail open fifo");exit(1);}while(1){char recv[100] = "";bzero(recv, sizeof(recv));read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);sleep(1);}return 0;
}
运行结果:管道只读 非阻塞打开,在 open函数 不阻塞,程序继续运行。
6.2只写方式打开(设置非阻塞)
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open标志位设置为非阻塞,并且以只写的方式打开管道文件//open函数会直接报错//如果open设置为可读可写,那么跟阻塞是一样的效果char send[100] = "Hello world";fd = open("myfifo", O_WRONLY | O_NONBLOCK);//fd = open("myfifo", O_RDWR | O_NONBLOCK);if(fd < 0){perror("fail open fifo");exit(1);}write(fd, send, strlen(send));char recv[100] = "";read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);return 0;
}
运行结果:管道只写 非阻塞打开管道文件,open函数会直接报错。(不加非阻塞设置,在open函数处,阻塞。见5.4章节)
6.3读写方式打开(设置非阻塞)
程序:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open设置为可读可写,那么跟阻塞是一样的效果char send[100] = "Hello world";//fd = open("myfifo", O_WRONLY | O_NONBLOCK);fd = open("myfifo", O_RDWR | O_NONBLOCK);//读写打开if(fd < 0){perror("fail open fifo");exit(1);}write(fd, send, strlen(send));char recv[100] = "";read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);return 0;
}
运行结果:读写端同时存在,设置为非阻塞,不会再open函数处阻塞。效果与读写端同时存在,设置为阻塞,效果相同。
相关文章:

Linux进程10-有名管道概述、创建、读写操作、两个管道进程间通信、读写规律(只读、只写、读写区别)、设置阻塞/非阻塞
目录 1.有名管道 1.1概述 1.2与无名管道的差异 2.有名管道的创建 2.1 直接用shell命令创建有名管道 2.2使用mkfifo函数创建有名管道 3.有名管道读写操作 3.1单次读写 3.2多次读写 4.有名管道进程间通信 4.1回合制通信 4.2父子进程通信 5.有名管道读写规律ÿ…...

精品可编辑PPT | 全面风险管理信息系统项目建设风控一体化标准方案
这份文档是一份全面风险管理信息系统项目建设风控一体化标准方案,涵盖了业务架构、功能方案、系统技术架构设计、项目实施及服务等多个方面的详细内容。方案旨在通过信息化手段提升企业全面风险管理工作水平,促进风险管理落地和内部控制规范化࿰…...
YOLOv8网络结构
YOLOv8的网络结构由输入端(Input)、骨干网络(Backbone)、颈部网络(Neck)和检测头(Head)四部分组成。 YOLOv8的网络结构如下图所示: 在整个系统架构中,图像首先进入输入处理模块,该模块承担着图像预处理与数据增强的双重任务。接着,…...
数组对象 按照对象中的某个字段排序
在JavaScript中,可以使用数组的sort()方法按照对象中的某个字段对数组进行排序。 按照对象中的某个字段对数组进行排序: 基本排序方法 升序排序 const array [{ name: John, age: 25 },{ name: Jane, age: 21 },{ name: Bob, age: 30 } ];// 按照age字…...

笔记本电脑升级实战手册【扩展篇1】:flash id查询硬盘颗粒
文章目录 前言:一、硬盘颗粒介绍1、MLC(Multi-Level Cell)2、TLC(Triple-Level Cell)3、QLC(Quad-Level Cell) 二、硬盘与主控1、主控介绍2、主流主控厂家 三 、硬盘颗粒查询使用flash id工具查…...

AutoDL租用服务器教程
在跑ai模型的时候,容易遇到算力不够的情况。此时便需要租用服务器。autodl是个较为便宜的服务器租用平台,h20仅需七点几元每小时。下面是简单的介绍。 打开网站AutoDL算力云 | 弹性、好用、省钱。租GPU就上AutoDL,并登录账号 登录后ÿ…...
四、STM32 HAL库API完全指南:从功能分类到实战示例
STM32 HAL库API完全指南:从功能分类到实战示例 一、HAL库API的总体架构 STM32 HAL库(Hardware Abstraction Layer)作为STMicroelectronics推出的统一驱动框架,提供了覆盖所有STM32外设的标准化API。HAL库的API设计遵循严格的分层…...
MySQL全量、增量备份与恢复
目录 数据备份 一、数据备份类型 二、常见备份方法 扩展:GTID与XtraBackup 一、GTID(全局事务标识符) 1. 定义与核心作用 2. GTID在备份恢复中的意义 3. GTID配置与启用 二、XtraBackup的意义与核心价值 1. 定…...
fastboot 如何只刷system.img 分区
在 fastboot 模式下只刷入 system.img 分区,可以按照以下步骤操作: 1. 确保设备已进入 Fastboot 模式 连接设备到电脑,并确保已进入 Fastboot/Bootloader 模式:adb reboot bootloader或手动进入(通常为 电源键 音量…...
连接词化归律详解
1. 连接词化归律的基本概念 连接词化归律(也称为归结原理)是数理逻辑中用于简化逻辑表达式的重要方法,它允许我们将复杂的逻辑表达式转化为更简单的等价形式,特别是转化为合取范式(CNF)或析取范式(DNF)。 核心思想 连接词化归律基于一系列逻辑等价关系…...
《构建社交应用用户激励引擎:React Native与Flutter实战解析》
React Native凭借其与JavaScript和React的紧密联系,为开发者提供了一个熟悉且灵活的开发环境。在构建用户等级体系时,它能够充分利用现有的前端开发知识和工具。通过将用户在社交应用中的各种行为进行量化,比如发布动态的数量、点赞评论的次数…...

goner/otel 在Gone框架接入OpenTelemetry
文章目录 背景与意义快速上手:五步集成 OpenTelemetry运行效果展示代码详解与实践目录结构说明组件加载(module.load.go)业务组件示例(your_component.go)程序入口(main.go) 进阶用法与最佳实践…...

杨校老师项目之基于SSM与JSP的鲜花销售系统-【成品设计含文档】
基于SSMJSP鲜花商城系统 随着电子商务的快速发展,鲜花在线销售已成为一种重要的消费模式。本文设计并实现了一个基于JSP技术的鲜花销售管理系统,采用B/S架构,使用SSM框架进行开发,并结合Maven进行项目依赖管理。系统分为前台用户模…...

springboot集成langchain4j实现票务助手实战
前言 看此篇的前置知识为langchain4j整合springboot,以及springboot集成langchain4j记忆对话。 Function-Calls介绍 langchain4j 中的 Function Calls(函数调用)是一种让大语言模型(LLM)与外部工具(如 A…...

Feed流推送之订阅推送
分类 feed流分为TimeLine和智能排序,前者不对内容进行过滤,一般根据发布的时间来进行排序,一般用于好友动态或者推送关注的人的消息,而后者一般有着复杂的算法,可以根据算法智能地向目标用户推送内容,例如…...

wordpress自学笔记 第四节 商城菜单的添加和修改美化
wordpress自学笔记 摘自 超详细WordPress搭建独立站商城教程-第四节 商城菜单的添加和修改美化,2025 WordPress搭建独立站商城#WordPress建站教程https://www.bilibili.com/video/BV1UwwgeuEkK?spm_id_from333.788.videopod.sections&vd_sourcea0af3bbc6b6d…...

GPU L2 Cache一致性协议对科学计算的影响研究
点击 “AladdinEdu,同学们用得起的【H卡】算力平台”,H卡级别算力,按量计费,灵活弹性,顶级配置,学生专属优惠。 一、GPU缓存层级革命:从Volta到Hopper的演进图谱 1.1 架构级缓存策略对比 Vo…...
C++中类中const知识应用详解
下面将从**const 成员**、const 成员函数、const 对象、mutable、constexpr 等方面,逐一详解 C 类中常见的 const 用法及注意事项,并配合示例。 一、const 数据成员 必须在初始化列表中初始化 class A {const int x; // const 成员 public:A(int v) :…...

【速写】KV-cache与解码的再探讨(以束搜索实现为例)
文章目录 1 Beam Search 解码算法实现2 实现带KV Cache的Beam Search解码3 关于在带kv-cache的情况下的use_cache参数 1 Beam Search 解码算法实现 下面是一个使用PyTorch实现的beam search解码算法: 几个小细节: 束搜索可以加入length_penalty&#…...

(网络)应用层协议-HTTPS
1.HTTPS是什么? HTTPS是应用层的一种协议,是在HTTP的基础上进行了加密层的处理。 HTTP协议的内容都是按照文本的形式进行传输的,所以呢就很容易被别人知道传输的是什么。 我们在了解了TCP/IP之后是知道我们的数据在传输的过程中是通过路由器进…...

vue3: pdf.js 3.4.120 using javascript
npm install pdfjs-dist3.4.120 项目结构: pdfjsViewer.vue <template><div><div v-if"loading" class"flex justify-center items-center py-8"><div class"animate-spin rounded-full h-12 w-12 border-b-2 borde…...
Spark目前支持的部署模式。
一、本地模式(Local Mode) 特点: 在单台机器上运行,无需集群。主要用于开发、测试和调试。所有组件(Driver、Executor)在同一个 JVM 中运行。 启动命令: bash spark-submit --master local[*]…...

想实现一个基于MCP的pptx生成系统架构图【初版实现】
技术栈:Python + MCP协议 + python-pptx + FastMCP 核心创新点:通过MCP协议实现PPTX元素的动态化生成与标准化模板管理 当前还是个半成品,后续持续更新。 主要先介绍一下思路。 一、MCP协议与系统设计原理 1.1 为什么选择MCP? 标准化工具调用:通过MCP将PPTX元素生成逻辑封…...

PyTorch Lightning实战 - 训练 MNIST 数据集
MNIST with PyTorch Lightning 利用 PyTorch Lightning 训练 MNIST 数据。验证梯度范数、学习率、优化器对训练的影响。 pip show lightning Version: 2.5.1.post0Fast dev run DATASET_DIR"/repos/datasets" python mnist_pl.py --output_grad_norm --fast_dev_run…...

力扣2094题解
记录: 2025.5.12 题目: 思路: 暴力遍历。 解题步骤: 1.统计数字出现次数:使用数组cnt来记录输入数组中每个数字的出现次数。 2.生成三位偶数:通过循环从100开始,每次递增2,生成…...

DHCP自动分配IP
DHCP自动分配IP 练习1 路由器 Router>en Router#conf t Router(config)#ip dhcp pool ip10 //创建DHCP地址池 Router(dhcp-config)#network 192.168.20.0 255.255.255.0 // 配置网络地址和子网掩码 Router(dhcp-config)#default-router 192.168.20.254 //配置默认网关 Rou…...
【CF】Day57——Codeforces Round 955 (Div. 2, with prizes from NEAR!) BCD
B. Collatz Conjecture 题目: 思路: 简单模拟 很简单的模拟,我们只需要快速的找到下一个离 x 最近的 y 的倍数即可(要大于 x) 这里我们可以这样写 add y - (x % y),这样就知道如果 x 要变成 y 的倍数还要…...

(done) 补充:xv6 的一个用户程序 init 是怎么启动的 ?它如何启动第一个 bash ?
先看 main.c 从函数名来看,比较相关的就 userinit() 和 scheduler() #include "types.h" #include "param.h" #include "memlayout.h" #include "riscv.h" #include "defs.h"volatile static int started 0;//…...
Nginx部署前端项目深度解析
在部署Vue前端项目时,Nginx的高效配置直接影响用户体验和性能表现。以下从7个关键维度深度解析部署方案,并提供专业级配置策略: 一、项目构建与基础部署 生产构建 npm run build -- --modern # 现代模式构建生成dist/目录包含:…...

超详细讲解C语言转义字符\a \b \r \t \? \n等等
转义字符 C语言有一组字符很特殊,叫做转义字符,顾名思义,改变原来的意思的字符。 1 \? ??)是一个三字母词,在以前的编译器它会被编译为] (??会被编译为[ 因此在以前输入(are you ok ??)就会被编译为are you ok ] 解决这个…...