Unix网络编程:I/O复用

I/O复用:进程预先告知内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,它就通知进程。

I/O复用典型使用在下列网络应用场合

  • 当客户处理多个描述符,必须使用I/O复用
  • 一个客户处理多个套接字
  • TCP服务器既要处理监听套接字,又要处理已连接套接字。
  • 一个服务器既要处理TCP又要处理UDP
  • 一个服务器要处理多个服务或多个协议。

I/O模型

Unix下可用的五种I/O模型
- 阻塞式I/O
- 非阻塞I/O
- I/O复用(select.poll)
- 信号驱动I/O
- 异步I/O

阻塞式I/O

这里写图片描述
从调用recvfrom函数开始到他返回整段时间内是被阻塞的,recvfrom成功返回后,应用进程开始处理数据报。

可能的阻塞套接字调用分为4类:

  • 输入操作:read、readv、recv、recvfrom、recvmsg
  • 输出操作:write writev send sendto sendmsg
  • 接收外来连接:accept函数
  • 发起外出连接:connect函数

非阻塞式I/O

进程把一个套接字设置成非阻塞是在通知内核:当所请求的I/O操作非得把本进程投入睡眠才能完成时。不要把本进程投入睡眠,而是立即返回一个错误

这里写图片描述

当一个应用进程对这样一个非阻塞的描述符循环调用的时候,称为轮询。

网络编程中socket可读的情况:

  • soekt内核接收缓冲区中的字节数大于或等于其低水平标记,可以无阻塞地读socket,并且返回的字节数大于0.
  • socket双方关闭通信连接,返回的字节数等于0.
  • 监听socket上有新的连接
  • socket上有未处理的错误
    网络编程中socket可写的情况
  • soekt内核发送缓冲区中的字节数大于或等于其低水平标记,可以无阻塞地写socket,并且返回的字节数大于0.
  • socket的写操作关闭
  • socket使用非阻塞connect连接成功或者失败
  • socket上有未处理的错误

I/O复用模型

可以调用select或poll,阻塞在这两个系统调用中的某一个上,而不是真正阻塞在I/O系统调用上。如果不采用并发机制,当有多个描述符就绪的时候,程序只能按顺序依次处理。
这里写图片描述

select函数

#include <sys/select.h>

#include <sys/time.h>

int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);

函数功能:允许进程指示内核等待所关注的描述符上事件发生,并且只有在一个或多个事件发生时或经历一段时间后才才唤醒进程。

参数
maxfdp1:被监听的文件描述符总数
timeout:告知内核等待所指定的描述符中任何一个就绪可以花费多长时间,若为0,检查描述符后立即返回,称为轮询。
readset:内核测试读描述符。
writeset:内核测试写描述符。
exceptet:内核异常描述符。对于其中某一个描述符不感兴趣,可设置为空指针。

fd_set的结构体包含一个整型数组,该数组的每一元素的每一位标记一个文件描述符,fd_set能容纳的描述符总量由FD_SETSIZE指定,这也限制了select能同时处理文件描述符的总量。

可以通过一系列宏来访问fd_set结构体中的位

#include<sys/select.h>
FD_ZERO(fd_set *fdset);//清空描述符集
FD_SET(int fd,fd_set *fdset); //设置fd_set的fd位
FD_CLR(int fd,fd_set *fdset); //清除fd_set的fd位
int FD_ISSET(int fd,fd_set *fdset); //测试fd_set的fd位是否被设置

poll函数

#include <poll.h>

int poll (struct pollfd *fdarray, unsigned long nfds, int timeout);

功能:与select类似
第一个参数指向结构数组的首地址,数组中每个元素都是一个pollfd结构。

struct pollfd {
  int     fd;       /* descriptor to check */
  short   events;   /* events of interest on fd */
  short   revents;  /* events that occurred on fd */
};

信号驱动I/O模型

利用信号,让内核在描述符就绪时发送SIGIO信号通知进程开始执行操作,这种模型称为信号驱动式I/O
这里写图片描述

针对一个套接字使用信号驱动是I/O要求进程执行以下3个命令

  • 建立SIGIO信号的信号处理函数
  • 设置该套接字的属主,使用fcntk的F_SETOWN设置
  • 开启该套接字的信号驱动I/O

在UDP上使用信号驱动,SIGIO信号在发生以下事件时产生

  • 数据报到达套接字
  • 套接字上发生异步错误

在TCP上使用信号驱动,SIGIO信号在发生以下事件时产生

  • 监听套接字上某个连接请求已经完成
  • 某个断连接请求已经发起
  • 某个断连接请求已经完成
  • 某个连接已经半关闭
  • 数据到达套接字
  • 数据已经从套接字发送走
  • 发声某个异步错误

异步I/O模型:不导致请求进程阻塞

这些函数的工作机制是:告知内核启动某个动作,并且让内核在整个操作完成时通知进程。
这里写图片描述

Tips:阻塞式、非阻塞式、I/O复用、信号驱动式都是同步I/O模型,因为真正的I/O操作都是将进程阻塞。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值