Linux-进程间通信(二): FIFO

1. FIFO:

FIFO也被成为命名管道,因其通过路径关系绑定,可以用于任意进程间通信,而普通无名管道只能用于有共同祖先的进行直接通信;

命名管道也是半双工的,open管道的时候不要以读写方式打开,这种操作是未定义的;

 

2. FIFO创建:

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

ret = 成功返回0,失败返回-1

FIFO是一种文件类型,mode参数与open函数中的mode参数相同,并且一般文件的操作函数(close, read, write, unlink等)都以用于FIFO;

 

3. 非阻塞标志(O_NONBLOCK):

(1) 阻塞模式:只读open要阻塞到某个进程为写而打开此FIFO,只写open要阻塞到某个进程为读而打开此FIFO;

(2) 非阻塞模式:只读立即返回,如果没有进程为读而打开FIFO,则只写open返回-1,erron=ENXIO;

 

4. 一端关闭:

(1) 若读一个已经关闭写端的FIFO,则读取完数据后,会读到文件结束符,read返回0;

(2) 若写一个已经关闭读端的FIFO,则产生SIGPIPE;

 

5. 用途:

(1) FIFO由shell命令使用以便将数据从一条管道传送到另一条,而无需创建临时文件;

(2) FIFO用于客户进程和服务器进程进行数据传递;

 

6. 测试代码:两个进程间通信;

fifo_writer.c -- 向fifo中写入字串

 1 #include <unistd.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 #include <limits.h>
 6 #include <sys/stat.h>
 7 #include <sys/types.h>
 8 #include <fcntl.h>
 9 
10 #define FIFO_NAME "/var/tmp/fifo_test"
11 #define BUF_LEN PIPE_BUF
12 
13 
14 int main(int argc, char *argv[])
15 {
16     int pipeid = -1;
17     int fifoid = -1;
18 
19     char buffer[BUF_LEN] = { 0 };
20 
21     if (access(FIFO_NAME, F_OK) < 0){
22         fifoid = mkfifo(FIFO_NAME, 0777);
23         if (fifoid < 0){
24             perror("mkfifo error\n");
25             return -1;
26         }
27     }
28 
29     pipeid = open(FIFO_NAME, O_WRONLY);
30     if (pipeid < 0){
31         perror("open pipeid error\n");
32         return -1;
33     }
34 
35     int read_bytes = read(STDIN_FILENO, buffer, BUF_LEN);
36     if (read_bytes < 0){
37         perror("read error\n");
38         close(pipeid);
39         return -1;
40     }
41 
42     const char * buff_send = buffer;
43     int no_write_bytes = read_bytes;
44     while (no_write_bytes > 0){
45         int n = write(pipeid, buff_send, no_write_bytes);
46         if (n < 0){
47             perror("write error\n");
48             close(pipeid);
49             return -1;
50         }
51 
52         no_write_bytes -= n;
53         buff_send += n;
54     }
55 
56     close(pipeid);
57 
58     return 0;
59 }

 

fifo_reader.c --  从fifo中读出字串

 1 #include <unistd.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 #include <limits.h>
 6 #include <sys/stat.h>
 7 #include <sys/types.h>
 8 #include <fcntl.h>
 9 
10 #define FIFO_NAME "/var/tmp/fifo_test"
11 #define BUF_LEN PIPE_BUF
12 
13 
14 int main(int argc, char *argv[])
15 {
16     int pipeid = -1;
17 
18     char buffer[BUF_LEN] = { 0 };
19 
20     pipeid = open(FIFO_NAME, O_RDONLY);
21 
22     int n = read(pipeid, buffer, BUF_LEN - 1);
23     if (n < 0){
24         perror("read error\n");
25         close(pipeid);
26         return -1;
27     }
28 
29     write(STDOUT_FILENO, buffer, n);
30 
31     close(pipeid);
32 
33     return 0;
34 }

 

7. 测试代码:多个客户端与服务器通信

模型如下图所示:

 Linux-进程间通信(二): FIFO_第1张图片

 

common.h--公共头文件

 1 #include <unistd.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <fcntl.h>
 5 #include <limits.h>
 6 #include <string.h>
 7 
 8 #define SERVER_FIFO_NAME "/var/tmp/fifoServer"
 9 #define CLIENT_FIFO_NAME "/var/tmp/fifoClient%d"
10 #define BUFF_SIZE PIPE_BUF
11 #define MSG_LEN 64
12 #define CLIENT_FIFO_NAME_LEN 64
13 
14 typedef struct fifo_msg{
15     pid_t client_pid;
16     char msg[MSG_LEN];
17 }fifo_msg_t;

 

fifo_server.c

 1 #include "common.h"
 2 
 3 int main(int argc, char *argv[])
 4 {
 5     int fifo_id = -1;
 6     int server_fifo_fd = -1;
 7 
 8     if (access(SERVER_FIFO_NAME, F_OK) < 0){
 9         fifo_id = mkfifo(SERVER_FIFO_NAME, 0777);
10         if (fifo_id < 0){
11             perror("mkfifo error\n");
12             return -1;
13         }
14     }
15 
16     server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);
17     if (server_fifo_fd < 0){
18         perror("open fifo error\n");
19         return -1;
20     }
21 
22     fifo_msg_t client_msg;
23     memset(&client_msg, 0, sizeof(client_msg));
24     int read_bytes = 0;
25 
26     do {
27         read_bytes = read(server_fifo_fd, &client_msg, sizeof(client_msg));
28         if (read_bytes < 0){
29             perror("read error\n");
30             close(server_fifo_fd);
31             return -1;
32         }
33 
34         char *tmp_msg = client_msg.msg;
35         while (*tmp_msg){
36             *tmp_msg = toupper(*tmp_msg);
37             tmp_msg++;
38         }
39 
40         char client_fifo[CLIENT_FIFO_NAME_LEN] = { 0 };
41         snprintf(client_fifo, CLIENT_FIFO_NAME_LEN - 1, CLIENT_FIFO_NAME, client_msg.client_pid);
42 
43         int client_fifo_fd = open(client_fifo, O_WRONLY);
44         if (client_fifo_fd < 0){
45             perror("open client fifo error\n");
46         }
47 
48         write(client_fifo_fd, &client_msg, sizeof(client_msg));
49         printf("write to client:%d\n", client_msg.client_pid);
50         close(client_fifo_fd);
51 
52     } while (read_bytes > 0);
53 
54     close(server_fifo_fd);
55     return 0;
56 }

 

fifo_client.c

 1 #include "common.h"
 2 
 3 int main(int argc, char *argv[])
 4 {
 5     pid_t client_pid = -1;
 6     int server_fifo_fd = -1;
 7     int client_fifo_fd = -1;
 8 
 9     server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY);
10     if (server_fifo_fd < 0){
11         perror("open server fifo error\n");
12         return -1;
13     }
14 
15     client_pid = getpid();
16 
17     char client_fifo_name[CLIENT_FIFO_NAME_LEN] = {0};
18     snprintf(client_fifo_name, CLIENT_FIFO_NAME_LEN - 1, CLIENT_FIFO_NAME, client_pid);
19     if (mkfifo(client_fifo_name, 0777) < 0){
20         perror("mkfifo client error\n");
21         close(server_fifo_fd);
22         return -1;
23     }
24 
25     fifo_msg_t client_msg;
26     memset(&client_msg, 0, sizeof(client_msg));
27     client_msg.client_pid = client_pid;
28 
29     #define TRY_TIMES 3
30     int times = 0;
31     for (times = 0; times < TRY_TIMES; times++){
32         snprintf(client_msg.msg, MSG_LEN - 1, "client_pid:%d\n", client_pid);
33         write(server_fifo_fd, &client_msg, sizeof(client_msg));
34 
35         client_fifo_fd = open(client_fifo_name, O_RDONLY);
36         if (client_fifo_fd < 0){
37             perror("open client fifo error\n");
38             close(server_fifo_fd);
39             unlink(client_fifo_name);
40             return -1;
41         }
42 
43         int n = read(client_fifo_fd, &client_msg, sizeof(client_msg));
44         if (n > 0){
45             printf("reveive msg from server:%s", client_msg.msg);
46         }
47 
48         close(client_fifo_fd);
49     }
50 
51     close(server_fifo_fd);
52     unlink(client_fifo_name);
53     return 0;
54 }

 

你可能感兴趣的:(Linux-进程间通信(二): FIFO)