NIO网络编程框架netty

https://www.iteye.com/magazines/103  dubbo开发者博客

用户空间与内核空间
现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。

linux下一切皆文件,文件描述符用来表示设备文件和普通文件,文件描述符是文件系统中连接用户空间和内核空间的枢纽。所有对文件的操作都通过文件描述符来实现。

当某个进程打开或者创建一个文件时,调用内核创建相应的结构并返回一个整形变量的文件描述符给该进程。之后进程使用这个整形变量的文件描述符对文件进行读写操作。用户空间读写文件时将文件描述符作为参数传递给read或write读写函数,读写函数的系统调用到达内核时,内核解析文件描述符找出对应的文件并运行相应的内核函数把结果返回给用户进程。

系统调用指内核提供给应用进程的接口。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序。 [1] 

网络IO和磁盘IO:

数据源不一样,一个是网卡,一个是磁盘。正常情况两种IO的数据都需要经过内核(磁盘IO有直接IO技术可以让进程直接从磁盘读数据而不经过内核)。

读就绪指:内核的数据准备好

真正读指:把内核数据复制到用户空间(进程空间)

进程切换
为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。
进程的阻塞

正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的。

linux对fd或socketfd的读写:调用内核提供的系统命令recvfrom

recvfrom:从(已连接)套接口上接收数据,并捕获数据发送源的地址。

与recv()函数的比较:UDP使用recvfrom()函数接收数据,他类似于标准的read(),但是在recvfrom()函数中要指明目的地址。从套接字上接收一个消息。对于recvfrom ,可同时应用于面向连接的和无连接的套接字。recv一般只用在面向连接的套接字,几乎等同于recvfrom,只要将recvfrom的第五个参数设置NULL。不管是recv还是recvfrom,都有两种模式,阻塞和非阻塞,可以通过ioctl函数来设置。阻塞模式是一直等待直到有数据到达,非阻塞模式是立即返回,需要通过消息,异步事件等来查询完成状态。

unix网络编程中的五种IO模型:

阻塞IO:

在进程空间中调用recvfrom,此系统调用直到数据包到达且被复制到应用进程的缓冲区中或发生错误才返回。在此期间进程在从调用recvfrom到它返回的整段时间都是被阻塞的。

非阻塞IO:

在进程空间中调用recvfrom,如果缓冲区没有数据的话,直接返回一个EWOULDBLOCK错误。一般会轮询此状态,看内核是否有数据到来。

 

复用(阻塞)IO技术实现的非阻塞IO(单个IO还是阻塞的)(即一次系统调用使用轮询或事件驱动方式监听多个阻塞IO的就绪状态(注意是监听就绪不是监听是否就绪,也就是说没有就绪的时候会一直阻塞)):

将多个fd传递给系统调用select/poll,select/poll顺序扫描fd是否就绪(支持一个进程打开的socketfd数量受限),扫描到有就绪的fd或经历了多少时间则返回。还有一个epoll系统调用(socketfd数量不受限),epoll用基于事件驱动方式代替顺序扫描,有fd就绪事件则返回调用callback函数不用轮询所有集合,效率更高。(如nginx使用epoll方式,而apache使用的是传统的select方式)

信号驱动IO:

先开启套接字信号驱动IO功能,通过系统调用执行sigaction执行信号处理函数,数据准备就绪时为进程生成一个信号通知应用程序调用recvfrom接收数据。(与复用IO中的epoll调用区别在于系统调用信号处理函数会立即返回,进程继承工作不阻塞。而epoll调用会导致进程阻塞直至读就绪事件发生。)

异步IO:

告知内核启动某个操作并让内核在整个操作完成后(包括将数据从内核复制到用户的缓冲区)通知我们。与信号驱动IO的区别是信号驱动IO通知我们何时可以开始一个IO操作,异步IO模型由内核通知我们IO操作何时已经完成。

 

在IO编程中,如果需要同时处理多个客户端请求时,可以使用多线程及线程池或IO多路复用技术来处理。

多线程:为每个请求建立一个线程。

线程池:JDK的线程池维护一个消息队列和N个活跃的线程,由于线程池和消息队列都是有界的,因此客户端连接数无论多大,都不会导致线程个数过于膨胀或者内存溢出,相比传统的一连接一线程模型是一种改良。线程池虽然可以灵活调配线程资源,但由于底层仍是同步阻塞IO,所以叫伪异步。

多路复用技术:即把多个IO的阻塞封装成同一个select调用的阻塞上,从而使单线程可以处理多个客户端请求。节省了系统开销。 

异步I/O由POSIX规范定义:进程发起系统调用后让内核启动某个操作,并让内核在整个操作完成后通知我们,很显然,按这种规范来说只有最后一种I/O模型是异步I/O。

NIO

NIO类库中的Buffer对象,体现了新库与原IO的重要区别。在面向流的IO中,可以将数据直接读到或写到Stream对象中。NIO中,所有数据都是用缓冲区处理(读写)的。

JDK1.4到1.5的update10前的版本NIO的selector用select/poll模型实现,之后sun优化了selector的实现用epoll来实现。

JDK1.4到1.6的NIO是同步非阻塞IO,1.7提供的NIO2.0才是真正的异步非阻塞IO即AIO,在异步IO操作的时候可以传递信号,当操作完成的时候可以回调相关的方法(类似于unix编程的第五种IO模型)。

同步异步指:单个线程在读取socket的数据这一操作没有明确结果(错误也好,可读也罢)前可不可以做别的事情。

比如同步IO,要求IO操作(读/写)必须返回一个结果(什么结果都可以)才能开始别的事情(重新IO操作或做与IO无关的事情)

异步IO,则不关心IO有无返回结果直接就开始做别的事情。

https://blog.csdn.net/historyasamirror/article/details/5778378 

 

netty的心跳检测:

netty的心跳检测机制是利用链路空闲检测机制实现,超过指定时间没有收到心跳检测消息则触发IdleStateEvent事件,用户订阅IdleStateEvent事件自定义逻辑处理,如关闭链接,重新发起连接,告警等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值