当前位置 博文首页 > 随便记记笔记:IO多路复用模型及网络服务器模型
同步:客户端请求服务器的内容,一直等待内容返回,期间客户端不做别的。
异步:调用后不会立刻得到结果,调用完成后通过状态,通知或者回调来通知调用者。例如ajax异步请求。
阻塞:调用返回前,线程/进程被挂起,不使用cpu资源。对同步调用,线程还是激活,只是逻辑上函数没有返回。例如,我们在socket中调用recv函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。
(忘了从哪copy的)
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。
recvfrom,recv,一直等内核准备数据,如果缓冲区没有数据,调用线程在数据到来前一直睡眠。默认的socket是阻塞的。
send,sendto,发送缓冲区没有空间会一直睡眠直到有空间。
accept,等待连接请求,没有睡眠
connect,发主动连接,收到服务器应答前不会返回
反复进行系统调用,没有数据立刻返回,有数据阻塞拷贝数据然后返回。
socket设置成非阻塞,当请求的IO无法完成时不睡眠而是返回错误。
select,阻塞等待多个套接字中的一个变成可读,内核返回可读条件;再调用recvfrom读数据。
可以同时阻塞多个IO操作,对多个读,写IO函数进行检测,有可读或可写时调用真正的IO操作。
优势在于单个进程可以同时处理多个网络连接的IO
建立SIGIO信号处理程序,内核准备好数据通知应用,进入信号处理程序
aio_read,系统调用直接返回,内核准备好后提交在aio_read指定的信号中
表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。
边缘触发IO事件只发生一次,不知道读写多少数据,只能尽可能多的读写,所以会循环读写,应该使用非阻塞的IO。所以边缘触发一般搭配非阻塞IO。
一般来说边缘触发效率比水平触发高,可以减少epoll_wait调用次数。select/poll只有水平触发模式,epoll默认是水平触发,可以设置成边缘触发。
bind,死循环,recv,process,send
服务器主进程构建多个子进程,请求来的时候随便选一个子进程处理客户端连接。
如何确定子进程数量,动态增加
bind后,fork,传入socket,子进程死循环,recv,send
对信号进行处理,接收到信号所有子进程退出
bind,fork(accept,recv,process,send)
主进程统一处理客户端连接,连接到来以后才fork,子进程处理请求。
bind,listen,死循环,accept,fork(recv,process,send)
线程更轻量。
多线程,线程内(accept,recv,process,send),需要设置互斥锁,防止一起调用accept
线程先进入互斥区,再accept,离开互斥区。
并发服务器的缺陷,建立多个并行处理单元,客户端增加时,负载转移到并行单元的现场切换,嵌入式系统尤为明显。IO复用循环服务器为了降低系统切换的开销,集中系统能力在核心业务。在系统开始时,建立多个不同工作类型的处理单元,处理连接,业务。客户端连接来,放到一个状态池中,对所有客户端连接状态在一个处理单元中进行轮询。
两个线程:
小林coding - 这次答应我,一举拿下 I/O 多路复用!
cs