进程间通信——FIFO(多个客户进程,一个服务进程)
FIFO简介
FIFO就是Unix的一种复合POSIX标准的进程间通信机制。他又称为命名管道,跟管道的不同点是,每个FIFO都有一个路径名与之关联。
FIFO虽然有路径名,但是他这中文件是在内核态(管道也是在内核态),跟文件系统没有关系。
单个服务器进程,多个客户端进程与服务器进通信。客户端进程想服务器进程发送请求(客户端进程通过write写FIFO),服务端处理(通过read读客户进程的请求)之后返回相应内容(通过write写入专用FIFO)。
单个服务器进程多个客户端进程通信框架
客户进程和服务器进程都知道专用FIFO的路径名,关键是怎样创建客户和服务器进程专用的FIFO。因为,一个系统的进程id是确定的并且互斥,所以我们可以通过进程id去寻找FIFO,客户进程和服务进程之间的FIFO用进程id来创建,在客户和服务器进程之间协商一个格式(比如“fifo.pid”格式)。
多个客户进程向服务器进程请求服务
本示例代码,实现的是将客户进程请求打开一个文件,具体就是客户进程传文件名,服务器进程将文件内容返回。
客户端代码:
/*
* client.c
*
* Created on: Nov 2, 2016
* Author: sujunjun
*/ #include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<limits.h>
#include<fcntl.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h> #define FIFO_SERVER "fifo.server"
#define SIZE PIPE_BUF
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) int main(){ pid_t pid=getpid();
char buf[SIZE];
char client_fifo_name[SIZE];//from server
snprintf(client_fifo_name,sizeof(client_fifo_name),"fifo.%ld",(long)pid);
if(mkfifo(client_fifo_name,FILE_MODE)< && errno!=EEXIST){
printf("mk error \n");
exit();
}
snprintf(buf,sizeof(buf),"%ld ",(long)pid);
int len=strlen(buf);
char *pathname=buf+len;
fgets(pathname,SIZE-len,stdin);
len =strlen(buf);/f include \n int writefd=open(FIFO_SERVER,O_WRONLY);
write(writefd,buf,len-);//len-1==not include \n int readfd=open(client_fifo_name,O_RDONLY);
int r;
while((r=read(readfd,buf,SIZE))>){
write(STDOUT_FILENO,buf,r);
}
close(readfd);
unlink(client_fifo_name);//delete this temp file
return ;
}
服务器代码:
/*
* server.c
*
* Created on: Nov 2, 2016
*/ #include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<errno.h>
#include<stdlib.h>
#include<fcntl.h>
#include<limits.h>
#include<string.h> #define FIFO_SERVER "fifo.server"//all known #define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) #define SIZE PIPE_BUF
int main(){
if(mkfifo(FIFO_SERVER,FILE_MODE)< && errno!=EEXIST){
printf("mk error \n");
exit();
} int readfd=open(FIFO_SERVER,O_RDONLY);
int writefd=open(FIFO_SERVER,O_WRONLY); if(readfd==-||writefd==-){
printf("open error \n");
exit();
} int r;char buf[SIZE];char *pathname;pid_t pid;char client_fifo_name[SIZE];
while((r=read(readfd,buf,SIZE))>){
buf[r]='\0';
if((pathname=strchr(buf,' '))==NULL){
printf("not include pid\n");
continue;
}
*pathname++='\0';//*pid_s=0 pid_s++
pid=atol(buf);
snprintf(client_fifo_name,sizeof(client_fifo_name),"fifo.%ld",(long)pid);
if((writefd=open(client_fifo_name,O_WRONLY))<){
printf("error\n");
continue;
}
int fd;
if((fd=open(pathname,O_RDONLY))<){
printf("open this file error\n");
write(writefd,"open this file error\n",sizeof("open this file error\n"));
close(writefd);
}else {
while((r=read(fd,buf,SIZE))>){
write(writefd,buf,r);
}
close(fd);
}
close(writefd);
}
return ;
}
运行示例:
编译两个文件
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型攻击)。
进程间通信——FIFO(多个客户进程,一个服务进程)的更多相关文章
- linux系统编程:进程间通信-fifo
进程间通信-fifo 进程间通信的还有一种方式是fifo. fifo是还有一种管道:有名管道.从名字能够看出.它也是队列. 使用fifo通信前,得先创建fifo $ mkfifo myfifo 随后仅 ...
- Android系统前台进程,可见进程,服务进程,后台进程,空进程的优先级排序
1.前台进程 前台进程是Android中最重要的进程,在最后被销毁,是目前正在屏幕上显示的进程和一些系统进程,也就是和用户正在交互的进程. 2.可见进程 可见进程指部分程序界面能够被用户看见,却不在前 ...
- Java基础面试操作题:线程同步代码块 两个客户往一个银行存钱,每人存三十次一次存一百。 模拟银行存钱功能,时时银行现金数。
package com.swift; public class Bank_Customer_Test { public static void main(String[] args) { /* * 两 ...
- 客户的一个紧急bug,我用了两种方式进行 C# 反编译修改源码
一:背景 1. 讲故事 周五下午运营反馈了一个紧急bug,说客户那边一个信息列表打不开,急需解决,附带的日志文件也发过来了,看了下日志大概是这样的: 日期:2020-11-13 12:25:45,92 ...
- 监听套接字描述字 已连接套接字描述字 和打电话的情形非常不一样的地方 完成了 TCP 三次握手,操作系统内核就为这个客户生成一个已连接套接字
1. accept: 电话铃响起了-- 当客户端的连接请求到达时,服务器端应答成功,连接建立,这个时候操作系统内核需要把这个事件通知到应用程序,并让应用程序感知到这个连接.这个过程,就好比电信运营商完 ...
- 主进程和服务进程通信调用Acrobat.AcroPDDoc时出现的问题
场景以及问题 主进程发送命令,服务进程接受到,然后执行转换pdf,调用Acrobat pdfDoc = (Acrobat.CAcroPDDoc)Microsoft.VisualBasic.Intera ...
- Oracle 进程 前台进程-服务进程
一.什么是服务进程(前台进程) 当用户运行一个应用进程时,系统会为用户运行的应用建立一个用户程序,该进程通过某种方式启动一个服务器进程(前台进程),用于处理连接到该实例的用户进程的请求. 二.服务进程 ...
- python全栈开发,Day40(进程间通信(队列和管道),进程间的数据共享Manager,进程池Pool)
昨日内容回顾 进程 multiprocess Process —— 进程 在python中创建一个进程的模块 start daemon 守护进程 join 等待子进程执行结束 锁 Lock acqui ...
- 五十一、进程间通信——System V IPC 之进程信号量
51.1 进程信号量 51.1.1 信号量 本质上就是共享资源的数目,用来控制对共享资源的访问 用于进程间的互斥和同步 每种共享资源对应一个信号量,为了便于大量共享资源的操作引入了信号量集,可对所有信 ...
随机推荐
- JDK和JRE的区别
JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE.Java工具和Java基础类库.Java Runtime Enviro ...
- hdu_5753_Permutation Bo(找规律)
题目连接:hdu_5753_Permutation Bo 题意: 给你一个有n个数的数列c1~cn,h1~hn为1~n的排列,求ci[hi>hi-1 and hi>hi+1]的期望和. ...
- 通过C++修改系统时间代码
#include <windows.h>#include <stdio.h>#include <iostream>using namespace std;int m ...
- Mac Git 学习笔记
lapommedeMacBook-Pro:~ lapomme$ cd GitHub lapommedeMacBook-Pro:GitHub lapomme$ cd lapommedeMacBook-P ...
- Unity 的ICallHander在C#项目中实现注入
项目包引用: Install-Package Unity.Interception 创建项目的接口和其实类: public interface ICalculator { double Calcula ...
- 解析JSON对象与字符串之间的相互转换
在开发的过程中,如果对于少量参数的前后台传递,可以直接采用ajax的data函数,按json格式传递,后台Request即可,但有的时候,需要传递多个参数,这样后台 接受的时候Request多个很麻烦 ...
- React和动态网站接口的经济学
来自: React and the economics of dynamic web interfaces 自从2000开始我就一直在做web开发,曾见过很多以各种库和框架的起起落落,这些库和框架作为 ...
- Inno Setup入门(十八)——Inno Setup类参考(4)
分类: Install Setup 2013-02-02 11:29 406人阅读 评论(0) 收藏 举报 编辑框 编辑框也叫文本框,是典型的窗口可视化组件,既可以用来输入文本,也可以用来显示文本,是 ...
- 12.04 ubuntu 更改IP
在一个局域网里面,如果是自动获取IP,就会导致IP冲突 进入要连接的热点进行设置 IPV4 Setting address netmask ...
- 我眼中的C#3.0 摘自于网络:http://www.cnblogs.com/joinger/articles/1297237.html
每次有新技术发布时,我们总能感受到两种截然不同的情绪: 一种是恐惧和抵抗,伴随着这种情绪的还有诸如"C# 2.0用的挺好的,为什么要在C# 3.0搞到那么复杂?"或者"我 ...