UNIX 网络编程 chapter 6

I/O模型

一个输入操作一般包括两个阶段:等待数据、从内核和进程复制数据

1. 阻塞式I/O : 直到读写完成或发生错误才返回,如被信号打断
2. 非阻塞I/O : 无读写数据时直接返回错误,有数据时直接复制数据
3. I/O复用 : 阻塞在select或poll上,而不是阻塞在真正的I/O系统调用上
4. 信号驱动式I/O(SIGIO) : 让内核在描述符就绪时发送SIGIO信号通知我们
5. 异步I/O(Posix的aio_系列函数): 告知内核启动某个操作,并让内核在整个操作完成后通知我们。
与信号I/O的区别是:信号I/O是内核通知何时可以启动一个操作,异步I/O通知I/O操作何时完成。

select、poll和epoll

select

int select(int maxfdp1, fd_set *readfds, fd_set *writefds, 
            fd_set *exceptfds, struct timeval *timeout); 

select 缺陷

1. 最大并发数限制

select对打开的文件描述符是有限制的,由FD_SETSIZE(1024)设置, 如果要改变FD_SIZE的大小需要重新编译内核。

2.效率低

调用select时,需要将readfds, writefds, exceptfds从用户层拷贝到内核
select返回需要线性遍历套接字集合(readfds, writefds, exceptfds)
select返回后,

poll

epoll

转载 1

1. Level_triggered(水平触发)

当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你.只要某个socket处于readable/writable状态,无论什么时候进行epoll_wait都会返回该socket
若系统中有大量不需要读写的就绪文件描述符,它们每次都会返回,这样会降低处理程序检索自己关心的就绪文件描述符的效率!

2.Edge_triggered(边缘触发)

当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你! 只有某个socket从unreadable变为readable或从unwritable变为writable时,epoll_wait才会返回该socket。

转载 2

问题:accept 、ET、阻塞

1. 阻塞模式 accept 存在的问题

考虑这种情况:TCP连接被客户端夭折,即在服务器调用accept之前,客户端主动发送RST终止连接,导致刚刚建立的连接从就绪队列中移出,如果套接口被设置成阻塞模式,服务器就会一直阻塞在accept调用上,直到其他某个客户建立一个新的连接为止。但是在此期间,服务器单纯地阻塞在accept调用上,就绪队列中的其他描述符都得不到处理。

解决办法是把监听套接口设置为非阻塞,当客户在服务器调用accept之前中止某个连接时,accept调用可以立即返回-1,这时源自Berkeley的实现会在内核中处理该事件,并不会将该事件通知给epool,而其他实现把errno设置为ECONNABORTED或者EPROTO错误,我们应该忽略这两个错误。

2. ET模式下 accept存在的问题

考虑这种情况:多个连接同时到达,服务器的TCP就绪队列瞬间积累多个就绪连接,由于是边缘触发模式,epoll只会通知一次,accept只处理一个连接,导致TCP就绪队列中剩下的连接都得不到处理。

解决办法是用while循环抱住accept调用,处理完TCP就绪队列中的所有连接后再退出循环。如何知道是否处理完就绪队列中的所有连接呢?accept返回-1并且errno设置为EAGAIN就表示所有连接都处理完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值