zoukankan      html  css  js  c++  java
  • 进程间通信——FIFO(多个客户进程,一个服务进程)

    FIFO简介

    FIFO就是Unix的一种复合POSIX标准的进程间通信机制。他又称为命名管道,跟管道的不同点是,每个FIFO都有一个路径名与之关联。

    FIFO虽然有路径名,但是他这中文件是在内核态(管道也是在内核态),跟文件系统没有关系。

    单个服务器进程,多个客户端进程与服务器进通信。客户端进程想服务器进程发送请求(客户端进程通过write写FIFO),服务端处理(通过read读客户进程的请求)之后返回相应内容(通过write写入专用FIFO)。

    单个服务器进程多个客户端进程通信框架

    客户进程和服务器进程都知道专用FIFO的路径名,关键是怎样创建客户和服务器进程专用的FIFO。因为,一个系统的进程id是确定的并且互斥,所以我们可以通过进程id去寻找FIFO,客户进程和服务进程之间的FIFO用进程id来创建,在客户和服务器进程之间协商一个格式(比如“fifo.pid”格式)。

    多个客户进程向服务器进程请求服务

    本示例代码,实现的是将客户进程请求打开一个文件,具体就是客户进程传文件名,服务器进程将文件内容返回。

    客户端代码:

     1 /*
     2  * client.c
     3  *
     4  *  Created on: Nov 2, 2016
     5  *      Author: sujunjun
     6  */
     7 
     8 
     9 #include<stdio.h>
    10 #include<unistd.h>
    11 #include<sys/stat.h>
    12 #include<limits.h>
    13 #include<fcntl.h>
    14 #include<stdlib.h>
    15 #include<errno.h>
    16 #include<string.h>
    17 
    18 #define FIFO_SERVER "fifo.server"
    19 #define SIZE PIPE_BUF
    20 #define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
    21 
    22 int main(){
    23 
    24     pid_t pid=getpid();
    25     char buf[SIZE];
    26     char client_fifo_name[SIZE];//from server
    27     snprintf(client_fifo_name,sizeof(client_fifo_name),"fifo.%ld",(long)pid);
    28     if(mkfifo(client_fifo_name,FILE_MODE)<0 && errno!=EEXIST){
    29             printf("mk error 
    ");
    30             exit(1);
    31     }
    32     snprintf(buf,sizeof(buf),"%ld ",(long)pid);
    33     int len=strlen(buf);
    34     char *pathname=buf+len;
    35     fgets(pathname,SIZE-len,stdin);
    36     len =strlen(buf);/f include 
    
    37 
    38     int writefd=open(FIFO_SERVER,O_WRONLY);
    39     write(writefd,buf,len-1);//len-1==not include 
    
    40 
    41     int readfd=open(client_fifo_name,O_RDONLY);
    42     int r;
    43     while((r=read(readfd,buf,SIZE))>0){
    44         write(STDOUT_FILENO,buf,r);
    45     }
    46     close(readfd);
    47     unlink(client_fifo_name);//delete this temp file
    48     return 0;
    49 }
    View Code

    服务器代码:

     1 /*
     2  * server.c
     3  *
     4  *  Created on: Nov 2, 2016
     5  */
     6 
     7 #include<stdio.h>
     8 #include<unistd.h>
     9 #include<sys/stat.h>
    10 #include<errno.h>
    11 #include<stdlib.h>
    12 #include<fcntl.h>
    13 #include<limits.h>
    14 #include<string.h>
    15 
    16 #define FIFO_SERVER "fifo.server"//all known
    17 
    18 #define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
    19 
    20 #define SIZE PIPE_BUF
    21 int main(){
    22     if(mkfifo(FIFO_SERVER,FILE_MODE)<0 && errno!=EEXIST){
    23         printf("mk error 
    ");
    24         exit(1);
    25     }
    26 
    27     int readfd=open(FIFO_SERVER,O_RDONLY);
    28     int writefd=open(FIFO_SERVER,O_WRONLY);
    29 
    30     if(readfd==-1||writefd==-1){
    31         printf("open error 
    ");
    32         exit(1);
    33     }
    34 
    35     int r;char buf[SIZE];char *pathname;pid_t pid;char client_fifo_name[SIZE];
    36     while((r=read(readfd,buf,SIZE))>0){
    37         buf[r]='';
    38         if((pathname=strchr(buf,' '))==NULL){
    39             printf("not include pid
    ");
    40             continue;
    41         }
    42         *pathname++='';//*pid_s=0  pid_s++
    43         pid=atol(buf);
    44         snprintf(client_fifo_name,sizeof(client_fifo_name),"fifo.%ld",(long)pid);
    45         if((writefd=open(client_fifo_name,O_WRONLY))<0){
    46             printf("error
    ");
    47             continue;
    48         }
    49         int fd;
    50         if((fd=open(pathname,O_RDONLY))<0){
    51             printf("open this file error
    ");
    52             write(writefd,"open this file error
    ",sizeof("open this file error
    "));
    53             close(writefd);
    54         }else {
    55             while((r=read(fd,buf,SIZE))>0){
    56                 write(writefd,buf,r);
    57             }
    58             close(fd);
    59         }
    60         close(writefd);
    61     }
    62     return 0;
    63 }
    View Code

    运行示例:

    编译两个文件

    gcc client.c -o client

    gcc server.c -o server

    ./server

    ./client  

    ./client  

    ./client

    多开几个客户进程,请求打开不同的文件,就会看到显示的文件内容。

    总结

    本例子设计的是一个迭代服务器,如果要设计一个并发服务器,还需要一些多线程编程的知识。

    还是要对FIFO一些特性要熟悉,比如open一个FIFO的时候,阻塞和非阻塞open之间的区别。还有FIFO的一次请求字节数必须小于等于PIPE_BUF(在limits.h中),这样能保证一次读请求是原子操作。如果不是原子的,那么两次请求的字节内容将无法区分。因为服务器进程是一直在循环读请求字节(服务器进程里有一个大循环,read用readline代替就更好理解了)。

    snprintf()函数还是比较方便,java中提供的一些字符串与数字之间转换的便利操作,其实在C语言中也有,只不过被我们忽视了。snprintf函数就为我们提供了一个很好的数字转换为字符串的函数。例如:snprintf(buf,buf的长度,"process id is %ld",(long)getpid());最后buf中存放的是"process id is 1234"(进程具体ID).

    另外,迭代服务器存在一些弊端,就是在处理服务型攻击的时候比较麻烦,这个不如并发服务器好处理。

    服务型攻击,就拿咱们的这个代码来说,如果咱们的客户进程只是请求服务,却从不打开自己进程与服务器专用FIFO来读服务回传的内容,这个时候,服务器可能就处于停顿状态。这就叫服务型攻击(DoS型攻击)。

  • 相关阅读:
    来实现一个缩水版Vuex
    vue中的适配:px2rem
    Vue.js的复用组件开发流程
    Vue调试神器之Vue.js devTools
    浅析Vue响应式原理(三)
    逐行粒度的vuex源码分析
    vue源码解读-目录结构
    Vue源码探究-虚拟DOM的渲染
    利用hash或history实现单页面路由
    passive的作用和原理
  • 原文地址:https://www.cnblogs.com/sylz/p/6022362.html
Copyright © 2011-2022 走看看