Unix/Linux进程间通信
一,Linux下进程间通信的几种主要手段简介:
1,管道(Pipe)及有名管道(named pipe)
管道可用于具有亲缘关系进程间的通信
有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
2,信号(Signal):,
3,消息队列(Message):
消息队列是消息的链接表,包括Posix消息队列system V消息队列
消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
4,共享内存:
使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
5,信号量(Semaphore):
主要作为进程间以及同一进程不同线程之间的同步手段。
6,套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。
二,管道
参考https://www.cnblogs.com/cfans1993/p/5657478.html
https://www.cnblogs.com/52php/p/5878029.html
https://www.cnblogs.com/52php/p/5840229.html
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
- 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
- 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
- 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
- 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
2.1 pipe
#include <unistd.h>
int pipe(int fd[2])
- 专用于父子进程通信, 函数原型 int pipe(int fd[2])
- fd[0]表示输入, fd[1]表示输出
- 如果父子进程要双向通信, 可以通过类似信号的功能进行控制, 也可以简单地打开两个pipe
- 用read,Wright 读写
- 只有阻塞方式
当管道的写端存在时,数据不能超过PIPE_BUF 注:(不同系统要求的PIPE_BUF不一样,通常为512字节)。
2.2 popen和pclose
#include <stdio.h>
FILE* popen(const char *command, const char *open_mode);
int pclose(FILE *stream_to_close);
- 函数原型FILE *popen(const char *cmdstring, const char *type) , type的参数为"r"或"w"
- 用于父子进程通信, popen会自动fork子进程、创建pipe和关闭不需要的pipe端
- popen的实现有可理解为execl("/bin/sh","sh","-c",cmdstring,NULL)
- 当父进程向子进程发送信息时(type="w"), 实际就是向shell发送命令;
当父进程从子进程获取信息时(type="r"), 实际就是读取shell的执行结果 - 虽然popen的返回是FILE,但关闭是要用pclose(fp)
- 用fread 和fwright写
- 只有阻塞方式
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define MAXLINE 1024
void err_quit(const char *str){
perror(str);
exit(1);
}
int main(){
char line[MAXLINE];
FILE *fpin;
if((fpin=popen("ls -l","r")) == NULL)
err_quit("popen error");
while(fgets(line,MAXLINE,fpin) != NULL){
if(fputs(line,stdout) ==EOF)
err_quit("fputs error");
}
if(ferror(fpin))
err_quit("fpin error");
if(pclose(fpin)==-1)
err_quit("pclose error");
return 0;
}
2.3 fifo
- int mkfifo(const char *pathname,mode_t mode), 创建一个通信文件, 参数同open
- mkfifo后, 以open打开文件pathname, 打开方式为只读或只写, 另外可以用阻塞或非阻塞方式打开
- 以只读打开时, 函数会阻塞直到有进程以只写方式打开
- 以只写打开时, 函数会阻塞直到有进程以只读方式打开
- 可用于非父子进程通信, 不同的进程只需要将pathname设置为同一文件,就可以通信。双向通信时开需两个
- 在一个进程中用mkfifo将一个文件设置为FIFO模式,同时open函数打开,read,Wright读写,另外一个进程只需要open和read,wright
三, 信号量
https://www.cnblogs.com/52php/p/5851570.html
3.1 信号量的工作原理
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,
因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。
3.2、semget()函数
它的作用是创建一个新信号量或取得一个已有信号量,原型为:
int semget(key_t key, int num_sems, int sem_flags);
key是整数值(唯一非零),不相关的进程可以通过它访问一个信号量,比如每个进程都调用:
sem_id = semget((key_t) 1234, 1, 0666 | IPC_CREAT);就可以访问同一个信号量
3.3 semop()函数
它的作用是改变信号量的值,原型为:
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
四,共享内存
参考:https://www.cnblogs.com/52php/p/5861372.html
4.1概念
不同进程之间共享的内存通常安排为同一段物理内存。通常与信号量一起用。
4.2 函数
int shmget(key_t key, size_t size, int shmflg);//不同的进程使用相同的key值,通常置为整形,就可以访问同一块共享内存
void *shmat(int shm_id, const void *shm_addr, int shmflg); // attach启动对该共享内存的访问,可以用memcpy直接操作空间
int shmdt(const void *shmaddr); //detach 该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。
int shmctl(int shm_id, int command, struct shmid_ds *buf); //用来控制共享内存
五,消息队列
5.1 概念
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 消息队列与命名管道一样,每个发送的数据块都有最大长度的限制。Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。
5.2 函数
int msgget(key_t, key, int msgflg);//创建和访问消息队列
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);//把消息添加到消息队列中
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);//从一个消息队列获取消息
int msgctl(int msgid, int command, struct msgid_ds *buf);//控制消息队列
六,socket
https://www.cnblogs.com/52php/p/5872596.html
6.1 概念
套接字的特性由3个属性确定,它们分别是:域、类型和协议。
套接字的域:
AF_INET,它指的是Internet网络
AF_UNIX表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。
套接字类型
流套接字 SOCK_STREAM: TCP
数据报套接字SOCK_DGRAM :UDP
6.2 套接字地址
不同的域,有不同的套接字地址格式
对于AF_UNIX域套接字来说,它的地址由结构sockaddr_un来描述,该结构定义在头文件sys/un.h中,它的定义如下:
1
2
3
4
|
struct sockaddr_un { sa_family_t sun_family; // AF_UNIX,它是一个短整型 char sum_path[]; // 路径名 }; |
对于AF_INET域套接字来说,它的地址结构由sockaddr_in来描述,它至少包括以下几个成员:
1
2
3
4
5
|
struct sockaddr_in { short int sin_family; //AF_INET unsigned short int sin_port; //端口号 struct in_addr sin_addr; //IP地址 }; |
6.3 基于流套接字(tcp)的客户/服务器的工作流程
6.3.1 服务器
socket-》bind-》listen-》accept
6.3.1 客户端
socket-》connect
6.4 基于流套接字(tcp)的客户/服务器的工作流程
6.4.1 服务器
socket-》bind-》recvfrom/sendto
6.4.1 客户端
socket-》recvfrom/sendto
七,信号
https://www.cnblogs.com/52php/p/5813867.html
信号的名称是在头文件signal.h中定义的,信号都以SIG开头,常用的信号并不多,常用的信号如下:
更多的信号类型可查看附录表。
Unix/Linux进程间通信的更多相关文章
- Unix/Linux进程间通信(一):概述
序 Linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进 ...
- Unix/Linux进程间通信(二):匿名管道、有名管道 pipe()、mkfifo()
1. 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管 ...
- UNIX/Linux进程间通信IPC---管道--全总结(实例入门)
管道 一般,进程之间交换信息的方法只能是经由fork或exec传送打开文件,或者通过文件系统.而进程间相互通信还有其他技术——IPC(InterProcessCommunication) (因为不同的 ...
- Linux进程间通信(一): 信号 signal()、sigaction()
一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...
- Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()
下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...
- Linux进程间通信(七):消息队列 msgget()、msgsend()、msgrcv()、msgctl()
下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信 -- 使用命名管道 一.什么是消息队列 消息队列提 ...
- linux运维的认知及RHEL7 Unix/Linux 系统 介绍和安装
如何成为一个优秀的linux运维人员? 如果你有机会和条件:环境能够磨练一个人的能力和意志. 大胆的做你从未做过的项目,每一个项目都是对自身的极大提升. 有好的环境资源不 ...
- Linux 进程间通信(一)
Linux 进程间通信 进程是一个独立的资源分配单位,不同进程之间的资源是相互独立的,没有关联,不能在一个进程中直接访问另一个进程中的资源.但是,进程不是孤立的,不同的进程之间需要信息的交换以及状态的 ...
- linux进程间通信-概述
一 进程间通信有如下的目的: 1.数据传输,一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M之间:2.共享数据,多个进程想要操作共享数据,一个进程对数据的修改,其他进程应该立刻看到 ...
随机推荐
- eclipse get set 自动添加注释
编码的时候通常要用到 JavaBean ,而在我们经常把注释写在字段上面,但生成的Get/Set方法不会生成,通过修改Eclipse源码可解决,直接上例子: /** * 员工ID */ private ...
- Python3+SQLAlchemy不使用字段名获取主键值教程
一.说明 1.1 环境说明 user model如下,且其现有一个实例user_inst: class User(Base): __tablename__ = 'users' username = C ...
- 201621123075《Java程序设计》第1周学习总结
1.本周学习总结 本周简单了解了一些Java的基本概念,如Java的用途,功能.也学习了一些变量,类型和运算符.我感觉学好Java也是不容易的,尽管它库函数丰富,可最重要的还是那一份创造力. 2.书面 ...
- day35-python 操作memcache二
Memcache常用命令 存储命令: set/add/replace/append/prepend/cas 获取命令: get/gets 其他命令: delete/stats.. add方法 添加一条 ...
- 显示“快捷键清单” acessksy
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- eclipse工具类及插件(修改eclipse.ini文件及作者名字)
https://jingyan.baidu.com/album/9158e0005633c0a254122807.html?picindex=1 (修改eclipse.ini文件及作者名字) http ...
- open live writer安装教程和账号配置
第一步:Open Live Writer软件下载.官方地址:http://openlivewriter.org/ 第二步:双击安装文件(OpenLiveWriterSetup.exe),然后点击下一步 ...
- 通过pid杀死进程
bool ****::KillProcess(DWORD pid) { // When the all operation fail this function terminate the " ...
- yarn不是内部指令 react-native不是内部指令
1.先查看是否全局安装 2.我遇到的是,全局安装了,依然有问题. 昨天装了一个高版本的node,成功后有个黑窗口我点了几个回车,在我的环境变量里加了一大推重复的变量,删除就正常了,如下图是我删完之后的
- vscode 插件推荐 - 献给所有前端工程师(更新与2018.8.1)
VScode现在已经越来越完善.性能远超Atom和webstorm,你有什么理由不用它?在这里,我会给你们推荐很多实用的插件,让你对 vscode 有更深刻的体会,渐渐地你就会知道它有多好用. 走马观 ...