linux 管道文件上机总结,[转载]LINUX 管道 fifo 等总结

Linux进程通信:命名管道FIFO小结

Linux下进程之间通信可以用命名管道FIFO完成。命名管道是一种特殊类型的文件,因为Linux中所有事物都是文件,它在文件系统中以文件名的形式存在。

在程序中,我们可以使用两个不同的函数调用来建立管道:

#include

#include

int mkfifo(const char *filename,

mode_t mode);

int mknode(const char *filename,

mode_t mode | S_IFIFO, (dev_t) 0 );

下面先来创建一个管道:

#include 

#include 

#include 

#include 

intmain()

{

intres = mkfifo("/tmp/my_fifo", 0777);

if(res == 0)

{

printf("FIFO created/n");

}

exit(EXIT_SUCCESS);

}

#include

#include

#include

#include

int main()

{

int res = mkfifo("/tmp/my_fifo", 0777);

if (res == 0)

{

printf("FIFO created/n");

}

exit(EXIT_SUCCESS);

}

编译这个程序:

gcc –o fifo1.c

fifo

运行这个程序:

$ ./fifo1

用ls命令查看所创建的管道

$ ls -lF

/tmp/my_fifo

prwxr-xr-x 1 root root 0 05-08

20:10 /tmp/my_fifo|

注意:ls命令的输出结果中的第一个字符为p,表示这是一个管道。最后的|符号是由ls命令的-F选项添加的,它也表示是这是一个管道。

虽然,我们所设置的文件创建模式为“0777”,但它被用户掩码(umask)设置(022)给改变了,这与普通文件创建是一样的,所以文件的最终模式为755。

打开FIFO一个主要的限制是,程序不能是O_RDWR模式打开FIFO文件进行读写操作,这样做的后果未明确定义。这个限制是有道理的,因为我们使用FIFO只是为了单身传递数据,所以没有必要使用O_RDWR模式。如果一个管道以读/写方式打开FIFO,进程就会从这个管道读回它自己的输出。如果确实需要在程序之间双向传递数据,最好使用一对FIFO,一个方向使用一个。

当一个Linux进程被阻塞时,它并不消耗CPU资源,这种进程的同步方式对CPU而言是非常有效率的。

有关Linux下命名管道FIFO的读写规则可以参见之前所写的一篇文章:。

一、实验:使用FIFO实现进程间通信

两个独立的程序:

1.

生产者程序,它在需要时创建管道,然后尽可能快地向管道中写入数据。

2.

消费者程序,它从FIFO中读取数据并丢弃它们。

生产者程序fifo2.c:

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define FIFO_NAME "/tmp/Linux/my_fifo"

#define BUFFER_SIZE PIPE_BUF

#define TEN_MEG (1024 * 1024 * 10)

intmain()

{

intpipe_fd;

intres;

intopen_mode = O_WRONLY;

intbytes = 0;

charbuffer[BUFFER_SIZE + 1];

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 opening FIFO O_WRONLY/n", getpid());

pipe_fd = open(FIFO_NAME, open_mode);

printf("Process %d result %d/n", getpid(), pipe_fd);

if(pipe_fd != -1)

{

while(bytes 

{

res = write(pipe_fd, buffer, BUFFER_SIZE);

if(res == -1)

{

fprintf(stderr, "Write error on pipe/n");

exit(EXIT_FAILURE);

}

bytes += res;

}

close(pipe_fd);

}

else

{

exit(EXIT_FAILURE);

}

printf("Process %d finish/n", getpid());

exit(EXIT_SUCCESS);

}

#include

#include

#include

#include

#include

#include

#include

#define FIFO_NAME "/tmp/Linux/my_fifo"

#define BUFFER_SIZE PIPE_BUF

#define TEN_MEG (1024 * 1024 * 10)

int main()

{

int pipe_fd;

int res;

int open_mode = O_WRONLY;

int bytes = 0;

char buffer[BUFFER_SIZE + 1];

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 opening FIFO O_WRONLY/n", getpid());

pipe_fd = open(FIFO_NAME, open_mode);

printf("Process %d result %d/n", getpid(), pipe_fd);

if (pipe_fd != -1)

{

while (bytes < TEN_MEG)

{

res = write(pipe_fd, buffer, BUFFER_SIZE);

if (res == -1)

{

fprintf(stderr, "Write error on pipe/n");

exit(EXIT_FAILURE);

}

bytes += res;

}

close(pipe_fd);

}

else

{

exit(EXIT_FAILURE);

}

printf("Process %d finish/n", getpid());

exit(EXIT_SUCCESS);

}

消费者程序fifo3.c:

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define FIFO_NAME "/tmp/Linux/my_fifo"

#define BUFFER_SIZE PIPE_BUF

intmain()

{

intpipe_fd;

intres;

intopen_mode = O_RDONLY;

charbuffer[BUFFER_SIZE + 1];

intbytes = 0;

memset(buffer, '/0',sizeof(buffer));

printf("Process %d opeining FIFO O_RDONLY/n", getpid());

pipe_fd = open(FIFO_NAME, open_mode);

printf("Process %d result %d/n", getpid(), pipe_fd);

if(pipe_fd != -1)

{

do{

res = read(pipe_fd, buffer, BUFFER_SIZE);

bytes += res;

}while(res > 0);

close(pipe_fd);

}

else

{

exit(EXIT_FAILURE);

}

printf("Process %d finished, %d bytes read/n", getpid(), bytes);

exit(EXIT_SUCCESS);

}

#include

#include

#include

#include

#include

#include

#include

#define FIFO_NAME "/tmp/Linux/my_fifo"

#define BUFFER_SIZE PIPE_BUF

int main()

{

int pipe_fd;

int res;

int open_mode = O_RDONLY;

char buffer[BUFFER_SIZE + 1];

int bytes = 0;

memset(buffer, '/0', sizeof(buffer));

printf("Process %d opeining FIFO O_RDONLY/n", getpid());

pipe_fd = open(FIFO_NAME, open_mode);

printf("Process %d result %d/n", getpid(), pipe_fd);

if (pipe_fd != -1)

{

do{

res = read(pipe_fd, buffer, BUFFER_SIZE);

bytes += res;

}while(res > 0);

close(pipe_fd);

}

else

{

exit(EXIT_FAILURE);

}

printf("Process %d finished, %d bytes read/n", getpid(), bytes);

exit(EXIT_SUCCESS);

}

编译这两个程序:

gcc –o fifo2

fifo2.c

gcc –o fifo3

fifo3.c

运行这两个程序:

[root@localhost chaper12]# ./fifo2

&

à后台执行,写数据

[2] 23121

Process 23121 opening FIFO

O_WRONLY

[root@localhost chaper12]# time

./fifo3à读数据

Process 24155 opeining FIFO

O_RDONLY

Process 23121 result

3

Process 24155 result

3

Process 23121

finish

Process 24155 finished, 10485760

bytes read

[2]- Done

./fifo2

real 0m0.214s

user 0m0.000s

sys 0m0.179s

以上两个程序均是使用阻塞模式FIFO。Linux会安排好这两个进程之间的调试,使它们在可以运行的时候运行,在不能运行的时候阻塞。因此,写进程将在管道满时阻塞,读进程将在管道空时阻塞。

虚拟机上,time命令显示,读进程只运行了0.2秒的时间,却读取了10M字节的数据。这说明管道在程序之间传递数据是非常有效的。

二、实验:使用FIFO的客户/服务器应用程序

利用FIFO实现一个客户/服务器的应用程序,服务器进程接受请求,对它们进程处理,最后把结果数据返回给发送请求的客户方。

首先建立一个头文件client.h,它定义了客户和服务器程序都要用到的数据结构,并包含了必要的头文件。

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define SERVER_FIFO_NAME "/tmp/Linux/chaper12/server_fifo"

#define CLIENT_FIFO_NAME "/tmp/Linux/chaper12/client_%d_fifo"

#define BUFFER_SIZE PIPE_BUF

#define MESSAGE_SIZE 20

#define NAME_SIZE 256

typedefstructmessage

{

pid_t client_pid;

chardata[MESSAGE_SIZE + 1];

}message;

#include

#include

#include

#include

#include

#include

#include

#define SERVER_FIFO_NAME "/tmp/Linux/chaper12/server_fifo"

#define CLIENT_FIFO_NAME "/tmp/Linux/chaper12/client_%d_fifo"

#define BUFFER_SIZE PIPE_BUF

#define MESSAGE_SIZE 20

#define NAME_SIZE 256

typedef struct message

{

pid_t client_pid;

char data[MESSAGE_SIZE + 1];

}message;

接下来是服务器程序server.c,在这一部分,是以只读阻塞模式打开服务器管道,用于接收客户发送过来的数据,这些数据采用message结构体封装。

#include "client.h"

intmain()

{

intserver_fifo_fd;

intclient_fifo_fd;

intres;

charclient_fifo_name[NAME_SIZE];

message msg;

char*p;

if(mkfifo(SERVER_FIFO_NAME, 0777) == -1)

{

fprintf(stderr, "Sorry, create server fifo failure!/n");

exit(EXIT_FAILURE);

}

server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);

if(server_fifo_fd == -1)

{

fprintf(stderr, "Sorry, server fifo open failure!/n");

exit(EXIT_FAILURE);

}

sleep(5);

while(res = read(server_fifo_fd, &msg,sizeof(msg)) > 0)

{

p = msg.data;

while(*p)

{

*p = toupper(*p);

++p;

}

sprintf(client_fifo_name, CLIENT_FIFO_NAME, msg.client_pid);

client_fifo_fd = open(client_fifo_name, O_WRONLY);

if(client_fifo_fd == -1)

{

fprintf(stderr, "Sorry, client fifo open failure!/n");

exit(EXIT_FAILURE);

}

write(client_fifo_fd, &msg, sizeof(msg));

close(client_fifo_fd);

}

close(server_fifo_fd);

unlink(SERVER_FIFO_NAME);

exit(EXIT_SUCCESS);

}

#include "client.h"

int main()

{

int server_fifo_fd;

int client_fifo_fd;

int res;

char client_fifo_name[NAME_SIZE];

message msg;

char *p;

if (mkfifo(SERVER_FIFO_NAME, 0777) == -1)

{

fprintf(stderr, "Sorry, create server fifo failure!/n");

exit(EXIT_FAILURE);

}

server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);

if (server_fifo_fd == -1)

{

fprintf(stderr, "Sorry, server fifo open failure!/n");

exit(EXIT_FAILURE);

}

sleep(5);

while (res = read(server_fifo_fd, &msg, sizeof(msg)) > 0)

{

p = msg.data;

while (*p)

{

*p = toupper(*p);

++p;

}

sprintf(client_fifo_name, CLIENT_FIFO_NAME, msg.client_pid);

client_fifo_fd = open(client_fifo_name, O_WRONLY);

if (client_fifo_fd == -1)

{

fprintf(stderr, "Sorry, client fifo open failure!/n");

exit(EXIT_FAILURE);

}

write(client_fifo_fd, &msg, sizeof(msg));

close(client_fifo_fd);

}

close(server_fifo_fd);

unlink(SERVER_FIFO_NAME);

exit(EXIT_SUCCESS);

}

客户端程序client.c,这个程序用于向服务器发送消息,并接收来自服务器的回复。

#include "client.h"

intmain()

{

intserver_fifo_fd;

intclient_fifo_fd;

intres;

charclient_fifo_name[NAME_SIZE];

message msg;

msg.client_pid = getpid();

sprintf(client_fifo_name, CLIENT_FIFO_NAME, msg.client_pid);

if(mkfifo(client_fifo_name, 0777) == -1)

{

fprintf(stderr, "Sorry, create client fifo failure!/n");

exit(EXIT_FAILURE);

}

server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY);

if(server_fifo_fd == -1)

{

fprintf(stderr, "Sorry, open server fifo failure!/n");

exit(EXIT_FAILURE);

}

sprintf(msg.data, "Hello from %d", msg.client_pid);

printf("%d sent %s ", msg.client_pid, msg.data);

write(server_fifo_fd, &msg, sizeof(msg));

client_fifo_fd = open(client_fifo_name, O_RDONLY);

if(client_fifo_fd == -1)

{

fprintf(stderr, "Sorry, client fifo open failure!/n");

exit(EXIT_FAILURE);

}

res = read(client_fifo_fd, &msg, sizeof(msg));

if(res > 0)

{

printf("received:%s/n", msg.data);

}

close(client_fifo_fd);

close(server_fifo_fd);

unlink(client_fifo_name);

exit(EXIT_SUCCESS);

}

#include "client.h"

int main()

{

int server_fifo_fd;

int client_fifo_fd;

int res;

char client_fifo_name[NAME_SIZE];

message msg;

msg.client_pid = getpid();

sprintf(client_fifo_name, CLIENT_FIFO_NAME, msg.client_pid);

if (mkfifo(client_fifo_name, 0777) == -1)

{

fprintf(stderr, "Sorry, create client fifo failure!/n");

exit(EXIT_FAILURE);

}

server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY);

if (server_fifo_fd == -1)

{

fprintf(stderr, "Sorry, open server fifo failure!/n");

exit(EXIT_FAILURE);

}

sprintf(msg.data, "Hello from %d", msg.client_pid);

printf("%d sent %s ", msg.client_pid, msg.data);

write(server_fifo_fd, &msg, sizeof(msg));

client_fifo_fd = open(client_fifo_name, O_RDONLY);

if (client_fifo_fd == -1)

{

fprintf(stderr, "Sorry, client fifo open failure!/n");

exit(EXIT_FAILURE);

}

res = read(client_fifo_fd, &msg, sizeof(msg));

if (res > 0)

{

printf("received:%s/n", msg.data);

}

close(client_fifo_fd);

close(server_fifo_fd);

unlink(client_fifo_name);

exit(EXIT_SUCCESS);

}

编译程序:

gcc –o server

server.c

gcc –o client

client.c

测试这个程序,我们需要一个服务器进程和多个客户进程。为了让多个客户进程在同一时间启动,我们使用了shell命令:

[root@localhost chaper12]# ./server

&

[26] 5171

[root@localhost chaper12]# for i in

1 2 3 4 5; do ./client & done

[27] 5172

[28] 5173

[29] 5174

[30] 5175

[31] 5176

[root@localhost chaper12]# 5172

sent Hello from 5172 received:HELLO FROM 5172

5173 sent Hello from 5173

received:HELLO FROM 5173

5174 sent Hello from 5174

received:HELLO FROM 5174

5175 sent Hello from 5175

received:HELLO FROM 5175

5176 sent Hello from 5176

received:HELLO FROM 5176

分析这个例子,服务器以只读模式创建它的FIFO并阻塞,直到第一个客户以写方式打开同一现个FIFO来建立连接为止。此时,服务器进程解除阻塞并执行sleep语句,这使得来自客户的数据排除等候。在实际应用程序中,应该把sleep语句删除,这里面只是为了演示当有多个客户请求同时到达时,程序的正确操作方法。

与此同时,在客户端打开服务器FIFO后,它创建自己唯一的一个命名管道以读取服务器返回的数据。完成这些工作后,客户发送数据给服务器(如果管道满或服务器仍处于休眠就阻塞),并阻塞于对自己FIFO的read调用上,等待服务器响应。

接收到来自客户的数据后,服务器处于它,然后以写的方式打开客户管道并将处理后的数据返回,这将解除客户端的阻塞状态,客户程序就可以从自己的管道里面读取服务器返回的数据了。

整个处理过程不断重复,直到最后一个客户关闭服务器管道为止,这将使服务器的read调用失败(返回0),因为已经没有进程以写方式打开服务器管道了。如果这是一个真正的服务器进程的话,它还需要继续等待其他客户的请求,我们就需要对它进行修改,有两种方法:

(1)对它自己的服务器管道打开一个文件描述符,这样read调用将阻塞而不是返回0。

(2)当read调用返回0时,关闭并重新打开服务器管道,使服务器进程阻塞在open调用处以等待客户的到来,就像它最初启动时那样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429301.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tomcat 下载

点project 关闭防火墙才可以让别人访问自己 转载于:https://www.cnblogs.com/feathe/p/6853491.html

linux消息框架,远程处理器消息框架 - 基于Linux 简化 AMP 配置使其更方便更动态地分配资源...

核心的 rpmsg 框架起到开关的作用&#xff0c;根据消息中包含的目的地址将消息传送到相应端点。由于消息报头包含源地址&#xff0c;因此可在不同处理器之间建立专用连接。命名服务处理器可通过向 rpmsg 框架的命名服务发送消息&#xff0c;以动态宣布特定服务。命名服务功能本…

洛谷 P3366 【模板】最小生成树

题目描述 如题&#xff0c;给出一个无向图&#xff0c;求出最小生成树&#xff0c;如果该图不连通&#xff0c;则输出orz 输入输出格式 输入格式&#xff1a;第一行包含两个整数N、M&#xff0c;表示该图共有N个结点和M条无向边。&#xff08;N<5000&#xff0c;M<200000…

陇东学院c语言程序设计,C语言程序设计

spContent《C语言程序设计》是高等学校本科教育普遍开设的一门课程&#xff0c;是广大程序设计语言学习者首选的入门课程。本课程立足于C语言基础知识的讲解&#xff0c;讲授中引入大量实例&#xff0c;突出重点&#xff0c;剖析难点&#xff0c;培养学生结构化程序设计的思想&…

关于android:windowNoTitle不起作用的解决办法

今天测试一个新功能的时候&#xff0c;在styles.xml设置<item name"android:windowNoTitle">true</item>并没有生效&#xff0c;当时很奇怪&#xff0c;以前的项目都这么设置的&#xff0c;并且都能生效&#xff0c;后来发现MainActivity继承的是AppComp…

jQuery笔记——选择器

jQuery 最核心的组成部分就是&#xff1a;选择器引擎。它继承了 CSS 的语法&#xff0c;可以对 DOM 元 素的标签名、属性名、状态等进行快速准确的选择&#xff0c;并且不必担心浏览器的兼容性 常规选择器 根据id选择元素就是使用#&#xff0c;还有两种其他选择元素的方式&…

c语言实现NRZ编码,CSC1001-课后笔记

前言&#xff1a;为什么编写此文1. 根据费曼的学习方法Pretend to teach your topic to a classroom. Make sure youre able to explain the topic in simple terms. 假装你在教室里向学生解释这个主题&#xff0c;用尽量简单的词汇去描述它&#xff0c;力求学生能听懂。(听众…

LeetCode 111. Minimum Depth of Binary Tree

原题 Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. 思路一 类似于求最大深度时的递归思路不过需要注意的是当某一节点的左子节点(右子节点类似)为空时…

c语言编程流水灯与交通灯实验,C51单片机实验报告_流水灯_交通灯_定时器_双机交互_时钟.doc...

C51单片机实验报告_流水灯_交通灯_定时器_双机交互_时钟学 号&#xff1a;班 级&#xff1a; 自动化10班姓 名&#xff1a; 张指导老师&#xff1a; 胡2012.12单片机核心板实验要求流水灯实验实验目的&#xff1a;简单I/O引脚的输出掌握软件延时编程方法简单按键输入捕获判断完…

angularjs中的分页指令

自定义指令 import angular from angular;/*** ngdoc module* name components.page* description 分页directive*/ export default angular.module(pageDirective, []).directive(ngPage, function () {return {restrict: E,scope: {totalCount: ,pageSize: ,param: ,pageItme…

金币问题c语言程序,【求助】急请c语言高手帮忙解决程序问题(问题已经被我自己解决,金币送给自己啦)...

不好意思&#xff0c;这是程序后面部分&#xff1a;RHOMOLL,double* X, double& DRHODT);void (__stdcall *FGCTYdll)(double& TK, double& RHOMOLL,double* X, double& FUGACITY);// The following ifdef block is…

xv6/调度算法及并发程序设计

1 在proc.c的scheduler函数中&#xff0c;有两行&#xff1a; if(setjmp(&cpus[cpu()].jmpbuf) 0) longjmp(&p->jmpbuf); 把它修改为&#xff1a; cprintf("setjmp called in scheduler\n"); if(setjmp(&cpus[cpu()].jmpbuf) 0){ cprintf(&qu…

c语言四舍五入取整向上取整,C 语言常用的函数(ceil-向上取整,floor-向下取整,round-四舍五入)...

释放双眼&#xff0c;带上耳机&#xff0c;听听看~&#xff01;1.ceil函数(向上取整)extern float ceilf(float); //参数为flot类型extern double ceil(double); //参数为double类型extern long double ceill(long double); //参数为long double类型举例&#xff1a;向上取整函…

PHP函数之HTMLSPECIALCHARS_DECODE

PHP函数之htmlspecialchars_decode htmlspecialchars_decode &#xff1a;将特殊的 HTML 实体转换回普通字符 htmlspecialchars&#xff1a; 将普通字符转换成实体转载于:https://www.cnblogs.com/lovebing/p/6866484.html

c语言中printk用法,printk和printf的区别

&&&大部分常用的C库函数在Linux内核中都已经得到了实现。在所有没有实现的函数中&#xff0c;最著名的就数printf()函数了。内核代码虽然无法调用printf()函数&#xff0c;但它可以调用printk()函数。printk()函数负责把格式化好的字符串拷贝到内核日志缓冲上&…

《Java技术》第八次作业

《Java技术》第八次作业 &#xff08;一&#xff09;学习总结 1.用思维导图对本周的学习内容进行总结。 2.通过实验内容中的具体实例说明在执行executeUpdate&#xff08;&#xff09;方法和executeQuery&#xff08;&#xff09;方法中使用动态参数时&#xff0c;为什么要使用…

android 短信 aapp,谈谈App的统一跳转和ARouter

App中每次页面跳转,都需要调用统一导航, 它用的非常频繁, 有必要对它进行一下梳理. 让他能用起来简单方便, 同时能支持各种常用的跳转业务场景.一. Android跳转遇到的问题1.intent-filter跳转不好管理Intent intent new Intent();intent.setAction(Intent.ACTION_SENDTO);inte…

android 自定义spnner弹出框,PopupWindow,ListView实现自定义Spinner

最终的效果图,点击86弹出popup这里写图片描述PupupWindow的布局文件为一个ListView 作为pupup的主体内容android:orientation"vertical"android:layout_width"match_parent"android:layout_height"match_parent">android:id"id/register…

hdu 6026 Deleting Edges(最短路计数)

题目链接&#xff1a;hdu 6026 Deleting Edges 题意&#xff1a; 给你n个点&#xff0c;和一个邻接矩阵&#xff0c;非0表示有边&#xff0c;0表示没边。 现在让你删一些边&#xff0c;构成一棵树&#xff0c;使得每个点到0这个点的距离为没删边之前的最短路。 问有多少棵这样的…

android 服务端 导入工程,如何导入与配置从网上下载的android源代码及服务器端源代码...

将Android项目导入import进Eclipse。 注意SDK版本是否匹配 。 服务器部署到Tomcat下。 你得在数据库中将这个点菜系统的数据库和表建好&#xff0c;或者导入。在服务器的代码中修改好你的数据库名和密码。首先看你的服务器配置的是什么环境 一般就2种 linux系统 window系统&…