高级io
先介绍记录锁的概念和记录锁的数据结构。然后介绍阻塞io,非阻塞IO,异步io,IO多路转接等概念,后者都是针对前者更优的技术。IO多路转接技术包括:select,peslect,poll。最后介绍存储映射IO。
进程间通信
介绍了基本进程间通信机制,包括两大类:
- 进程间数据共享:管道,FIFO,消息队列和共享存储
- 进程间数据同步:信号量
网络进程间通信
介绍网络间的进程通信机制:套接字。首先是如何寻址。然后介绍socket编程的连接建立,数据传输等。
高级进程间通信
高级进程间通信提供一种可以在进程间传递文件描述符的机制,包括STREAMS管道和unix域套接字
需要C/C++ Linux服务器架构师学习资料后台私信“资料”(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
![a671b1d6dfe00928957c7a9822f020be.png](https://i-blog.csdnimg.cn/blog_migrate/64132de6b944483fdbdc7629826714e2.jpeg)
一. 高级IO
1. 非阻塞IO
1.1 概念
- 非阻塞io使得与磁盘io有关的系统调用永远不会被阻塞
- 这些io相关的系统调用有:open,read,write
- 如果这种操作不能完成,则调用立即出错返回
1.2 如何指定非阻塞io
- 如果调用open获得文件描述符,可指定O_NONBLOCK标识
- 对于已经打开的文件描述符,可调用fcntl,由该函数打开O_NONBLOCK标识
2. 记录锁
2.1 概述
- 概念:当一个进程正在读或修改文件的某个部分时,可以阻止其他进程修改同一文件区
- flock:文件锁,早期的unix只支持锁整个文件,使用该函数
- fcntl:记录锁,允许锁文件中的任意字节数的区域
2.2 fcntl
![937367e4aa2dfaf5b1c89c65de8004fe.png](https://i-blog.csdnimg.cn/blog_migrate/8bfd599a3fe5bb837531b0a19fe56b8d.jpeg)
cmd:
F_GETLK:获取锁信息
F_SETLK:设置锁信息
F_SETLKW:阻塞版本的F_SETLK
flockptr:指向flock的指针struct flock{ short l_type;//F_RDLCK共享读锁,F_WRLCK独占写锁,F_UNLCK解锁 off_t l_start;//加锁区域其实位置 short l_whence;//和start一起确定加锁位置 off_t l_len;//加锁长度 pid_t l_pid;//进程id }
不同锁的兼容性:针对同一把锁。如果不同锁,新锁总是覆盖旧锁
![1fc0be81d790188ee9096238d16e7b06.png](https://i-blog.csdnimg.cn/blog_migrate/a825fdf6877acc8b7f815c34a50dcc28.jpeg)
2.3 锁的隐含继承和释放
- 进程终止时,所建立的锁全部释放
- 关闭文件描述符时,文件描述符引用的文件上的任何一把锁都被释放
- fork产生的子进程不继承父类设置的锁
- 执行exec后,新进程可以继承原程序的锁
2.4 FreeBSD中记录锁的数据结构
![af2318ef7e626e35af3f1dd6c3392207.png](https://i-blog.csdnimg.cn/blog_migrate/487186603688b76315c0fb4bb4bdb6c4.jpeg)
- v节点表的i节点结构串联起所有的lockf结构
- 每个lockf结构说明了一个给定进程的一个加锁区域
- 在父进程中,关闭任意一个文件描述符,内核都会遍历i节点各项lockf,并释放持有的锁
3. 系统v流机制
3.1 基本概念
- STREAMS是系统V提供的构造内核设备驱动程序和网络协议包的一种通用方法。不同于标准io中的stream
- 流在用户进程和设备驱动程序之间提供一条全双工通路,流无需和实际硬件设备之间会话
- 简单流的基本结构:
![174c8ea36e64e625ec1bc37ae7248953.png](https://i-blog.csdnimg.cn/blog_migrate/672b0cfad671c3e7c91db180ec47b879.jpeg)
3.2 STREAMS消息
- STREAMS的所有输入输出都基于消息
- 流首和用户进程进行消息交换的函数:read,write,ioctl,getmsg,getpmsg,putmsg,putpmsg
- 消息可以顺流而下,也可以逆流而上
- 消息的组成:消息类型,控制信息,数据。控制信息和数据由strbuf指定:
![659d9f30b1279634655364d775cd17f4.png](https://i-blog.csdnimg.cn/blog_migrate/139be387cf22f93de1f244a00492c2e4.jpeg)
- 消息约有25种,但一般使用的只涉及三种: M_DATA:用户数据M_PROTO:协议控制信息M_PCPROTO:高优先级协议控制信息
- 每个输入STREAMS模块有两个输入队列,一个来自上面模块的消息,另一个来自下面模块的消息
- 流中的消息都有一个排队优先级,通过优先级波段指定
3.3 putmsg和putpmsg
- 用于将STREAMS消息写入流中
- 后者允许指定优先级波段
3.4 getmsg和getpmsg
- 从流首读STREAMS消息
4. IO多路转接
4.1 阻塞io
- 读取一个文件描述符对数据,如果没有数据就一直阻塞住
- 缺点:长时间阻塞在同一个文件描述符,另一个文件描述符虽然有很多数据却得不到及时处理
4.2 非阻塞io
- 将两个文件描述符都设置为非阻塞的
- 对第一个文件描述符发送read,如果该输入上有数据,则读取并处理。如无数据则立即返回。
- 第二个描述符重复上一步操作
- 若干秒后,重复执行以上步骤,即轮询
- 缺点:浪费cpu时间,大多数时间实际上上无数据可读的。轮询的时间间隔也很难确定
4.3 异步io
- 当一个文件描述符已准备好可以进行io时,用一个信号通知它
- 缺点:并发所有的系统都支持,其次这种信号对每个进程而言只有一个
4.4 IO多路转接
- 一种比异步IO更好的处理IO的技术
- 先构造一张有关描述符的图表,然后调用一个函数,直到这些描述符中至少一个准备好io时,该函数才返回。返回时,告诉哪些文件描述符已准备好可以io
- 支持IO多路转接的函数:poll,pselect,select
4.5 select
![d1b9f3a81b51fed1945a831b6acab991.png](https://i-blog.csdnimg.cn/blog_migrate/dcdbd525ea064fb23eac476df296a36e.jpeg)
readfds:可读描述符集,每一个文件描述符占一位
内部结构视图
![c5324596602a6740824436430ba1ac41.png](https://i-blog.csdnimg.cn/blog_migrate/c0ed95f58652c73ea92cdc0ba043ee9a.jpeg)
描述符集的设置函数
![670a9265faaece7ce9de3101b2241479.png](https://i-blog.csdnimg.cn/blog_migrate/b23a0fed67c11c5c99dca04b3102a849.jpeg)
maxfdp1:最大描述符+1,可设置为FD_SETSIZE(1024)
writefds:可写描述符集
exceptfds:异常描述符集
tvptr:愿意等待的时间 NULL:永远等待,捕捉到信号则中断等待时间每个字段为0:完全不等待,测试指定的文件描述符并立即返回不为0:实际等待的时间
返回值: 返回-1:表示出错,文件描述符没有准备好时收到信号,此时不修改文件描述符返回0:已经超时了,指定都文件描述符都没有准备好正数:已经准备好的文件描述符数量(每个文件描述符读写单独各算一次)
4.6 pselect
pselect与select类似,仅仅少部分有差异,如下:
超时值的数据结构不同
pselect超时值为const,不可改变
可使用信号屏蔽字
![42c63f5bec047f8bc9d31caf63ee20c7.png](https://i-blog.csdnimg.cn/blog_migrate/5260fd8b188b92c8d4ca620108cb6028.jpeg)
4.7 poll
![365c4f16c7d460aa5846c331ac68951b.png](https://i-blog.csdnimg.cn/blog_migrate/99de80a8ee7094be58359ef6bf8e3fae.jpeg)
poll类似与select,不过接口有所不同
不是为每个状态构造文件描述符集,而是构造一个pollfd的数组,数组每个元素指定文件描述符编号和关心的状态
![543b8743333a7d4278ca5fa545b1ab0b.png](https://i-blog.csdnimg.cn/blog_migrate/a5b9008d839efbe6d81dcae18816af19.jpeg)
参数: events:用户设置关心的事件 reevents:内核返回文件描述符事件
![8b9d78cc79d8e1c849b3fb64a180ba50.png](https://i-blog.csdnimg.cn/blog_migrate/5d544b9179f5be9456cb41741c8eb262.jpeg)
5. 异步IO
5.1 概述
异步io并不像select和poll对所有文件描述符都生效
- SystemV系统:只对STREAMS设备和STREAMS管道起作用,发送SIGPOLL信号
- BSD系统:只对终端和网络起作用,发送SIGIO信号
5.2 SystemV异步IO
- 启动异步IO,需要调用ioctl,第二个参数为I_SETSIG
- 同时,在调用ioctl之前建立信号处理程序
5.3 BSD异步IO
异步IO是SIGIO(通用异步io)和SIGURG(通知网络进程数据到达)两个信号的组合
- 调用signal或signalaction为SIGIO建立信号处理程序
- 以命令F_SETOWN调用fcntl设置进程id和进程组id,将接收对于该描述符的信号
- 以命令F_SETFL调用fcntl设置O_ASYNC文件状态标识,使文件描述符上可以进行异步IO
6. readv和writev
- 用于在一次函数调用中读写多个非连续的缓冲区
![a5efbe7570093a615eae60dd2a7b15e5.png](https://i-blog.csdnimg.cn/blog_migrate/b3d95b3d2366e246f0eede92ee086b6c.jpeg)
7. readn和writen
- 按需多此调用read和write,直至读写了N各字节数据
- 使用与读写管道,网络设备或终端数据
![71e8ffaebb4ea06cceac987271fd6292.png](https://i-blog.csdnimg.cn/blog_migrate/d96b75da772e3bc157b7e0f8e64992d9.jpeg)
8. 存储映射IO
- 使一个磁盘空间与一个存储空间中的缓冲区映射。当从缓冲区取数据,就相当于读文件中的相应字节。写数据到缓冲区相当于自动写入文件。这样就可以不用read和write的情况下执行io
- 文件映射到存储区:
![2da3ce14946630f1cbcd14a161bea461.png](https://i-blog.csdnimg.cn/blog_migrate/f9e1ba9e36130749ef45908f9589e29f.jpeg)
- addr:存储映射起始地址,通常设置为0,表示由系统选择地址然后作为返回值返回
- port:说明对存储映射区的保护要求,权限不能超过文件本身权限 PORT_READ:映射区可读PORT_WRITE:映射区可写PORT_EXEC:映射区可执行PORT_NONE :映射区不可访问
- flag: MAP_FIXED:返回值必须等于addr,不利于移值MAP_SHARED:存储操作的配置MAP_PRIVATE:创建私有副本
- 更改存储映射区权限:mprotect
- 刷新映射存储区:msync
- 解除存储映射区:munmap
二. 进程间通信
进程间通信机制包括:
- 经典IPC:管道,FIFO,消息队列,信号量,共享存储
- 网络IPC:套接字
1. 管道
1.1 概述
- 最古老的ipc机制
- 管道有两个局限性: 历史上,它是半双工的,即数据只能在一个方向流动。虽然现在某些系统提供全双工,但是为了移植性,不假定它有此特性他们只能在具有公共祖先的进程之间使用
- 尽管有局限性,半双工管道仍然是最常用的ipc
- 若write写一个尚无进程为读而打开的管道,产生SIGPIPE信号
- 若管道的最后一个写进程关闭该管道,则为管道的读进程产生文件结束标识
1.2 管道的创建
![0b6c58c9769ba93f9b67e1fb406b7413.png](https://i-blog.csdnimg.cn/blog_migrate/6f0a6dd49f50a1236ae4fed93fc4a9cf.jpeg)
- 参数fields传入两个文件描述符,field[0]为读而打开,field[1]为写而打开,field[1]的输出是field[0]的输入
- 管道模型:
![d2d71cf903e230fe65c4d8c593936d0a.png](https://i-blog.csdnimg.cn/blog_migrate/4df95f335b7f02aaaf02a7ea19a6a2e6.jpeg)
1.3 popen和pclose
![ff84a05015540964b45f6a7bf421d5a7.png](https://i-blog.csdnimg.cn/blog_migrate/209d5924bc5caf995383dca6bccca986.jpeg)
- popen先执行fork,然后调用exec以执行cmdstring,并返回标准io文件指针。如果type=“r“,文件指针连接到cmdstring的标准输出。如果type=“w”,文件指针连接到cmdstring的标准输入
- pclose关闭标准io流
1.4 FIFO
- FIFO也成为命名管道,通过FIFO,不相关的进程也能交换数据
- 创建FIFO:
![6ef25bd71a137f0614ef1757f2ff3db6.png](https://i-blog.csdnimg.cn/blog_migrate/4465609a70f8ce58cb772946722e46c6.jpeg)
- mode参数与open函数一致
- 非阻塞标准O_NONBLOCK: 没有指定该参数:只读open要阻塞到某个其他进程为写而打开此FIFO指定该参数:只读open立即返回。没有进程打开FIFO,将出错返回-1
- 类似与管道,若write写一个尚无进程为读而打开的FIFO,产生SIGPIPE信号。若FIFO的最后一个写进程关闭该FIFO,则为FIFO的读进程产生文件结束标识
- PIPE_BUF说明了可被原子写到FIFO的最大数据量
- FIFO的用途 由shell命令使用,以便将数据从一条管道线传到另一条,无需创建中间临时文件用于客户-服务器进程中,以在客户进程和服务器进程间传递数据
2. XSI IPC
消息队列,信号量和共享存储,这三种IPC称做XSI IPC,他们之间有很多共性,包括:
2.1 标识符和键
- 标识符:唯一标识IPC对象的内部名,非负整数
- 键:IPC对象的外部名,使多个合作进程能在同一个IPC对象上会合。键基本数据类型为key_t
- 客户进程和服务器进程在同一IPC上会合的方法: 服务器进程指定键IPC_PRIVATE创建一个新的IPC结构,将返回的标识符放到某处(文件)给客户进程使用。缺点:要分别读写文件在公共头文件中定义一个键,服务器进程指定该键创建IPC结构。缺点:可能IPC已经存在,获取时会出错客户进程和服务器进程认同一个路径名和项目id,接着调用ftok将两个值变换为键,再调用方法2
2.2 权限结构
- XSI IPC为每个IPC结构设置了一个ipc_perm结构,规定了权限和所有者。
![47c60453a23d35bbf6a627733a757ef0.png](https://i-blog.csdnimg.cn/blog_migrate/c0ff491ec4250676100a47e8876c7320.jpeg)
2.3 结构限制
- 三种形式的IPC都有内置限制
2.4 优点和缺点
缺点
- IPC结构是在系统范围内起作用的,没有访问计数
- IPC结构在文件系统中没有名字,不能修改属性,不能ls查看IPC对象,不能用rm删除,也不能用chmod修改权限。不能用文件描述符,也就不能使用select,poll模型
优点
- 可靠
- 流是受控的:缓冲区资源紧张,进程就休眠
- 面向记录
- 可以用非先进先出方式处理
特征对比
![a57b2faee4d9876c8f9ff67615d00d17.png](https://i-blog.csdnimg.cn/blog_migrate/0542f504444ac3d05ce9fec62a779ca9.jpeg)
3. 消息队列
3.1 概述
- 消息的链接表,存放在内核中,由消息队列标识符标识
- 最开始出现的为了提供比一般IPC更高速度的通讯方式,但现在速度上没有优势,已经不再使用了
- 创建或打开队列:msgget
- 发送消息:msgsend
- 获取消息:msgrcv,不一定先进先出,可按消息的类型字段取
3.2 数据结构
- 每个队列相关的数据结构
![25b98bd4c26faa436c10cd4d6ac8e17f.png](https://i-blog.csdnimg.cn/blog_migrate/500f8aca13e3f56b3007aef9311fac25.jpeg)
- 消息队列在各个系统中的参数限制
![cb4ae4c255c9a117b401d3ff64a4b2ed.png](https://i-blog.csdnimg.cn/blog_migrate/14dece52defd3fa6301606481bc8bb51.jpeg)
3.3 msgctl函数
msgctl函数对队列执行多装操作(类似于ioctl,垃圾桶函数)
![28a1a07b144c63353c6c85992950751a.png](https://i-blog.csdnimg.cn/blog_migrate/f2cdb4a89ff39ab8e9e3f5a745529419.jpeg)
- cmd:要执行的命令 IPC_STATE:获取msgid_ds结构,并放入buf参数IPC_SET:按buf值,设置数据IPC_RMID:删除队列和数据
3.4 msgsend函数
![fb83ab4702bbc80e353e568be8519033.png](https://i-blog.csdnimg.cn/blog_migrate/c2259e4d36bb6d169476113266992547.jpeg)
- ptr:指向消息内容指针,消息的组成: 类型:正长整型类型长度实际数据
- flag:标志 IPC_NOWAIT:非阻塞io
3.5 msgrcv函数
![6bdb1cc2cdb6f8c051fc212015ec68b9.png](https://i-blog.csdnimg.cn/blog_migrate/09b110a8d1c1a3a59cf0ad219d8c9073.jpeg)
- ptr:获取的数据地址,包括类型和实际数据
- nbytes:数据缓冲区长度
- type:获取哪种消息。 type=0:返回队列中第一条消息type>0:返回消息类型为type的第一个消息type<0:返回消息类型小于等于type绝对值的消息
- flag: IPC_NOWAIT:非阻塞
4. 信号量
4.1 概述
- 信号量不同于管道和消息队列,它是一个计数器,用于多进程堆共享数据对象的访问
- 信号量计数操作必须是原子的,通常在内核中实现
- 使用信号量获取共享资源的操作 测试该资源的信号量N若N为正,则进程可以使用该资源。然后N=N-1,表示使用了一个资源单位若N=0,则进程休眠,直到N>0才唤醒,然后第一步当进程不使用共享资源时,N=N+1,如果有进程在休眠等待则唤醒
- XSI信号量相对复杂一些 信号量并发单个非负值,而是一个或多个信号量值的集合创建信号量和赋值是分开的,不能原子的创建信号集合即使没有进程在使用信号量,他仍然存在
- 获得一个信号量ID:semget
4.2 数据结构
- 内核为每个信号量集合设置了一个semid_ds结构
![b9be76e50e4c6d606a9dc977bba75dc4.png](https://i-blog.csdnimg.cn/blog_migrate/6ff7993be4ee4b1890850d01d7c56c51.jpeg)
- 每个信号量的结构
![bf31bc690df0d0a4f68815dcec1b7f17.png](https://i-blog.csdnimg.cn/blog_migrate/2b0006c4c0bbad2caa953ca59dc5b67a.jpeg)
- 信号量的系统限制
![faa3ef4b37878ff7d353d9e6bcbc900e.png](https://i-blog.csdnimg.cn/blog_migrate/861689470c0f05072235c53617b55145.jpeg)
4.3 semctl函数
- 包含多种信号量操作
![7f43f22171716695832fd221f8ea819e.png](https://i-blog.csdnimg.cn/blog_migrate/da46c2e359095a31a3f54e06b8898783.jpeg)
- cmd: IPC_STAT:取semid_ds结构IPC_SET:设置数据IPC_RMID:删除信号量集合
4.4 信号量与记录锁在liunx的对比
- 记录锁比信号量耗时
- 但如果只锁一个资源,宁可用记录锁。因为他使用简单,进程终止时会自动清理锁
5. 共享存储
5.1 概述
- 共享存储允许两个或更多进程共享给定的存储区
- 数据不需要在进程间复制,是最快的IPC
- 多进程对于同一个存储区,要注意同步访问,通常使用信号量来进行同步
- 获取共享存储区域id:shmget
- 共享存储的位置:栈下面
![11bf3018fd7faf046e508d777eb403f3.png](https://i-blog.csdnimg.cn/blog_migrate/b1c910ecc414b1801d14171d57053521.jpeg)
5.2 数据结构
- 内核为每个共享存储段设置了shmid_ds结构
![2ffbafda0f0ba1a67daf8d7ba8a67d0f.png](https://i-blog.csdnimg.cn/blog_migrate/d7c8fb8daba4bb957bf1f03c87cfe225.jpeg)
- 共享存储的系统限制
![645f987bddf3cbf561719eeb39d4d327.png](https://i-blog.csdnimg.cn/blog_migrate/f1c0bae924599fa0b05a6dd3ac005178.jpeg)
5.3 shmctl函数
- 包含堆共享存储的多种操作
![04356ce78e3633b10294a01fa9b64a4d.png](https://i-blog.csdnimg.cn/blog_migrate/16750be35e40674aa97cd5169b6dccd0.jpeg)
- 参数同前面
5.4 共享存储的使用
- shmat函数:进程用于连接共享存储到其他的地址空间中
![27767d232d4e254321ba2cc40a6b7b8c.png](https://i-blog.csdnimg.cn/blog_migrate/2f07f7512dae1e3e8630e7ef7d02d1df.jpeg)
- addr参数: 为0:连接到由内核选择的可以地址上,推荐方式非0:且没有指定SHM_RND,连接到该地址非0:指定SHM_RND,将地址向下取最低边界地址倍数
- flag: SHM_RDONLY:只读其他:读写
5.5 共享存储的释放
- shmdt:脱离该段,但并不删除数据,标识符还在,直到调用shmctl删除
三. 网络进程间通信:套接字
1. 套接字描述符
- 套接字是通信端点的抽象,是用文件描述符实现的
- 创建套接字描述符:
![653e89f5c129460b53a9698d2d7dd054.png](https://i-blog.csdnimg.cn/blog_migrate/8b0a7c31ab878363e387bf2e4ff9a5e4.jpeg)
- domain:套接字域
![82e3c9a17b360c0b2c1a49e87832ab75.png](https://i-blog.csdnimg.cn/blog_migrate/949d66e6e3f4ffad029c22b967c34b62.jpeg)
- type:套接字类型
![74c413743d67308f8761614544251a1a.png](https://i-blog.csdnimg.cn/blog_migrate/ee956300fb2fb4c3d70cf926ebb566d8.jpeg)
- protocol:协议,通常为0。表示根据套接字类型默认选择协议
- 关闭套接字:close
- shutdown:禁止套接字上的输入/输出,可只关闭一个方向
2. 寻址
2.1 字节序
- 大端字节序:最大字节地址对应于数字最低有效字节
- 小段字节需:最小字节地址对应于数字最低有效字节
- 各个平台的字节序如下:
![b08b555805afa583fa37d4b2ff2ad443.png](https://i-blog.csdnimg.cn/blog_migrate/f8534799ca7810356d43fa66d3173d2a.jpeg)
- 网络传输中:tcp/ip使用大端字节序
2.2 地址格式
- 地址标识了套接字端点,通用地址格式为:
struct sockaddr{ sa_famliy_t sa_famliy; char sa_data[]; }
- 套接字实现可以自由添加aa_data字段以及长度
//linux实现 struct sockaddr{ sa_famliy_t sa_famliy; char sa_data[14]; } //freeBSD实现 struct sockaddr{ unsigned char sa_len; sa_famliy_t sa_famliy; char sa_data[14]; }
- ipv4套接字通用地址:,实现者可以自由添加额外字段
![d9fd01e0007bcd6a2ef350c8becc9e87.png](https://i-blog.csdnimg.cn/blog_migrate/417bd754391d00b4d8a971717d077b67.jpeg)
- ipv6套接字通用地址:实现者可以自由添加额外字段
![f18f11d38580b9d63afdad14ae68abe2.png](https://i-blog.csdnimg.cn/blog_migrate/b35f1b9cd0dc436d001b981a8b132a21.jpeg)
- sockaddr_int和sockaddr_int6都会被转化为sockaddr结构传入套接字例程中
- 二进制地址与文本格式地址转化:inet_ntop,inet_pton
2.3 地址查询
- 查找给定计算机主机信息:gethostent
![4db3c85ae279ab4734df1d6d6d871d36.png](https://i-blog.csdnimg.cn/blog_migrate/2a8a034ef613a3e79033013f91fb0a7c.jpeg)
- 返回的主机信息数据结构:
![113d3e18404fae52e72cc8035f2b63c9.png](https://i-blog.csdnimg.cn/blog_migrate/3fe12c4de376d8e531b97dfb52eb1cb9.jpeg)
- 获取网络名字和网络号
![dfde99c44a8f9fa8da55a0510974dc21.png](https://i-blog.csdnimg.cn/blog_migrate/17e0207226ec6b7da578b7609cdf67c4.jpeg)
- 获取协议名字和协议号
![00b1bb818971b40f06a6ebc6c043144d.png](https://i-blog.csdnimg.cn/blog_migrate/4a0f6f58274306ca1ada7e00d2d79435.jpeg)
- 服务名字和端口号映射关系查询
![9d1241cf10055bc010802dfd19828f81.png](https://i-blog.csdnimg.cn/blog_migrate/155a485ff0a196169d6e220ec3178abd.jpeg)
- 将主机名和服务名映射到一个地址
![5820f96cbe6a9027f52c0464652090e6.png](https://i-blog.csdnimg.cn/blog_migrate/91fbb069a0314ff7c8d443e014385a0c.jpeg)
- 地址信息包含的成员
![d3e3ba08e2a70f431f86543ee087210e.png](https://i-blog.csdnimg.cn/blog_migrate/e1e9e75808d1f5e8d43388fb4cf94130.jpeg)
2.4 将套接字与地址绑定
- 客户端套接字关联地址没有太大意义,可以让系统选一个默认地址
- 服务端需要给一个客户端请求的套接字绑定一个众所周知的地址
- 客户端绑定服务端地址的方法:
![d89de48d7cd8d672b3a30c58c7a0698c.png](https://i-blog.csdnimg.cn/blog_migrate/d4600ed698af16417f74aba127a323c3.jpeg)
3. 建立连接
3.1 connect
![1b5468feb445296bc303e304017180c3.png](https://i-blog.csdnimg.cn/blog_migrate/a46567bdcd90a4cf2585860d4e205cd2.jpeg)
- connect为客户端调用,用于连接请求
- addr为服务器地址
- 如果sockfd没有绑定地址,connect会给调用者绑定一个默认地址
- 连接可能失败,应用程序必须能处理connect返回的错误
3.2 listen
![6d2e5215fec334934ed64a06475e259e.png](https://i-blog.csdnimg.cn/blog_migrate/027ceb137900d823bf4a880a5015473c.jpeg)
- listen为服务端调用
- 服务器用listen宣告可以接受连接请求
- backlog:连接请求数量
3.3 accept
![7155db27bfdf59a1627e35a777dddece.png](https://i-blog.csdnimg.cn/blog_migrate/daceaec1daa7cf1df96f8b9bdaa109ab.jpeg)
- accept获得连接请求,并建立连接
- 返回的文件描述符是套接字描述符,描述符连接到调用connect到客户端
- 新的套接字描述符和原始套接字sockfd具有相同的套接字类型和地址族
- 传给accept的原始套接字没有关联到这个连接,而是继续保存可以状态并接受其他连接请求
- 如果没有连接请求等待处理,accept会阻塞直到有请求到来
4. 数据传输
4.1 send
![cd459e2cec8eaf0bcf63a9048f78a5f3.png](https://i-blog.csdnimg.cn/blog_migrate/d7197f2ae9c9c3779dc8f562db900c75.jpeg)
- 发送数据,类似与write函数
- send比write多了第四个参数flags,用于改变处理数据到传输方式 MSG_DONTROUTE:勿将数据路由出本地网络MSG_DONTWAIT:允许非阻塞操作MSG_EOR:记录结束MSG_OOB:外带数据
- sendto函数:类似send。但是sendto允许在勿连接到套接字上指定一个目标地址
4.2 recv
![faace6e90cf8b14b28a34b7c84af40b5.png](https://i-blog.csdnimg.cn/blog_migrate/2f1093e560e3bcb85ad4c83092fa328f.jpeg)
- 获取数据,类似于read函数
- recv比read多了第四个产生flags,用于控制如何接收数据 MSG_OOB:接受外带数据MSG_PEEK:返回报文内容而不真正取走报文MSG_TRUNC:即使报文被截短,也返回实际的长度MSG_WAITALL:等待直到所以数据可用
5. 套接字选项
5.1 套接字选项包括
- 通用选项,工作在所有套接字类型上
- 在套接字层次管理的选项,但是依赖底层协议的支持
- 特定与某种协议的选项,为某个协议独有
5.2 设置套接字的函数
![54db26a9fc8c5b238862f2ae3ddfebfd.png](https://i-blog.csdnimg.cn/blog_migrate/58e44dc0200d7d2ab152a4e2d11e81a9.jpeg)
6. 带外数据
- 带外数据是一些通信协议支持的可选特征,允许高优先级的数据比普通数据优先传输
- TCP将外带数据成为“紧急数据”
四. 高级进程间通信
1. 概述
- Streams管道和unix套接字,这两种高级IPC,可以在进程间传递文件描述符
- 服务进程可以使他们的打开文件描述符与特定的名字相关联
- 客户进程可以使用这些名字与服务器通信
- 操作系统会为每个客户进程提供一个独自的IPC通道
2. STREAMS管道
- Streams pipe是一个全双工(双向)通道
- 内部结构如下
![598b50231bc836077a1a7ac7b023974a.png](https://i-blog.csdnimg.cn/blog_migrate/07fe31c0069ec6e65e75dae34de13178.jpeg)
3. UNIX域套接字
- 用于在同一台机器上运行的进程之间通讯