一、本地进程通信的方法
注意:在本地进程用PID来标识进程的唯一性
1.消息传递(管道、FIFO、消息队列)
①管道
(1)父进程创建管道,得到两个文件描述符指向管道的两端
(2)父进程fork出子进程,子进程也有两个文件描述符指向同⼀管道。
(3)父进程关闭fd[0],子进程关闭fd[1],即父进程关闭管道读端,子进程关闭管道写端(因为管道只支持单向通信)。父进程可以往管道里写,子进程可以从管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。
②FIFO
(1)管道与FIFO的关系
管道通信只能限制于有亲缘关系的进程通信,具有局限性,而FIFO解决了这个问题。FIFO实质也是一个管道,但是他是有路径名称的管道。
(2)FIFO的基本原则
★创建FIFO管道并为其命名
★用open函数打开管道,open函数的参数应该注明具体管道的名称
★如果当前的操作是为读而打开FIFO,则必须保证此时有一个进程为写而打开FIFO,否则将阻塞该进程直到有一个进程来写FIFO
★如果当前操作是为了写而打开FIFO,那么必须保证有一个进程是为了读而打开FIFO,否则将阻塞该进程直到有一个进程来读FIFO
③消息队列
(1)消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。
(2)消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。
(3)可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。
2.同步(读写锁、信号量)
①同步和异步
★同步:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程
★异步:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。
②读写锁(参考数据库锁机制)
避免了读取脏数据、幻读、不可重复读等问题
②信号量
(1)定义
信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。
(2)概念补充
★临界资源:一次只允许一个进程(一个线程)使用的资源叫做临界资源。
★临界区:访问临界资源的代码称为临界区。
(3)信号量基本操作
★一个信号量被初始化为非负数
★semWiat(s)操作使信号量减1,若值成为负数,则阻塞执行semWait(s)的进程
★semSignal(s)操作使信号量加1,若值小于等于0,则被semWait(s)所阻塞的进程解除阻塞
(4)信号量基本操作的通俗理解:信号量的初始值为临界区内资源可用的数量,当一个进程试图访问临界区资源的时候,要先用semWait操作询问是否还有可用资源。信号量为负值的时候说明已经没有可用资源,那么,为了避免死锁我们必须阻塞该进程,等到有可用资源再让他进入临界区。而当一个在临界区中的进程已经用完资源的时候,用semSignal操作告诉其他进程他使用完资源了,要退出临界区了,那些被阻塞的进程就可以解除阻塞去访问该进程所释放的资源了。
3.共享内存
(1)创建内存共享区,会生成key值
(2)两个进程通过key值将共享内存映射到自己的进程里
(3)没有同步机制,进程间协商进行通信
(4)撤销映射关系
(5)删除共享内存
二、网络进程通信方法
1.网络进程标识方法
网络层的“IP地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(IP地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
2.什么是Socket
Socket是TCP/IP协议的应用程序通常采用的应用编程接口,并且它的本质其实就是一类特殊的文件,一些针对于Socket的函数就是对其(读写I/O,开,关)的操作。
3.Socket的基本操作
(1)int socket(int domain int type int protocol)函数
①domain:协议域,决定了地址类型(IPV4,IPV6)
②type:socket类型,具体的字节流类型
③protocol:指定协议(传输层)如TCP、UDP
(2)int bind(int sockfd,const* struct sockaddr *addr,socklen_t addrlen)
bind()函数把一个地址族中的特定地址赋给socket, 把一个ipv4或ipv6地址和端口号组合赋给socket。
①sockfd:标识socket的唯一id
②addr:ip地址(包含地址+端口号)
③addrlen:ip地址长度
(3)int listen(int sockfd,int backlog)
listen函数将socket变为被动类型的,等待客户的连接请求。
(4)int connect(int sockfd conststruct sockaddr *addr,socklen_t addlen)
客户端通过调用connect函数来建立与TCP服务器的连接。
(5)int accept()
TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。
(6) read()、write()函数进行通信
(7)close()进行关闭