- 一 有名管道的概述
- 二 有名管道的特点
- 三 有名管道的API
- 3.1 创建有名管道
- 四 有名管道案例
- 五 有名管道读写特点
- 六 命名管道实例-单机qq聊天
- 主要用于没有血缘关系的进程间通信;
- 有名管道实际上是一块物理内存;无名管道是逻辑内存;
1. 半双工,数据只能在一个方向上流动; 2. 写入FIFO中的数据遵循先入先出的规则; 3. FIFO所传输的数据是无格式的,这要求FIFO的读出方与写入方必须事先约定好数据格式,如多少字节算一个消息等; 4. FIFO在文件系统中作为一个特殊文件存在,但FIFO中的内容是存放在内存中的; 5. 管道在内存中对应一个缓冲区,不同的系统其大小不一定相同; 6. 从FIFO读数据是一次性操作,读完就从FIFO中被抛弃; 7. 当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用; 8. FIFO有名字,不相关的进程可以通过打开命名管道进行通信三 有名管道的API 3.1 创建有名管道
- 需要的头文件和函数原型
#include#include int mkfifo(const char *pathname, mode_t mode);
- 参数
pathname:FIFO的路径名+文件名 mode:权限描述符
- 返回值
成功:返回0 失败:如果文件已经存在,则会出错并返回-1四 有名管道案例
#include五 有名管道读写特点#include #include #include #include #include #include #include int main(int arg, char *argv[]) { //创建有名管道 mkfifo("/root/myfifo1",0666); #ifdef READ int fd = open("/root/myfifo1",O_RDONLY); #endif #ifdef WRITE int fd = open("/root/myfifo1",O_WRONLY); #endif if(fd<0) { perror("open"); return 0; } #ifdef READ printf("读端open成功了n"); while(1) { char buf[1024] = ""; read(fd,buf,sizeof(buf)); printf("收到数据:%sn",buf); if(strcmp(buf,"bye") == 0) break; } #endif #ifdef WRITE printf("写端open成功了n"); while(1) { printf("请输入:"); char buf[1024] = ""; fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1] = 0; write(fd,buf,strlen(buf)); if(strcmp(buf,"bye") == 0) break; } #endif close(fd); return 0; }
以阻塞方式打开管道: 1. open函数以只读方式打开有名管道时,要阻塞直到有其他进程以写方式打开这个管道; 2. open函数以只写方式打开有名管道时,要阻塞直到有其他进程以读方式打开这个管道; 3. 调用read函数从有名管道读数据时,read会阻塞; 4. 通信过程中如果写进程先退出,则调用read函数从有名管道读数据时不阻塞;如果写进程又重新运行,则调用read函数又恢复阻塞; 5. 读进程退出后,写进程向管道写时会收到SIGPIPE信号而退出; 6. 调用write函数向管道写数据时,如果缓冲区满了,write会阻塞 以非阻塞方式打开管道: 7. 先以只读方式打开:如果没有进程已经为写而打开一个FIFO,只读open成功,而且open不阻塞; 8. 先以只写方式打开:如果没有进程已经为读而打开一个FIFO,只写open将出错返回-1; 9. read,write读写命名管道中数据时不堵塞; 4.通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会收到SIGPIPE信号而退出; 注意: open函数以可读可写方式打开FIFO文件时的特点: 1. open不阻塞; 2.调用read函数从FIFO里读取数据时read会阻塞; 3. 调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞六 命名管道实例-单机qq聊天
实现单机QQ聊天。提示:父进程创建子进程,实现多任务。父进程负责发消息(向FIFO里写数据),子进程负责接收信息(从FIFO里读数据)。打开命名管道用阻塞方式打开。
#include#include #include #include #include #include #include #include int main(int arg, char *argv[]) { //创建有名管道 mkfifo("./andytolinda",0666); mkfifo("./lindatoandy",0666); //创建两个子进程用管道通信 int i = 0; for(i=0;i<2;i++) { pid_t pid = fork(); if(pid == 0) break; } if(i==0) //子进程1 负责写 { #ifdef andy int fd = open("./andytolinda",O_WRONLY); #endif #ifdef linda int fd = open("./lindatoandy",O_WRONLY); #endif if(fd==-1) { perror("open"); return 1; } while(1) { #ifdef andy printf("rAndy: "); #endif #ifdef linda printf("rLinda: "); #endif char buf[128]=""; fgets(buf,sizeof(buf),stdin); buf[strlen(buf)-1]=0; write(fd,buf,strlen(buf)); if(strcmp(buf,"bye")==0) break; } close(fd); _exit(0); } else if(i == 1) //子进程2 负责读 { #ifdef andy int fd = open("./lindatoandy",O_RDONLY); #endif #ifdef linda int fd = open("./andytolinda",O_RDONLY); #endif if(fd==-1) { perror("open"); return 1; } while(1) { char buf[128]=""; read(fd,buf,sizeof(buf)); #ifdef andy printf("rLinda said: %snrAndy:",buf); #endif #ifdef linda printf("rAndy said: %snrLinda:",buf); #endif if(strcmp(buf,"bye")==0) break; } close(fd); _exit(0); } else if(i == 2) //父进程 { while(1) { pid_t pid = wait(NULL); if(pid > 0) printf("主进程回收了子进程:%dn",pid); else if(pid < 0) break; } } return 0; }



