- 浏览: 1597912 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
jsrgzhangzhiyong:
关于null值的转换还是感觉不太友好,就像 mapstruct ...
我也造了个轮子:BeanMapping(属性拷贝) -
he037:
a417930422 写道引用使用EPHEMERAL会引出一个 ...
基于zookeeper的分布式lock实现 -
seancheer:
qianshangding 写道首先节点启动后,尝试读取本地的 ...
zookeeper学习记录三(session,watcher,persit机制) -
雪夜归人:
您好,我想咨询一下,开源的canal都能支持mysql的哪些版 ...
Canal BinlogChange(mysql5.6) -
zhoudengyun:
copy 一份做记录,后续学习,请知悉
阿里巴巴开源项目: 基于mysql数据库binlog的增量订阅&消费
背景
前一段时间一直在关注一些nio的相关技术,也和公司的架构师交流了一下,学到了一些相关原理,比如nio的优势和劣势。以及一些排查nio bug问题的方式,受益量多。为自己做一下技术储备,以后可以多玩玩nio的相关技术
知识点
unix网络编程第6章: 几种unix下的I/O模型。
- 阻塞I/O模型 (java io)
- 非阻塞I/O模型
- I/O复用 (java 5的nio)
- 信号驱动I/O
- 异步I/O (java7的aio)
#include<sys/select.h> int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds,fd_set *restrict exceptfds, struct timeval* restrict tvptr);
#include <sys/select.h> int pselect(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds,fd_set *restrict exceptfds, const struct timespec *restrict tsptr,const sigset_t *restrict sigmask);
#include <poll.h> int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
struct pollfd { int fd; /* file descriptor to check, or <0 to ignore */ short events; /* events of interest on fd */ short revents; /* events that occurred on fd */ };
2. nfds代表pollfd的长度
返回值:0超时,-1出错, 正数代表准备好的描述符
同样变种的有ppoll函数,具体可以见man ppoll,两者的区别和select/pselect区别一样,多了时间精度的支持+信号屏蔽字
和select系列的区别点,poll不再受限于select中位数组的长度限制,我们可以将关心的描述符添加到poolfd中。
再看epoll函数,是对select/poll的一个增强版:
1. 因为它不会复用文件描述符集合来传递结果而迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合
2. 另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。
epoll的除了提供select/poll 那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。
电平触发(Level Triggered): select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息
边沿触发(Edge Triggered: 只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发。
几个接口:
int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 1. 第一个参数是epoll_create()的返回值. 2. 第二个参数表示动作,用三个宏来表示: EPOLL_CTL_ADD:注册新的fd到epfd中; EPOLL_CTL_MOD:修改已经注册的fd的监听事件; EPOLL_CTL_DEL:从epfd中删除一个fd; 3. 第三个参数是需要监听的fd 4. 第四个参数是告诉内核需要监听什么事 events可以是以下几个宏的集合: EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭); EPOLLOUT:表示对应的文件描述符可以写; EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来); EPOLLERR:表示对应的文件描述符发生错误; EPOLLHUP:表示对应的文件描述符被挂断; EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 1. 等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size, 2. 参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有 说法说是永久阻塞)。 该函数返回需要处理的事件数目,如返回0表示已超时。
再看一下jdk中对nio的使用:
public static SelectorProvider create() { PrivilegedAction pa = new GetPropertyAction("os.name"); String osname = (String) AccessController.doPrivileged(pa); if ("SunOS".equals(osname)) { return new sun.nio.ch.DevPollSelectorProvider(); } // use EPollSelectorProvider for Linux kernels >= 2.6 if ("Linux".equals(osname)) { pa = new GetPropertyAction("os.version"); String osversion = (String) AccessController.doPrivileged(pa); String[] vers = osversion.split("\\.", 0); if (vers.length >= 2) { try { int major = Integer.parseInt(vers[0]); int minor = Integer.parseInt(vers[1]); if (major > 2 || (major == 2 && minor >= 6)) { return new sun.nio.ch.EPollSelectorProvider(); } } catch (NumberFormatException x) { // format not recognized } } } return new sun.nio.ch.PollSelectorProvider(); }
比较明显: 如果当前是sunos系统,直接使用DevPoll,在linux 2.6内核下,使用Epoll模型,否则使用Poll。
DevPoll估计是sunos自己整的一套poll模型,公司一般使用redhat系列,内核2.6.18,64位主机。所以就介绍下Epoll的实现
java实现类: EPollSelectorImpl
// wake up使用的两描述符 protected int fd0; protected int fd1; // The poll object , native的实现 EPollArrayWrapper pollWrapper; // Maps from file descriptors to keys , 文件描述符和SelectKey的关系 private HashMap fdToKey;
看下select()的实现:
PollSelectorImpl类: ============== protected int doSelect(long timeout) //具体执行epoll调用 throws IOException { if (closed) throw new ClosedSelectorException(); processDeregisterQueue(); try { begin(); pollWrapper.poll(timeout); } finally { end(); } processDeregisterQueue(); int numKeysUpdated = updateSelectedKeys(); if (pollWrapper.interrupted()) { // Clear the wakeup pipe pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0); synchronized (interruptLock) { pollWrapper.clearInterrupted(); IOUtil.drain(fd0); interruptTriggered = false; } } return numKeysUpdated; } 继续看下EPollArrayWrappe : ========================== int poll(long timeout) throws IOException { updateRegistrations(); updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd); for (int i=0; i<updated; i++) { // 这里判断下当前响应的描述符是否为fd0,后面再细说 if (getDescriptor(i) == incomingInterruptFD) { interruptedIndex = i; interrupted = true; break; } } return updated; } 继续看下EPollArrayWrapper 的native实现: epollWait(): ====================JNIEXPORT jint JNICALL Java_sun_nio_ch_EPollArrayWrapper_epollWait(JNIEnv *env, jobject this, jlong address, jint numfds, jlong timeout, jint epfd) { struct epoll_event *events = jlong_to_ptr(address); int res; if (timeout <= 0) { /* Indefinite or no wait */ RESTARTABLE((*epoll_wait_func)(epfd, events, numfds, timeout), res); } else { /* Bounded wait; bounded restarts */ res = iepoll(epfd, events, numfds, timeout); } if (res < 0) { JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed"); } return res; } static int iepoll(int epfd, struct epoll_event *events, int numfds, jlong timeout) { jlong start, now; int remaining = timeout; struct timeval t; int diff; gettimeofday(&t, NULL); start = t.tv_sec * 1000 + t.tv_usec / 1000; //转化为ns单位 for (;;) { int res = (*epoll_wait_func)(epfd, events, numfds, timeout); if (res < 0 && errno == EINTR) { //处理异常 if (remaining >= 0) { gettimeofday(&t, NULL); now = t.tv_sec * 1000 + t.tv_usec / 1000; diff = now - start; remaining -= diff; if (diff < 0 || remaining <= 0) { return 0; } start = now; } } else { return res; } } }
看下wakeup的实现 :
EPollSelectorImpl类: EPollSelectorImpl(SelectorProvider sp) { super(sp); int[] fdes = new int[2]; IOUtil.initPipe(fdes, false); fd0 = fdes[0]; fd1 = fdes[1]; pollWrapper = new EPollArrayWrapper(); pollWrapper.initInterrupt(fd0, fd1); // 设置中断的两个描述符 fdToKey = new HashMap(); } public Selector wakeup() { synchronized (interruptLock) { if (!interruptTriggered) { pollWrapper.interrupt(); //调用warpper进行中断 interruptTriggered = true; } } return this; } 继续看下EPollArrayWrapper : void initInterrupt(int fd0, int fd1) { outgoingInterruptFD = fd1; //保存pipeline的描述符 incomingInterruptFD = fd0; epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN); //注册到epoll上。 } public void interrupt() { interrupt(outgoingInterruptFD); //调用native方法 } 继续看下EPollArrayWrapper.c native实现: JNIEXPORT void JNICALL Java_sun_nio_ch_EPollArrayWrapper_interrupt(JNIEnv *env, jobject this, jint fd) { int fakebuf[1]; fakebuf[0] = 1; if (write(fd, fakebuf, 1) < 0) { //发送一字节的内容,让epoll_wait()能得到及时响应 JNU_ThrowIOExceptionWithLastError(env,"write to interrupt fd failed"); } }
实现方式也是挺简单的,弄了两个fd,一个往另一个写1byte的内容,促使epoll_wait能得到响应。
异步I/O模型:
暂时还未真实用过,只是大致看过其api,有兴趣可以自己baidu。
最后
后续会起一篇,单独针对nio在服务端和客户端使用上的注意点,主要是吸收了一些大牛门的经验,需要做个总结,消化一下。
评论
最近忙着做项目,都没太多时间写blog。
等项目走上正轨后,一定补上
发表评论
-
yugong QuickStart
2016-03-05 01:52 0几点说明 a. 数据迁移的方案可参见设计文档,oracl ... -
阿里巴巴开源项目: 阿里巴巴去Oracle数据迁移同步工具
2016-03-05 18:29 6546背景 08年左右,阿里巴巴开始尝试MySQL的相关 ... -
愚公performance
2016-03-02 17:29 0性能测试 全量测试 场景1 (单主键, ... -
yugong AdminGuide
2016-03-02 16:40 0环境要求 操作系统 数据库 迁移方案 部署 ... -
Tddl_hint
2014-01-27 13:52 0背景 工作原理 Hint格式 direct模 ... -
tddl5分库规则
2014-01-26 14:41 0背景 工作原理 构建语法树 元数据 基于 ... -
tddl5优化器
2014-01-22 15:12 0背景 工作原理 构建语法树 元数据 抽象语 ... -
Canal BinlogChange(mariadb5/10)
2014-01-20 17:25 4627背景 先前开源了一个 ... -
asynload quickstart
2013-10-08 22:49 0几点说明: 1. asyncload是做为一个j ... -
网友文档贡献
2013-09-18 15:50 01. Otter源代码解析系列 链接:http://e ... -
Manager配置介绍
2013-09-16 13:00 0通道配置说明 多种同步方式配置 a. 单向同步 ... -
canal&otter FAQ
2013-09-05 17:30 0常见问题 1. canal和 ... -
阿里巴巴开源项目:分布式数据库同步系统otter(解决中美异地机房)
2013-08-22 16:48 40476项目背景 阿里巴巴B2B公司,因为业务的特性 ... -
Otter AdminGuide
2013-08-19 11:06 0几点说明 otter系统自带了manager,所以简化了一 ... -
Otter高可用性
2013-08-17 23:41 0基本需求 网络不可靠,异地机房尤为明显. man ... -
Otter数据一致性
2013-08-17 23:39 0技术选型分析 需要处理一致性的业务场景: 多地修改 ( ... -
Otter扩展性
2013-08-17 22:20 0扩展性定义 按照实现不同,可分为两类: 数据处理自定 ... -
Otter双向回环控制
2013-08-17 21:37 0基本需求 支持mysql/oracle的异构数据库的双 ... -
Otter调度模型
2013-08-17 20:13 0背景 在介绍调度模型之前,首先了解一下otter系统要解 ... -
Otter Manager介绍
2013-08-16 11:16 0背景 otter4.0发布至 ...
相关推荐
ABB[a]-J-4ABB 机器人的 IO 通信 4.1 任务目标... 4.3 知识储备 4.3.1ABB 机器人 I/O 通信种类 机器人提供了丰富的 I/O 通信接口,可以轻松地实现与周边设备进行通信。 ABB 机器人 "PC "现场总线 "ABB 标准 " " "Device
ABB[a]-J-4ABB 机器人的 IO 通信 4.1 任务目标... 4.3 知识储备 4.3.1ABB 机器人 I/O 通信种类 机器人提供了丰富的 I/O 通信接口,可以轻松地实现与周边设备进行通信。 ABB 机器人 "PC "现场总线 "ABB 标准 " " "Device
#### 三、知识储备 ##### 3.1 ABB机器人I/O通信种类 - **机器人提供的I/O通信接口**:ABB机器人提供了丰富的I/O通信接口,能够方便地与其他设备进行通信。 - **通信协议**:包括但不限于DeviceNet、ProfiBus等现场...
本资源提供了新程序员考试大纲的详细信息,涵盖计算机科学基础、计算机系统基础知识、软件基础知识、网络基础知识和数据库基础知识等方面的知识点,为考生和相关从业人员提供了系统的知识储备和学习指南。
* ISA总线的主要性能指标:I/O地址空间0100H---03FFH,24位地址线可直接寻址的内容为16MB,8/16位数据线,62+36引脚,最大传输率8MB/S,DMA通道功能,开放式总线结构。 * EISA:Extended Industry ...
计算机系统概论是计算机科学领域的基石,它不仅为学生打下坚实的理论基础,也为未来从事系统编程、嵌入式开发或是硬件交互等相关工作提供了必不可少的知识储备。在计算机系统的学习中,汇编语言作为连接硬件和软件的...
【接口实验报告1】 引言: 计算机科学与技术的不断进步,...通过亲自动手进行硬件实验,学生能够更好地体会到计算机系统设计的复杂性和创造性,为解决未来可能遇到的计算机系统问题提供了有力的知识储备和技术支持。
计算机组成原理是计算机科学与技术领域的一门基础课程,它主要研究计算机系统中硬件部分的结构和工作原理。...对于想从事硬件设计、系统编程或者计算机系统分析的人来说,这门课程更是必不可少的知识储备。
* 在面试过程中,需要注意自己的语言表达能力和技术知识储备。 * 对于不熟悉的技术问题,可以礼貌地回答“不知道”,然后尝试分析和解决问题。 * 对于已经掌握的技术问题,需要详细地解释和演示,以展示自己的技术...
接口技术部分,习题涉及到I/O端口的使用,如`OUT`指令,用于将CPU内部的数据发送到外部设备的I/O端口。如`OUT DX, AL`指令将AL寄存器中的数据输出到由DX寄存器指定的I/O端口。这样的操作在实现CPU与外部设备通信时至...
在确定问题时,需要具备丰富的知识储备,并能够量化和比较不同组件的性能指标。 Oracle数据库性能优化的要点在于定位问题、监控预警和自动化运维。基线监控能帮助识别数据库组件的健康状况,预警系统则能提前发现...
而计算机则需要更多的专业知识储备。 - **通用性**:PLC通常由特定的厂商生产,各厂商之间产品不完全兼容。相比之下,计算机的标准化程度更高,兼容性更强。 - **运行方式**:PLC采用模块化结构,易于扩展和组合;...
计算机组成原理是计算机科学与技术领域的一门核心课程,它主要研究计算机系统的基本结构和工作原理。...对于从事硬件设计、系统架构或嵌入式开发的工程师来说,计算机组成原理更是必不可少的知识储备。
更重要的是,通过亲自操作,学生能够直观地感受到计算机硬件的实际工作情况,对于学生未来从事相关领域的深入研究和技术实践,提供了宝贵的经验和知识储备。通过这样的实践操作,学生将能够更好地理解计算机系统的...
《微机原理与接口技术》课程是计算机科学与技术专业学生必备的知识储备,它不仅包括了计算机硬件与软件的基础知识,还涉及到了计算机与外部设备通信的核心技术。在深入学习这门课程的过程中,掌握微机的工作原理和...
#### 三、基础知识储备 1. **音频脉冲产生**: 音频脉冲是通过计算特定音频的周期并将其除以2得到半周期时间。然后利用定时器计时半周期时间并在每个半周期结束时反转I/O口的状态,以此产生所需的频率脉冲。 2. **计...
设计报告中列举的参考文献涉及嵌入式开发、检测技术与系统设计、程序设计语言以及电工学等多个方面,显示了设计者在设计该装置时广博的知识储备和技术基础。 总结 十字旋转LED显示屏通过创新的设计,结合了动态视觉...