Socket通信模型
socket模型:
1、阻塞模型
一个单进程accept阻塞,接收到客户端请求后,read消息,处理write返回,然后循环继续accept。
这种模型最最简单,不实际,没什么实际用途,对于新手教学还行。
2、多进程(线程)模型
主进程循环accept阻塞,接收到客户端请求后,fork子进程处理,子进程read阻塞,接收客户端消息并响应。
这种模型是我使用到最多的,简单实用,但是当客户端请求超多时,fork子进程多,系统资源消耗大,效果不理想;当然这种与多线程同理。
3、进程池(线程池)
主进程产生固定多的子进程,并定时监控子进程状态,初始子进程都为空闲状态。子进程在accept到客户端请求,通知主进程我很忙,然后处理请求,请求处理完成后,通知主进程我很闲。主进程主要监控子进程是否僵死或退出,维护进程池固定数量的进程来处理消息。
这种模型,可能每个人的实现方式不一样,这是我接触到的。优点是:不会产生超多的进程(线程)以至于过多消耗资源,在请求数量不多的情况下,效果还好;缺点是:因为是‘池’都有限制,当远远超过进程池限制的进程数,效果并不理想。
4、连接池
这种实现方式我第一次听说,在网上查了好久也没有头绪。在我的理解里,socket都是客户端向服务端发请求建立socket连接,因为客户端不同这种连接怎么重用?请高手指点一二,主要讲清原理即可。
5、select事件模型
这种实现方式是主进程将socket监听连接和client请求连接一起FD_SET到一个内核队列中,内核一直检查这个队列的哪个socket描述符有读或写或异常的响应则通知用户进程。用户进程检测到socket监听连接有响应,则accept与客户端建立连接,并把新的client请求连接FD_SET到内核队列中;如果检测到client请求连接有响应,则fork子进程,read客户端消息,处理并响应消息。
这种模型,select会捕获到你设置的某个socket描述符有可读可写或异常的事件,但是程序员需要自己检查自己设置的所有描述符,以确认是哪个描述符有事件发生。优点:占用资源少,不会消耗太多的cpu;缺点是select的效率和FD_SET到内核队列中的描述符的个数有关,当需要检测的描述符过多时,就要花费过多的时间去检测所有的描述符是否有时间发生,而且可以FD_SET的描述符内核也有限制,当客户端请求成千上万时,select便无能为力。
6、epoll事件模型
这种模型我刚开始接触,目前还没有完全使用或练习过。但是实现方式却是目前最好的一种模型,对设置监测的socket描述符同时设置回调函数,当内核监测到socket描述符有事件发生,则会主动触发回调函数。
这种模型,优点:可以接收任意多的连接,高效率,低消耗,稳定易使用;缺点:因为各系统提供的接口有很大的差异,可移植性差。