【UNIX网络编程】FIFO

管道作为进程间通信的最古老方式,它的缺点是没有名字,因此只能用在有亲缘关系的父子进程之间。对于无亲缘关系的进程间,无法用管道进行通信。FIFO可以完成无亲缘关系的进程间的通信,FIFO也被称为命名管道。它是一种特殊类型的文件,在文件系统中以文件名的形式存在,但它的行为却和上面提到的管道类似。

创建命名管道有两种方法:

1、在命令行上执行命令:mkfifo filename 来创建FIFO。

2、使用mkfifo函数创建FIFO。

#include <sys/stat.h>
#include <sys/types.h>
int mkfifo(const char *pathname, mode_t mode); 	//返回值:若成功则返回0,若出错则返回-1

注意,mkfifo函数只是创建FIFO,要想打开它,还必须使用open函数,而且创建的过程中是隐含了O_CREAT| O_EXCL标志的,也就是说它要么创建一个新的FIFO,要么返回一个EEXIST错误。如果不希望创建一个新的FIFO,就改调用open而不是mkfifo。要打开一个已存在的FIFO或创建一个新的FIFO,应先调用mkfifo,再检查它是否返回EEXIST错误,若返回该错误则改为调用open。FIFO不能打来来既读又写,因为它是半双工的。

FIFO与管道的区别主要有以下两点:

1、创建并打开一个管道只需要调用pipe。创建并打开一个FIFO则需要调用mkfifo后再调用open。

2、管道在所有进程最终都关闭它之后自动消失。FIFO的名字则只有调用unlink才从文件系统中删除。

管道与FIFO都有系统加在他们上面的限制:

1、OPEN_MAX 一个进程在任意时刻打开的最大描述符数。

2、PIPE_BUF 可原子地写一个管道或FIFO的最大数据量。

下面就以例子来学习FIFO的创建、访问、打开等操作。

创建方法一mkfifo命令:

[email protected]:/work/tmp/unp$ mkfifo my_file  	//利用mkfifo命令创建my_file命名管道
[email protected]:/work/tmp/unp$ ls -l my_file
prw-r--r-- 1 book book 0 2014-07-03 15:44 my_file	//利用ls命令查看上一条命令创建的my_file命名管道
[email protected]:/work/tmp/unp$ mkfifo my_file
mkfifo: cannot create fifo `my_file': File exists	//因为命名管道已经存在,所以此时的mkfifo命令失败

创建方法二mkfifo函数:

将上面的命名管道删除后,利用下面的语句重新创建my_file命名管道。

	int res = mkfifo("my_file", 0777);
	if(res == 0)	printf("FIFO created\n");
	exit(EXIT_SUCCESS);

查看结果如下:

[email protected]:/work/tmp/unp$ rm -rf my_file
[email protected]:/work/tmp/unp$ ls
a.out  fifo.c       mutex  pipemesg  unpv22e
fifo   fifocliserv  pipe   pxmsg     unpv22e.tar.gz
[email protected]:/work/tmp/unp$ ./a.out
FIFO created
[email protected]:/work/tmp/unp$ 

访问上面创建的FIFO:

cat < my_file,因为此时FIFO里没有任何数据,所以此时阻塞。

echo "Hello world." > my_file,因为没有echo等待其他进程读取数据,所以同样阻塞。

使用open打开FIFO文件:

1、打开FIFO的主要限制是,程序不能以O_RDWR模式打开FIFO文件进行读写操作,因为通常我们只是单向传递数据。如果需要双向传递数据,就要创建一对FIFO。实现实例请参考之前写的客户-服务器程序,点此进入

2、打开FIFO文件和打开普通文件的另一个区别是,对open_flag的O_NOBLOCK选项的用法。使用这个选项不仅改变open调用的处理方式,还会改变对这次open调用返回的文件描述符进行的读写请求的处理方式。

a、open(const char *path, O_RDONLY);这种情况下,open调用将阻塞,除非有一个进程以写方式打开同一个FIFO,否则不会返回。例如上面的cat命令的例子。

b、open(const char *path,O_RDONLY | O_NONBLOCK);即使没有其他进程以写方式打开FIFO,这个open调用也将成功立即返回。

c、open(const char *path, O_WRONLY); open调用将阻塞,知道有一个进程以读的方式打开同一个FIFO为止。如上面的echo命令的例子。

d、open(const char *path, O_WRONLY | O_NONBLOCK);函数立即返回,但如果没有进程以读方式打开FIFO,open调用将返回一个错误并且FIFO也不会被打开。

示例代码:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "my_file"

int
main(int argc, char **argv)
{
	int res;
	int open_mode = 0;
	int i;

	if(argc < 2){
		fprintf(stderr, "Usage : %s <some combinations of						O_RDONLY O_WRONLY O_NONBLOCK>\n", *argv);
				exit(EXIT_FAILURE);
	}

	for(i = 1; i < argc; i++){
		if(strncmp(*++argv , "O_RDONLY", 8) == 0);
			open_mode |= O_RDONLY;
		if(strncmp(*++argv , "O_WRONLY", 8) == 0);
			open_mode |= O_WRONLY;
		if(strncmp(*++argv , "O_NONBLOCK", 10) == 0);
			open_mode |= O_NONBLOCK;
	}

	if(access(FIFO_NAME, F_OK) == -1){
		res = mkfifo(FIFO_NAME, 0777);
		if(res != 0){
			fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
			exit(EXIT_FAILURE);
		}
	}

	printf("Process %d opending FIFO\n", getpid());
	res = open(FIFO_NAME, open_mode);
	printf("Process %d result %d\n", getpid(), res);
	sleep(5);
	if(res != -1)	close(res);
	printf("Process %d finished\n", getpid());
	exit(EXIT_SUCCESS);
}

对于FIFO的高级一点的应用,比如客户-服务器程序,进程间通信等,参见直接的总结,点此链接

参考:

1、之前的总结:http://blog.csdn.net/to_be_it_1/article/details/28384117

2、《Linux程序设计》 Neil Matthew&&Richard Stones

3、《UNIX环境高级编程》Richard Stevenson

4、《UNIX网络编程 卷2》 Richard Stevenson

【UNIX网络编程】FIFO,布布扣,bubuko.com

时间: 2024-11-06 19:12:24

【UNIX网络编程】FIFO的相关文章

【UNIX网络编程】进程间通信之管道

管道是最早的Unix进程间通信形式,它存在于全部的Unix实现中.关于管道,有例如以下几点须要知道: 1.它是半双工的,即数据仅仅能在一个方向上流动.虽然在某些Unix实现中管道能够是全双工的.但须要对系统进行某些设置.在Linux系统中,它是半双工的. 2.它没有名字.因此仅仅能在具有公共祖先的进程之间使用. 通经常使用在父子进程间.虽然这一点随着"有名管道FIFO"的增加得到改正了.但应该把它们看作是两种不同的进程间通信方式. 3.它由pipe函数创建,read和write函数訪问

UNIX网络编程 卷2:进程间通信

这篇是计算机类的优质预售推荐>>>><UNIX网络编程 卷2:进程间通信(第2版)> UNIX和网络专家W. Richard Stevens的传世之作 编辑推荐 两卷本的<UNIX网络编程>是已故著名技术作家W. Richard Stevens的传世之作.卷2着重讨论怎样让应用程序与在其它机器上的应用程序进行对话. 良好的进程间通信(IPC)机制是提高UNIX程序性能的关键. 本书全面深入地解说了各种进程间通信形式,包括消息传递.同步.共享内存及远程过程调用

Unix网络编程-同步

1.互斥锁(量)和条件变量 默认情况下互斥锁和条件变量用于线程间同步,若将它们放在共享内存区,也能用于进程间同步. 1.1 互斥锁 1.概述: 互斥锁(Mutex,也称互斥量),防止多个线程对一个公共资源做读写操作的机制,以保证共享数据的完整性. 用以保护临界区,以保证任何时候只有一个线程(或进程)在访问共享资源(如代码段).保护临界区的代码形式: lock_the_mutex(...); 临界区 unlock_the_mutex(...); 任何时刻只有一个线程能够锁住一个给定的互斥锁. 下面

UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select 加阻塞式 I/O 版本. 非阻塞式 I/O 版本.fork 版本.线程化版本.它们都由同一个 main 函数调用来实现同一个功能,即回射程序客户端. 它从标准输入读入一行文本,写到服务器上,读取服务器对该行的回射,并把回射行写到标准输出上. 其中,非阻塞式 I/O 版本是所有版本中执行速度最快的,

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模

unix网络编程环境搭建

unix网络编程环境搭建 新建 模板 小书匠 1.点击下载源代码 可以通过下列官网中的源代码目录下载最新代码: http://www.unpbook.com/src.html 2.解压文件 tar -xzvf upv13e.tar.gz 3.上传至阿里云 本人本地已经配置好,这次实验是将环境搭建至云服务器中. scp -r unpv13e [email protected]120.76.140.119:/root/program/unp // -r 上传文件夹  4.编译文件 cd unpv13

unix网络编程代码(2)

继续贴<unix网络编程>上的示例代码.这次是一个反射程序,反射是客户端讲用户输入的文本发送到服务器端,服务器端读取客户端发过来的文本消息,然后原封不动的把文本消息返回给客户端.使用tcp协议连接客户端和服务端,我已经在我的阿里云服务器上测试过了,能够完美运行. 首先是头文件wrap.h,在该头文件中,声明了封装部分网络编程套接字api的包裹函数,以及某些宏定义. 1 #ifndef WRAP_H_ 2 #define WRAP_H_ 3 4 #include <stdio.h>

【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)

RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [实验目的] 1.熟练掌握线程的创建与终止方法: 2.熟练掌握线程间通信同步方法: 3.应用套接字函数完成多线程服务器,实现服务器与客户端的信息交互. [实验内容] 通过一个服务器实现最多5个客户之间的信息群发. 服务器显示客户的登录与退出: 客户连接后首先发送客户名称,之后发送群聊信息: 客户输入bye代表退

Unix网络编程 之 socket基础

基本结构 (这部分的地址均为网络地址<网络字节序>) 1.struct sockaddr:通用套接字地址结构 此结构用于存储通用套接字地址. 数据结构定义: typedef unsigned short sa_family_t; struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };    sa_fa