zoukankan      html  css  js  c++  java
  • 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
    ");
    25             return -1;
    26         }
    27     }
    28 
    29     pipeid = open(FIFO_NAME, O_WRONLY);
    30     if (pipeid < 0){
    31         perror("open pipeid error
    ");
    32         return -1;
    33     }
    34 
    35     int read_bytes = read(STDIN_FILENO, buffer, BUF_LEN);
    36     if (read_bytes < 0){
    37         perror("read error
    ");
    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
    ");
    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
    ");
    25         close(pipeid);
    26         return -1;
    27     }
    28 
    29     write(STDOUT_FILENO, buffer, n);
    30 
    31     close(pipeid);
    32 
    33     return 0;
    34 }

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

    模型如下图所示:

     

    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
    ");
    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
    ");
    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
    ");
    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
    ");
    46         }
    47 
    48         write(client_fifo_fd, &client_msg, sizeof(client_msg));
    49         printf("write to client:%d
    ", 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
    ");
    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
    ");
    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
    ", 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
    ");
    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 }
  • 相关阅读:
    工作中问题的总结1
    linux问题故障
    时间转换
    Tips
    总结
    方向
    同步&异步-阻塞&非阻塞
    IO 之 mark()、reset()
    GC日志分析
    JDK 部分工具使用方法
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/5296467.html
Copyright © 2011-2022 走看看