**Linux 知识补充 -- 进程间的通信** 1652270 **冯舜** 目录结构 ================= !![dir,目录结构] 无名管道 =================== ## 无名管道, 父写子读 !![fxzd,父写子读] ## 无名管道, 子写父读 !![zxfd,子写父读] ## 无名管道, 全双工 !![qsg,全双工] ## 无名管道方式传递的数据类型, 长度限制 数据类型限定为字节, 以字节流的形式传递; 当一方写, 另一方不读时, 缓冲区的大小限制了可以传输的长度, 一般是操作系统页大小乘以 16. 在本系统中为 65536, 但实测小于这个值. !![hcqdx,缓冲区大小] ## 能否在独立进程间用无名管道通信 不能在祖先不同的进程间通信, 因为祖先非相同的独立进程间, 文件描述符对应的读/写缓冲区是独立且不可互访的. 有名管道 =============== ## 有名管道, 父写子读 !![namedfxzd,父写子读] ## 有名管道, 子写父读 !![namedfdzx,子写父读] ## 有名管道, 全双工 此处要注意打开管道文件的顺序. `open()` 管道时, 会阻塞等待对方的 `open()`. 所以, 父子进程统一首先打开某个管道, 再打开另一个管道. !![namedbi,全双工] ## 有名管道在独立进程间通信 !![4-1,单向通信, 一侧] !![4-2,单向通信, 另一侧] !![5-1,双向通信, 一侧] !![5-2,双向通信, 另一侧] !![5,双向通信, 全双工方式(共用一条有名管道来读/写)] 双向通信时同样要注意打开管道时的顺序, 防止死锁. ## 有名管道方式传递的数据类型, 长度限制 限制与无名管道相同. !![5-testmax,缓冲区大小接近 65536 字节] 有名管道与无名管道的区别是, 有名管道依赖于文件系统, 允许独立进程之间的通信, 以及可以控制管道的所有者和权限. 此外, 有名管道可以是全双工的. 信号方式 ====================== ## 一对进程, 一个持续发信号, 一个持续收信号 使用 `kill()` + `pause()` + 信号处理函数. !![3-1,发信号进程与收信号进程] ## 信号能否带数据 能. 使用 `sigaction()` 注册信号处理函数, 用 `sigqueue()` 发送信号, 允许在传送信号的同时, 传送一个整数和一个指针. ## 哪几个信号不能被截获和重定义? `SIGSTOP` 和 `SIGKILL`. ## 一对进程, 利用信号和文件来互通信息 !![3-2,一对用信号互通信息的进程] 消息队列方式 ==================== ## 单向传递数据 !![m4-1,进程单向传递数据] ## 双向传递数据 本例子在同一条消息队列中双向传递数据, 但这可能造成同一进程读到自己之前写的消息的情况. 为防止这一情况发生, 可采用两条单向传递数据的消息队列. !![m4-2,进程双向传递数据] ## 消息队列方式传递的数据的类型, 长度限制, 及它和管道的不同 消息队列方式传递的数据的类型必须是一个以 `long` 型和 `char []` 型拼合的结构. 长度由这个结构中 `char[]` 数组的长度决定. 与管道不同, 消息队列方式传递数据的类型, 长度均有所其他限制; 当一个进程退出后, 它发出的消息还存在于消息队列中. 共享内存方式 ==================== ## 一对进程共享内存 !![s5,进程共享内存] ## 可否在独立进程间共享内存 可以. 例如可以使用 `ftok()` 函数, 指定同一个文件产生相同的 key 来产生相同的 Shared Memory ID. ## 两个进程同时写 若两个进程同时写, 会弄乱共享内存的内容. 可以通过进程间同步的方式防止共享内存乱. Unix 套接字方式 ======================== ## 测试程序对 !![6,用 Unix Socket 双向通信的程序对] ## Unix 类型 Socket 的建立/使用与 TCP 类型的异同 - Unix 类型依赖于文件系统中文件作为地址, TCP 类型依赖于网络 IP 地址. - Unix 类型 socket 在创建时, 可能需要移除原有文件 - 在使用时都作为可作为文件描述符的 socket. ## Unix 类型 Socket 的阻塞/非阻塞方式, 能否使用 select 读写? 写满后是返回不可写还是继续可写? 文件锁机制 ======================= ## 测试程序对 - 阻塞 !![7,阻塞的测试程序对] ## 测试程序对 - 非阻塞 !![7,非阻塞的测试程序对] 锁定文件有 flock, fnctl, lockf 等方法. 无论阻塞或非阻塞, 结果相同. flock 只能对整个文件上锁, 且是劝告性的. 而其他方式可以排他. flock() 是劝告性锁, read() write() 不会报错, 读写 0 字节 其他的 read() 不会报错, 但 write() 函数会报错.