默认socket调用read, sendto 等函数都是阻塞的
服务端使用select,同时客户端断开tcp连接,read不会阻塞,会返回0;
从上面可以看出select的不足:
1. 检测一个就绪套接字,你需要给所有的套接字FD_ISSET(),若套接字少还行,一旦多了,那就是直接拖速度啊
2. 能够监听的套接字数目有限制,一千多个的套接字对于大一点的网络服务器就是‘呵呵‘了其实还有缺点并不能直接看出来,不过还是要列出来
3. 每次调用select,系统要把套接字集合复制到内核空间
---------------------
作者:Mr.shi
来源:CSDN
原文:https://blog.csdn.net/u014627661/article/details/50915987
版权声明:本文为博主原创文章,转载请附上博文链接!
使用ET和LT的区别
LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。
ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。
下面举一个列子来说明LT和ET的区别(都是非阻塞模式,阻塞就不说了,效率太低):
采用LT模式下,如果accept调用有返回就可以马上建立当前这个连接了,再epoll_wait等待下次通知,和select一样。
但是对于ET而言,如果accpet调用有返回,除了建立当前这个连接外,不能马上就epoll_wait还需要继续循环accpet,直到返回-1,且errno==EAGAIN,
从本质上讲:与LT相比,ET模型是通过减少系统调用来达到提高并行效率的。
ET模式下的读写
经过前面几节分析,我们可以知道,当epoll工作在ET模式下时,对于读操作,如果read一次没有读尽buffer中的数据,那么下次将得不到读就绪的通知,造成buffer中已有的数据无机会读出,除非有新的数据再次到达。对于写操作,主要是因为ET模式下fd通常为非阻塞造成的一个问题——如何保证将用户要求写的数据写完。
要解决上述两个ET模式下的读写问题,我们必须实现:
a. 对于读,只要buffer中还有数据就一直读;
b. 对于写,只要buffer还有空间且用户请求写的数据还未写完,就一直写。
同时处理多个流
1. 要么多进程(fork),要么多线程(pthread_create),很不幸这两种方法效率都不高。
2. 于是再来考虑非阻塞忙轮询的I/O方式,我们发现我们可以同时处理多个流了(把一个流从阻塞模式切换到非阻塞模式再此不予讨论):
while true {
for i in stream[]; {
if i has data
read until unavailable
}}
3.复杂度 o(n)
while true {
select(streams[])
for i in streams[] {
if i has data
read until unavailable
}}
4. 复杂度o(1)
while true {
active_stream[] = epoll_wait(epollfd)
for i in active_stream[] {
read or write till
}
}