网络通信
网络通信,就是进程间的一种通信方式,网络通信都采用客户端-服务端模型,当然与之相对的就是进程内部的通信(就是后面要讲的多线程编程里面的东西,包括同步,信号量)。
unix网络通信关于网络通信
I/O多路复用,select(基于轮询,支持少数文件描述符)、poll(基于轮询,支撑大量文件描述符)、epoll(系统计算文件描述数量,基于回调)
select 在初始化时,指定描述符容量大小,FD_SETSIZE的值上限在不同平台上运行是不一致的windows上是64(WINSOCK.H文件中定义)和linux(ulimit -a 查找open files 项)上受限于每个进程打开的最大文件个数(默认1024)
winsock.h文件中定义
linux fd限制
![linux fd限制](https://i-blog.csdnimg.cn/blog_migrate/85ccf86beeb5708fe66e2988d7174a8f.png)
这里的select 函数 后来有pselect函数支持纳秒级别超时等待
poll 在初始化时,传入的第一个参数是一个链表,表示支持的文件描述,意味着受限于内存大小
select和poll都是在每次调用监听文件描述符时,是通过轮询来遍历,随着连接数量的增加,性能会下降
epoll,基于select和poll的缺点在2.6内核中引入,epoll中epoll_create(int size)中的size不是最大值,是一个估算值,系统会动态计算出真正的值,甚至在之后的更新中,只要是个整数就行
epoll_ctl(),控制文件描述的添加、删除,文件描述符感兴趣的事件注册和更改,就是一个回调机制。在epoll_ctl中传入的事件event.events是一个枚举类型,通过|符号来添加监听事件,其中如果添加了EPOLLET,设置关联的fd为ET的工作方式(水平触发事件立即返回结果)默认工作方式是LT(边缘触发事件,等待处理完毕后返回结果)。
I/O复用,理解I/O复用,就要理解,I/O没有复用的情况,多个连接同时请求一个服务,服务就排队一个一个处理,为了解决这个问题,就提出了I/O复用,通过上面讲解的select,poll,epoll 来统一接收请求,分发任务(select、poll)或主动处理,任务结束后通知(epoll回调)来解决。
网络通信模型
单进程模式
父进程接收到请求,fork子进程来处理,处理完毕了关闭子进程,缺点是,每次都要fork新的子进程出来,开销大
preforking改进
提前fork一个子进程池,父进程接收到请求,直接使用闲置的子进程
单线程模式
进程接收到请求,直接创建一个线程,就是每个请求,对应一个线程
prethreading改进
服务器启动时,预先创建一个线程池,服务器接收到请求,使用闲置的线程处理,不用临时创建新线程
Reactor,反应堆(I/O多路复用+线程池)
一个线程(进程)或线程池(进程池)每当Reactor(s)接受到一个请求时,就分配任务给其他线程或线程池处理,其中Netty采用多Reactor(接受)多线程(处理)模式
Proactor(异步网络模型)
每个请求来时,Proactor构造器负责创建Proactor时,同时也会创建对应的Handler回调,异步处理器(内核中)把Proactor和Handler同时注册到内核当中,异步处理器完成I/O后就会通知Proactor,proactor就会回调相应的Handler
说来比较拗口,简单点讲就是内核异步处理I/O操作,通知Proactor,proacor回调handler,linux下的异步网络模型就通过Reactor+epoll模拟出来的。
总结,网络编程模型讲解到此结束,接下里会一一通过Java代码展示讲解单线程模型,prethreading,reactor,proactor。