linux 管道文件上机总结,[转载]LINUX 管道 fifo 等总结
Linux進(jìn)程通信:命名管道FIFO小結(jié)
Linux下進(jìn)程之間通信可以用命名管道FIFO完成。命名管道是一種特殊類(lèi)型的文件,因?yàn)長(zhǎng)inux中所有事物都是文件,它在文件系統(tǒng)中以文件名的形式存在。
在程序中,我們可以使用兩個(gè)不同的函數(shù)調(diào)用來(lái)建立管道:
#include
#include
int mkfifo(const char *filename,
mode_t mode);
int mknode(const char *filename,
mode_t mode | S_IFIFO, (dev_t) 0 );
下面先來(lái)創(chuàng)建一個(gè)管道:
#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);
}
編譯這個(gè)程序:
gcc –o fifo1.c
fifo
運(yùn)行這個(gè)程序:
$ ./fifo1
用ls命令查看所創(chuàng)建的管道
$ ls -lF
/tmp/my_fifo
prwxr-xr-x 1 root root 0 05-08
20:10 /tmp/my_fifo|
注意:ls命令的輸出結(jié)果中的第一個(gè)字符為p,表示這是一個(gè)管道。最后的|符號(hào)是由ls命令的-F選項(xiàng)添加的,它也表示是這是一個(gè)管道。
雖然,我們所設(shè)置的文件創(chuàng)建模式為“0777”,但它被用戶(hù)掩碼(umask)設(shè)置(022)給改變了,這與普通文件創(chuàng)建是一樣的,所以文件的最終模式為755。
打開(kāi)FIFO一個(gè)主要的限制是,程序不能是O_RDWR模式打開(kāi)FIFO文件進(jìn)行讀寫(xiě)操作,這樣做的后果未明確定義。這個(gè)限制是有道理的,因?yàn)槲覀兪褂肍IFO只是為了單身傳遞數(shù)據(jù),所以沒(méi)有必要使用O_RDWR模式。如果一個(gè)管道以讀/寫(xiě)方式打開(kāi)FIFO,進(jìn)程就會(huì)從這個(gè)管道讀回它自己的輸出。如果確實(shí)需要在程序之間雙向傳遞數(shù)據(jù),最好使用一對(duì)FIFO,一個(gè)方向使用一個(gè)。
當(dāng)一個(gè)Linux進(jìn)程被阻塞時(shí),它并不消耗CPU資源,這種進(jìn)程的同步方式對(duì)CPU而言是非常有效率的。
有關(guān)Linux下命名管道FIFO的讀寫(xiě)規(guī)則可以參見(jiàn)之前所寫(xiě)的一篇文章:。
一、實(shí)驗(yàn):使用FIFO實(shí)現(xiàn)進(jìn)程間通信
兩個(gè)獨(dú)立的程序:
1.
生產(chǎn)者程序,它在需要時(shí)創(chuàng)建管道,然后盡可能快地向管道中寫(xiě)入數(shù)據(jù)。
2.
消費(fèi)者程序,它從FIFO中讀取數(shù)據(jù)并丟棄它們。
生產(chǎn)者程序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);
}
消費(fèi)者程序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);
}
編譯這兩個(gè)程序:
gcc –o fifo2
fifo2.c
gcc –o fifo3
fifo3.c
運(yùn)行這兩個(gè)程序:
[root@localhost chaper12]# ./fifo2
&
à后臺(tái)執(zhí)行,寫(xiě)數(shù)據(jù)
[2] 23121
Process 23121 opening FIFO
O_WRONLY
[root@localhost chaper12]# time
./fifo3à讀數(shù)據(jù)
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
以上兩個(gè)程序均是使用阻塞模式FIFO。Linux會(huì)安排好這兩個(gè)進(jìn)程之間的調(diào)試,使它們?cè)诳梢赃\(yùn)行的時(shí)候運(yùn)行,在不能運(yùn)行的時(shí)候阻塞。因此,寫(xiě)進(jìn)程將在管道滿(mǎn)時(shí)阻塞,讀進(jìn)程將在管道空時(shí)阻塞。
虛擬機(jī)上,time命令顯示,讀進(jìn)程只運(yùn)行了0.2秒的時(shí)間,卻讀取了10M字節(jié)的數(shù)據(jù)。這說(shuō)明管道在程序之間傳遞數(shù)據(jù)是非常有效的。
二、實(shí)驗(yàn):使用FIFO的客戶(hù)/服務(wù)器應(yīng)用程序
利用FIFO實(shí)現(xiàn)一個(gè)客戶(hù)/服務(wù)器的應(yīng)用程序,服務(wù)器進(jìn)程接受請(qǐng)求,對(duì)它們進(jìn)程處理,最后把結(jié)果數(shù)據(jù)返回給發(fā)送請(qǐng)求的客戶(hù)方。
首先建立一個(gè)頭文件client.h,它定義了客戶(hù)和服務(wù)器程序都要用到的數(shù)據(jù)結(jié)構(gòu),并包含了必要的頭文件。
#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;
接下來(lái)是服務(wù)器程序server.c,在這一部分,是以只讀阻塞模式打開(kāi)服務(wù)器管道,用于接收客戶(hù)發(fā)送過(guò)來(lái)的數(shù)據(jù),這些數(shù)據(jù)采用message結(jié)構(gòu)體封裝。
#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);
}
客戶(hù)端程序client.c,這個(gè)程序用于向服務(wù)器發(fā)送消息,并接收來(lái)自服務(wù)器的回復(fù)。
#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
測(cè)試這個(gè)程序,我們需要一個(gè)服務(wù)器進(jìn)程和多個(gè)客戶(hù)進(jìn)程。為了讓多個(gè)客戶(hù)進(jìn)程在同一時(shí)間啟動(dòng),我們使用了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
分析這個(gè)例子,服務(wù)器以只讀模式創(chuàng)建它的FIFO并阻塞,直到第一個(gè)客戶(hù)以寫(xiě)方式打開(kāi)同一現(xiàn)個(gè)FIFO來(lái)建立連接為止。此時(shí),服務(wù)器進(jìn)程解除阻塞并執(zhí)行sleep語(yǔ)句,這使得來(lái)自客戶(hù)的數(shù)據(jù)排除等候。在實(shí)際應(yīng)用程序中,應(yīng)該把sleep語(yǔ)句刪除,這里面只是為了演示當(dāng)有多個(gè)客戶(hù)請(qǐng)求同時(shí)到達(dá)時(shí),程序的正確操作方法。
與此同時(shí),在客戶(hù)端打開(kāi)服務(wù)器FIFO后,它創(chuàng)建自己唯一的一個(gè)命名管道以讀取服務(wù)器返回的數(shù)據(jù)。完成這些工作后,客戶(hù)發(fā)送數(shù)據(jù)給服務(wù)器(如果管道滿(mǎn)或服務(wù)器仍處于休眠就阻塞),并阻塞于對(duì)自己FIFO的read調(diào)用上,等待服務(wù)器響應(yīng)。
接收到來(lái)自客戶(hù)的數(shù)據(jù)后,服務(wù)器處于它,然后以寫(xiě)的方式打開(kāi)客戶(hù)管道并將處理后的數(shù)據(jù)返回,這將解除客戶(hù)端的阻塞狀態(tài),客戶(hù)程序就可以從自己的管道里面讀取服務(wù)器返回的數(shù)據(jù)了。
整個(gè)處理過(guò)程不斷重復(fù),直到最后一個(gè)客戶(hù)關(guān)閉服務(wù)器管道為止,這將使服務(wù)器的read調(diào)用失敗(返回0),因?yàn)橐呀?jīng)沒(méi)有進(jìn)程以寫(xiě)方式打開(kāi)服務(wù)器管道了。如果這是一個(gè)真正的服務(wù)器進(jìn)程的話(huà),它還需要繼續(xù)等待其他客戶(hù)的請(qǐng)求,我們就需要對(duì)它進(jìn)行修改,有兩種方法:
(1)對(duì)它自己的服務(wù)器管道打開(kāi)一個(gè)文件描述符,這樣read調(diào)用將阻塞而不是返回0。
(2)當(dāng)read調(diào)用返回0時(shí),關(guān)閉并重新打開(kāi)服務(wù)器管道,使服務(wù)器進(jìn)程阻塞在open調(diào)用處以等待客戶(hù)的到來(lái),就像它最初啟動(dòng)時(shí)那樣。
總結(jié)
以上是生活随笔為你收集整理的linux 管道文件上机总结,[转载]LINUX 管道 fifo 等总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 部署项目的问题(三)—— node启动服
- 下一篇: linux通过spi和stm32通信,双