NIO 看破也说破(二)—— Java 中的两种 BIO
上一篇 Linux/IO 基础我们得出结论,提供网络能力的不是 Java 是 Linux 操作系统。本文我们通过分析系统函数调用,观察不同 jdk 版本中 BIO 的实现差别。NIO看破也说破(一)- Linux/IO基础
核心结论:
不同版本 jdk 实现方式不一致
如果不给 socket 设置 nonblocking,accept 会阻塞直到数据到达
poll 的调用是阻塞的,直到注册的 event 发生后,返回发生事件的 fd
环境准备
centOS 7
jdk1.5.0-jdk1.8.0
strace
测试代码
BIOServer.java
测试步骤
1、编译 BIOServer.java 后,命令行启动,监听 8080 端口
2、模拟 client 端 telnet localhost 8080,连通后立马断开
3、strace 监听 Java 进程的函数调用
Java5
strace 调用栈
查看 man 手册
如果没有对 socket 设置 nonblocking,accept 会一直阻塞直到一个链接出现
结论
java5 中的 bio 是通过 accept 阻塞实现
Java6
strace 调用栈
listen 之后这里没有立即调用 accept,而是先调用 poll 把 server_sockfd 与 pollfdArray[0]关联起来,然后再把 pollfdArray 放到 poll 里去,这里只有一个文件描述符。
调用 poll 会使得线程阻塞,当有客户端连接进来的时候,poll 函数就会返回一个整数,代表了数组中有多少个 socket 上有数据到达。对于第一次连接这种情况,返回值就是 1。
接着,先判断 pollfdArray[0]上是不是有数据,如果有的话,再去调用 accept 去接受新的连接,新的连接创建以后,我们会把新的 socket 放到 pollfdArray 中去,继续这个循环,然后在 poll 中再次休眠。
先看 man 手册中对于 poll 的定义:
man 手册可以得到如下结论:
1、poll 是和 select 类似的方法
2、当没有任何 event 到来时,poll 会阻塞,直到一个 event 发生
3、timeout 参数明确了 poll 在指定的毫秒内阻塞,指定一个负数表示无限超时
验证
猜想 server 启动后,没有客户端建立连接,系统调用应该阻塞在 poll 方法上
当有 client 与 8080 建立连接时,日志滚动,出现 accept 调用
日志继续停留在 poll 方法,验证猜想是正确的
结论
1、jdk6 中,bio 通过 poll 和 accept 的方式实现
2、poll 方法是阻塞的
Java7/8
strace 调用栈
可以看出 jdk7 和 jdk8 跟 jdk6 中的实现方式一致
备忘录
不同版本 jdk 实现方式不一致
如果不给 socket 设置 nonblocking,accept 会阻塞直到数据到达
poll 的调用是阻塞的,直到注册的 event 发生后,返回发生事件的 fd
系列
关注我
如果您在微信阅读,请您点击链接 关注我 ,如果您在 PC 上阅读请扫码关注我,欢迎与我交流随时指出错误
版权声明: 本文为 InfoQ 作者【小眼睛聊技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/e8ab7c9020253b83355c10661】。文章转载请联系作者。
评论 (4 条评论)