Java 网络编程 —— 异步通道和异步运算结果
从 JDK7 开始,引入了表示异步通道的 AsynchronousSockerChannel 类和 AsynchronousServerSocketChannel 类,这两个类的作用与 SocketChannel 类和 ServerSockelChannel 相似,区别在于异步通道的一些方法总是采用非阻塞模式,并且它们的非阻塞方法会立即返回一个 Future 对象,用来存放方法的异步运算结果
AsynchronousSocketChannel 类有以下非阻塞方法:
// 连接远程主机
Future<Void> connect(SocketAddress remote);
// 从通道中读入数据,存放到ByteBuffer中
// Future对象包含了实际从通道中读到的字节数
Future<Inleger> read(ByteBuffer dst);
// 把ByteBuffer的数据写入通道
// Future对象包含了实际写入通道的字节数
Future<Integer> write(ByteBuffer src);
AsynchronousServerSocketChannel 类有以下非阻塞方法:
// 接受客户连接请求
// Future对象包含连接建立成功后创建的AsynchronousSockelChannel对象
Future<AsynchronousSocketChannel> accept();
使用异步通道,可以使程序并行执行多个异步操作,例如:
SocketAddress socketAddress = ...;
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
//请求建立连接
Future<Void> connected = client.connect(socketAddress);
ByteBuffer byteBuffer = ByteBuffer.allocate(128);
//执行其他操作
//...
//等待连接完成
connected.get();
//读取数据
Future<Integer> future = client.read(byteBuffer);
//执行其他操作
//...
//等待从通道读取数据完成
future.get();
byteBuffer.flip();
WritableByteChannel out = Channels.newChannel(System.out);
out.write(byteBuffer);
下例的代码演示了异步通道的用法,它不断接收用户输入的域名并尝试建立连接,最后打印建立连接所花费的时间。如果程序无法连接到指定的主机,就打印相关错误信息。如果用户输入 bye,就结束程序
//表示连接一个主机的结果
class PingResult {
InetSocketAddress address;
long connectStart; //开始连接时的时间
long connectFinish = 0; //连接成功时的时间
String failure;
Future<Void> connectResult; //连接操作的异步运算结果
AsynchronousSocketChannel socketChannel;
String host;
final String ERROR = "连接失败";
PingResult(String host) {
try {
this.host = host;
address = new InetSocketAddress(InetAddress.getByName(host), 80);
} catch (IOException x) {
failure = ERROR;
}
}
//打印连接一个主机的执行结果
public void print() {
String result;
if (connectFinish != 0) {
result = Long.toString(connectFinish - connectStart) + "ms";
} else if (failure != null) {
result = failure;
} else {
result = "Timed out";
}
System,out,println("ping "+ host + "的结果" + ":" + result);
}
public class PingClient {
//存放所有PingResult结果的队列
private LinkedList<PingResult> pingResults = new Linkedlist<PingResult>();
boolean shutdown = false;
ExecutorService executorService;
public PingClient() throws IOException {
executorService = Executors.newFixedThreadPool(4);
executorService.execute(new Printer());
receivePingAddress();
}
}
public static void main(String args[]) throws IOException {
new PingClient();
}
/*接收用户输入的主机地址,由线程池执行PingHandler任务 */
public void receivePingAddress() {
try {
BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
//接收用户输入的主机地址
while((msg = localReader.readLine()) != null) {
if(msg.equals("bye")) {
shutdown = true;
executorService.shutdown();
break;
}
executorService.execute(new PingHandler(msg));
}
} catch(IOException e) {}
}
/* 尝试连接特定主机,生成一个PingResult对象,把它加入PingResults结果队列中 */
public class PingHandler implements Runnable {
String msg;
public PingHandler(String msg) {
this.msg = msg;
}
public void run() {
if(!msg.equals("bye")) {
PingResult pingResult = new PingResult(msg);
AsynchronousSocketChannel socketChannel = null;
try {
socketChannel = AsynchronousSocketChannel.open();
pingResult.connectStart = System.currentTimeMillis();
synchronized (pingResults) {
//向pingResults队列加入一个PingResult对象
pingResults.add(pingResult);
pingResults,notify();
}
Future<Void> connectResult = socketChannel.connect(pingResult.address);
pingResult.connectResult = connectResult;
} catch (Exception x) {
if (socketChannel != null) {
try { socketChannel.close();} catch (IOException e) {)
}
pingResult.failure = pingResult.ERROR;
}
}
}
}
/* 打印PingResults结果队列中已经执行完毕的任务的结果 */
public class Printer implements Runnable {
public void run() {
PingResult pingResult = null;
while(!shutdown) {
synchronized (pingResults) {
while (!shutdown && pingResults.size() == 0 ) {
try {
pingResults.wait(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
if(shutdown && pingResults.size() == 0 ) break;
pingResult = pingResults.getFirst();
try {
if(pingResult.connectResult != null) {
pingResult.connectResult.get(500, TimeUnit,MILLISECONDS);
} catch(Exception e) {
pingResult.failure = pingResult.ERROR;
}
}
if(pingResult.connectResult != null && pingResult.connectResult.isDone()) {
pingResult.connectFinish = System.currentTimeMillis();
}
if(pingResult,connectResult != null && pingResult.connectResult.isDone() || || pingResult,failure != null) {
pingResult.print();
pingResults.removeFirst();
try {
pingResult.socketChannel.close();
} catch (IOException e) {}
}
}
}
}
}
}
PingClient 类定义了两个表示特定任务的内部类:
PingHandler:负责通过异步通道去尝试连接客户端输入的主机地址,并且创建一个PingResult对象,它包含了连接操作的异步运算结果,再将其加入PingResults结果队列Printer:负责打印PingResults结果队列已经执行完毕的任务结果,打印完毕的PingResult对象会从队列中删除
Java 网络编程 —— 异步通道和异步运算结果的更多相关文章
- Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO
Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...
- Java网络编程基础(Netty预备知识)
今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...
- Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector
Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...
- Java网络编程和NIO详解3:IO模型与Java网络编程模型
Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...
- Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
本文转载 https://www.javadoop.com 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c ...
- Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
本文转自:http://www.sohu.com/a/203838233_827544 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 ht ...
- 这份书单会告诉你,Java网络编程其实很重要
- Java 网络编程学习总结
新手一枚,Java学习中,把自己学习网络编程的知识总结一下,梳理下知识,方便日后查阅,高手莫进. 本文的主要内容: [1] 网络编程认识 [2] TCP/IP编程 ...
- 【Android实战】----从Retrofit源代码分析到Java网络编程以及HTTP权威指南想到的
一.简单介绍 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明确为什么Retrofit那么屌. 近期也看了一些其源代码分析的文章以及亲自查看了源代码 ...
- Java网络编程和NIO详解9:基于NIO的网络编程框架Netty
Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...
随机推荐
- CDQ分治(初步入门)
CDQ分治 CDQ分治,传说中是一个神犇创造的算法. 在了解这种算法之前,我们有必要了解一下一种基本的思想:分治. 分治介绍 分而治之,将原问题不断划分成若干个子问题,直到子问题规模小到足以直接解决 ...
- 如何理解微服务体系结构中的 CQRS
本文翻译自 How To Understand CQRS In Microservices Architecture,原作者 OLEKSII. 问题描述 在典型的软件应用程序中,有一个负责写入和读取操 ...
- SpringBoot实现Flyway的Callback回调钩子
背景 产品迭代使用CI/CD升级过程中,需要对不同发布环境的不同产品版本进行数据库迭代升级,我们在中间某次产品迭代时加入了Flyway中间件以实现数据库结构的自动化升级. 需求 由于是迭代过程中加入的 ...
- java制作游戏,如何使用libgdx,入门级别教学
第一步,进入libgdx的官网.点击get started 进入这个页面,点击setup a project 进入这个页面直接点击,Generate a project. 点击下载,下载创建工具 它会 ...
- 华企盾DSC导致Solidworks无法导出xls文件
将Solidworks进程和Excel进程的OLE控制和启用虚拟重定向都关闭
- CENTOS docker拉取私服镜像
概述 docker的应用越来越多,安装部署越来越方便,批量自动化的镜像生成和发布都需要docker镜像的拉取. centos6版本太老,docker的使用过程中问题较多,centos7相对简单容易. ...
- 第三方登录--QQ登录--单体应用
从零玩转第三方QQ登录 下面有源码 前后端分离版本 一样的思路 https://www.cnblogs.com/Yangbuyi/p/13194007.html 第三方GITEE登录 https:// ...
- 隐匿自己的c2服务器(一)
隐匿自己的c2服务器(一) 目录 隐匿自己的c2服务器(一) 服务器设置 安装java环境 启动设置 开启禁ping 微信机器人推送上线信息 ️端口特征修改 证书特征修改 流量特征修改 利用cdn加 ...
- Windows系统修复(System Update Readiness Tool、SFC模式、DISM命令)可解决系统更新问题。
安装System Update Readiness Tool 提供此更新是因为在 Windows servicing store 中发现了不一致,这可能会影响将来成功安装更新.service pack ...
- @Conditional+@Configuration有没有搞头?
日拱一卒,功不唐捐. 在了解 @Conditional 之前先花 10 秒钟复习一下 @Configuration 这个注解. @Configuration 是干什么? 是配合 @Bean 注解来配置 ...