进程间通信:管道(数据传输)共享内存(数据共享)消息队列(数据传输)信号量(进程控制)Socket(实现不同主机之间的通信)
https://github.com/smile-vampire/Linux
目的:每一个进程都拥有自己的独立的虚拟地址空间和页表结构,促使了进程独立,但是也带来了进程与进程之间的相互协作,产生了进程 间通信
1.管道
匿名管道和命名管道
管道就是内核当中的一块内存,相当于内核为进程通信创建的缓冲区
匿名管道
特性:
具有亲缘关系的进程间通信
半双工通信
提供字节流服务
自带同步和互斥功能
生命周期跟随进程
命名管道:具有标识符,可以满足不同进程间通信
设置非阻塞:
如果不进行读,一直写,将写端设置为非阻塞
第一种情况:读端不关闭,调用写,write返回-1,报错当前资源不可用
第二种情况:读端关闭,调用写,就会造成写端进程收到SIGPIPE信号,写端程序会被杀死,管道破裂
如果不进行写,一直读,将读端设置为非阻塞
第一种情况:写端不关闭,调用写,read返回-1,报错当前资源不可用
第二种情况:写端关闭,调用写,read正常调用,返回读到的字节数
2.共享内存
本质:开辟一块物理空间映射到各个进程的虚拟地中空间上
创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
int shmget(key_t key, size_t size, int flag);
连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
void *shmat(int shm_id, const void *addr, int flag);
断开与共享内存的连接:成功返回0,失败返回-1
int shmdt(void *addr);
控制共享内存的相关信息:成功返回0,失败返回-1
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
特性:
最快的IPC通信,直接内存进行存储
多个进程需要同时操作,所以需要同步
3.消息队列
具有队列的的特性,底层是链表实现,在内核中创建
在队列中每一个元素都有自己的类型,类型间有优先级概念
每个节点最大发送8字节
队列当中消息长度之和16384
系统当中队列最多有2379
特性:
可以双工通信
生命周期随内核
克服了管道无格式的字节的缺点
4.信号量
作用:实现了进程的同步和互斥
本质:计数器+PCB等待队列
互斥:
前提访问:信号量计数器取值只有0、1
访问:当一个进程需要访问临界资源时,要获取信号量,对计数器进行预减操作
**同步:保证对资源访问的合理性
信号量 = 计数器 + pcb等待队列 计数器不仅仅局限0、1两个值
释放资源通知问题:小于等于0才需要通知
Socket通信
在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”*可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);将进程和网卡建立联系
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr address,
socklen_t address_len);对于服务端:将进程和端口联系起来,绑定ip+port;对于客户端不建议绑定,操作系统会自动绑定,如果自己绑定,那么客户端端口固定,就只能启动一个客户端了
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr address,
socklen_t address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
网络字节序
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可
对于传输层UDP/TCP具体下次详解
使用
1.匿名管道速度慢,容量有限,只有父子进程能通讯,命名管道可以实现不同进程间通信
2.消息队列:可以双工通信克服了管道无格式的字节的缺点,但是容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数 据的问题
4.信号量:实现同步和互斥 ,但是不能传递复杂消息
5.共享内存区:能够很容易控制容量,速度快,但要保持同步,一个进程在写的时候,另一个进程要注意读写的问题,
相当于线程中的线程安全。