4000-520-616
欢迎来到免疫在线!(蚂蚁淘生物旗下平台)  请登录 |  免费注册 |  询价篮
主营:原厂直采,平行进口,授权代理(蚂蚁淘为您服务)
咨询热线电话
4000-520-616
当前位置: 首页 > 新闻动态 >
新闻详情
Java 中的两种 BIO-鸿蒙HarmonyOS技术社区-官方战略合作伙伴-51...
来自 : harmonyos.51cto.com/posts/... 发布时间:2021-03-25
鸿蒙HarmonyOS技术社区 首页 专栏 问答 学院 活动 极客Show 登录 注册 51CTO

中国优质的IT技术网站

51CTO学院

IT职业在线教育平台

Java 中的两种 BIO lingyuli 发布于 2020-9-9 11:00 678浏览 0收藏

核心结论:

不同版本jdk实现方式不一致

如果不给socket设置nonblocking,accept会阻塞直到数据到达

poll的调用是阻塞的,直到注册的event发生后,返回发生事件的fd\'Java

环境准备
centOS 7

jdk1.5.0-jdk1.8.0

strace

测试代码

BIOServer.java

import java.io.IOException;import java.net.ServerSocket;public class BIOServer { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(8080); while (true) { server.accept(); System.out.println(\"===========\");}

测试步骤
1、编译BIOServer.java后,命令行启动,监听8080端口

2、模拟client端telnet localhost 8080,连通后立马断开

3、strace监听Java进程的函数调用

Java5
strace调用栈

//开启3号fd3188 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 33189 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0//对fd3 绑定8080端口,返回成功3190 bind(3, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr(\"0.0.0.0\")}, 16) = 0//监听fd3 3191 listen(3, 50) = 03197 gettimeofday({tv_sec=1588789268, tv_usec=224692}, NULL) = 03198 gettimeofday({tv_sec=1588789268, tv_usec=224993}, NULL) = 03199 gettimeofday({tv_sec=1588789268, tv_usec=225263}, NULL) = 0//从fd3中接受到新的连接,放到fd5中3200 accept(3, {sa_family=AF_INET, sin_port=htons(40862), sin_addr=inet_addr(\"127.0.0.1\")}, [16]) = 53199 gettimeofday({tv_sec=1588789268, tv_usec=225263}, NULL) = 03201 gettimeofday({tv_sec=1588789270, tv_usec=619848}, NULL) = 03208 gettimeofday({tv_sec=1588789270, tv_usec=623749}, NULL) = 03209 write(1, \"===========\", 11) = 113210 write(1, \"\\n\", 1) = 13211 accept(3, 0xffe9a4ec, [16]) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)3212 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---3213 futex(0xf79429c0, FUTEX_WAKE_PRIVATE, 1) = 13214 rt_sigreturn({mask=[QUIT]}) = 1023215 accept(3, unfinished ... ) = ?

查看man手册

If no pending connections are present on the queue, and the socket is not marked as nonblocking, accept() blocks the caller until a connection is present. If the socket is marked nonblocking and no pending connections are present on the queue, accept() fails with the error EAGAIN or EWOULDBLOCK.

如果没有对socket设置nonblocking,accept会一直阻塞直到一个链接出现

结论
java5中的bio是通过accept阻塞实现

Java6
strace调用栈

// 打开6号fd13614 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 613615 fcntl(6, F_GETFL) = 0x2 (flags O_RDWR)13616 fcntl(6, F_SETFL, O_RDWR|O_NONBLOCK) = 013617 setsockopt(6, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 013618 gettimeofday({tv_sec=1588790897, tv_usec=258322}, NULL) = 013619 gettimeofday({tv_sec=1588790897, tv_usec=277413}, NULL) = 013620 gettimeofday({tv_sec=1588790897, tv_usec=277603}, NULL) = 0 //对fd6绑定808013621 bind(6, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr(\"0.0.0.0\")}, 16) = 013622 listen(6, 50) = 013623 gettimeofday({tv_sec=1588790897, tv_usec=278363}, NULL) = 013624 gettimeofday({tv_sec=1588790897, tv_usec=287641}, NULL) = 0//先把6号fd放入poll中监听,返回1个POLLIN的fd13625 poll([{fd=6, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=6, revents=POLLIN}])//调用accept把fd6中的内容读出来13626 accept(6, {sa_family=AF_INET, sin_port=htons(40868), sin_addr=inet_addr(\"127.0.0.1\")}, [16]) = 813627 fcntl(8, F_GETFL) = 0x2 (flags O_RDWR)13628 fcntl(8, F_SETFL, O_RDWR) = 013629 gettimeofday({tv_sec=1588790899, tv_usec=835776}, NULL) = 013630 gettimeofday({tv_sec=1588790899, tv_usec=837031}, NULL) = 013631 gettimeofday({tv_sec=1588790899, tv_usec=837294}, NULL) = 013632 gettimeofday({tv_sec=1588790899, tv_usec=837659}, NULL) = 013633 gettimeofday({tv_sec=1588790899, tv_usec=838010}, NULL) = 013634 write(1, \"===========\", 11) = 1113635 write(1, \"\\n\", 1) = 1// 读取完数据后,再次吧6号fd放入到poll中等待数据13636 poll([{fd=6, events=POLLIN|POLLERR}], 1, -1 unfinished ... ) = ?13637 +++ exited with 130 +++

listen之后这里没有立即调用 accept,而是先调用poll把 server_sockfd 与pollfdArray[0]关联起来,然后再把pollfdArray放到poll里去,这里只有一个文件描述符。

调用poll会使得线程阻塞,当有客户端连接进来的时候,poll函数就会返回一个整数,代表了数组中有多少个socket上有数据到达。对于第一次连接这种情况,返回值就是1。

接着,先判断pollfdArray[0]上是不是有数据,如果有的话,再去调用accept去接受新的连接,新的连接创建以后,我们会把新的socket放到pollfdArray中去,继续这个循环,然后在poll中再次休眠。

先看man手册中对于poll的定义:

NAME poll, ppoll - wait for some event on a file descriptorSYNOPSIS #include poll.h  int poll(struct pollfd *fds, nfds_t nfds, int timeout);DESCRIPTION poll() performs a similar task to select(2): it waits for one of a set of file descriptors to become ready to perform I/O.

本文链接: http://bioblocks.immuno-online.com/view-748979.html

发布于 : 2021-03-25 阅读(0)
公司介绍
品牌分类
其他
联络我们
服务热线:4000-520-616
(限工作日9:00-18:00)
QQ :1570468124
手机:18915418616