Lecture 8. Unix 管道与套接字(16 页)
普通管道
- 管道(pipe) 是一种在所有 Unix 版本中都提供的进程间通信机制。现在先考虑匿名管道(普通管道)。
- 对于运行在同一设备上的进程,可以使用管道来实现高速的信息传递。
- 管道是 FIFO 的,像一个隧道。由系统内核以有限大小的 缓冲区实现。
- 匿名管道必须是两个相关的进程才可以访问。比如父进程和子进程。要让子进程拥有权限,必须先 创建管道,再创建子进程。
- 一个进程在管道的一端写入数据,另一个进程从管道的另一边读数据。因此,匿名管道是单向 的。
- 匿名管道的生命周期随进程,命名管道的生命周期随系统。也就是说当没有进程访问一个匿名管道的时候,这个匿名管道就消失了。但命名管道会像文件一样持续存在。
使用 C 语言操作匿名管道
首先,创建
stdin
,stdout
,stderr
分别是 0、1、2,因此 fdptr[0]
、fdptr[1]
最小值是 3。
接着,进行读写
char strbuff[5];
write(fdptr[1], "welcome", 7); // 向管道写入数据
int n = read(fdptr[0], strbuff, 5); // n 是实际读到的字节数
关于 read()
:
- 注意如果管道里面啥都没有,那么 read() 就会被阻塞
- 如果管道里面有东西但是不够第三个参数那么多,那么不会被阻塞,返回实际读到的字节数
命名管道 named pipe
对于两个没有直接关联的进程,如果对于同一个 file name space 具有权限,那么可以使用命名管道进行通信。
命名管道也是 FIFO 的,只不过是以类似于文件的形式存在的。甚至对于使用同样文件系统的不同设备,可以把这个命名管道用 U 盘啊之类的东西拷过去然后再进行跨设备的进程间通信。
使用 C 语言操作命名管道
首先,创建
参数解释:
mknod
用于创建文件(命名管道),名字叫 mypipe- 010777 是八进制的表示。10 表示这个文件比较特殊,777 表示 owner、group、world 三者对此文件的读、写、执行的权限
- 0 不用管
接着,进行读写
- 如果没有进程写,那么读的就会阻塞
- 如果没有进程读,那么写的就会阻塞
网络套接字
套接字是独立进程之间通信的更加常见的形式。无论是系统内核的数据结构还是文件,都可以通过套接字传输。
管道与命名管道的通信具有局限性:管道通信必须要求两个进程之间有关联,而命名管道需要使用公共文件系统。对于既不存在关联、也不共享文件系统的进程,要实现通信,就要考虑 TCP/IP 等机制。
套接字是由进程创建的,由 IP 地址与端口号组成。每一对进程需要使用一对(也就是俩)套接字进行通信。
通信服务(比如 TCP/IP),可以为不同进程之间套接字的连接提供方案。
套接字连接之后,数据(字节)从本地套接字发送到远程套接字。然后远程设备通过监听套接字上的数据变化,来接收数据。
TCP 套接字是 面向连接(connection-oriented) 的,UDP 套接字是 无连接(connectionless) 的。面向连接就会稳定一些但是牺牲一些速度,vice versa。
像 FTP 服务器使用 21 号端口,HTTP 服务器使用 80 号端口,这些小于 1024 的端口都是众所周知(well known)的。
TCP 套接字连接过程示意图
bind()
是指把特定端口和 IP 地址结合起来listen()
就是开始监听connect()
过程涉及到了 三次握手,图示如下(SYN 表示搞个序列号希望连接,ACK 表示确认)
三次握手
- A: 嗨,我想跟你初始化(SYN)一个连接
- B:好,我知道了(ACK),我跟你初始化这个连接(SYN)
- A:OK,我们的连接搞好了(ACK)
四次挥手
- A:嗨,我想跟你说的话都说完了(FIN)
- B:哦我知道了(ACK)
- (此时 B 还可以给 A 继续说话)
- B:嗨,我跟你想说的也说完了(FIN)
- A:哦我知道了(ACK)