一:异步套接字通道
1:设置服务器
1.1:打开 AsychronousServerSocketChannel 并将其绑定到类似于 ServerSocketChannel 的地址
AsynchronousServerSocketChannel server =
AsynchronousServerSocketChannel.open().bind(null);
方法 bind() 将一个套接字地址作为其参数。找到空闲端口的便利方法是传递一个 null 地址,它会自动将套接字绑定到本地主机地址,并使用空闲的 临时 端口。
---bind参数为bind(SocketAddress paramSocketAddress)
1.2:接受一个连接
Future<AsynchronousSocketChannel> acceptFuture = server.accept();
返回一个 Future<AsynchronousSocketChannel> 对象,该对象可在以后用于检索AsynchronousSocketChannel
1.3:利用 Future 对象,当前线程可阻塞来等待结果
AsynchronousSocketChannel worker = future.get();
此处,其阻塞超时时间为 10 秒:
AsynchronousSocketChannel worker = future.get(10, TimeUnit.SECONDS);
或者轮询操作的当前状态,还可取消操作:
if (!future.isDone()) {
future.cancel(true);
}
2:设置客户端
2.1:通过打开并连接与服务器之间的 AsynchronousSocketChannel
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
client.connect(server.getLocalAddress()).get();
2.1:使用读写字节缓存
// send a message to the server
ByteBuffer message = ByteBuffer.wrap("ping".getBytes());
client.write(message).get();
// read a message from the client
worker.read(readBuffer).get(10, TimeUnit.SECONDS);
System.out.println("Message: " + new String(readBuffer.array()));
还支持异步地分散读操作与写操作,该操作需要大量字节缓存。
新异步通道的 API 完全从底层套接字中抽取掉:无法直接获取套接字,而以前可以调用 socket() ,例如,SocketChannel。引入了两个新的方法 —— getOption 和 setOption —— 来在异步网络通道中查询并设置套接字选项。例如,可通过channel.getOption(StandardSocketOption.SO_RCVBUF) 而不是 channel.socket().getReceiveBufferSize(); 来检索接收缓存大小。
3:完成端口模型----处理程序
使用 Future 对象的替代机制,是向异步操作注册一个 callback 。接口 CompletionHandler 有两个方法:
o void completed(V result, A attachment) 在任务完成结果中具有类型 V 时执行。
o void failed(Throwable e, A attachment) 在任务由于 Throwable e 而失败时执行。
两个方法的附件参数都是一个传递到异步操作的对象。如果相同的对象用于多个操作,其可用于追踪哪个操作已完成。
4:创建一个新的通道
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("myfile"));
概述:异步通道 API 提供两种对已启动异步操作的监测与控制机制:
一:
第一种是通过返回一个 java.util.concurrent.Future 对象来实现,它将会建模一个挂起操作,并可用于查询其状态以及获取结果。
第一个返回java.util.concurrent.Future,代表等待结果,你可以使用Future特性等待I/O操作结束;
二:
第二种是通过传递给操作一个新类的对象,java.nio.channels.CompletionHandler,来完成,它会定义在操作完毕后所执行的处理程序方法。------主要做文件系统
第一步,我们要设置服务器
AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(threadGroup);
listener.bind(new InetSocketAddress(listeningAddress, listeningPort));
方法 bind() 将一个套接字地址作为其参数。找到空闲端口的便利方法是传递一个 null 地址,它会自动将套接字绑定到本地主机地址,并使用空闲的 临时 端口。
这个线程池执行两个任务:处理IO事件和
派发CompletionHandler,异步IO操作结果的回调接口,用于定义在IO操作完成后所作的回调工作
第二步:告诉通道接受一个连接
listener.accept(null, new AcceptCompletionHandler()); 这个返回void
或者
listener.accept(); 这个返回Future<AsynchronousSocketChannel>对象。
Future 对象的通用类型是实际操作的结果。比如,读取或写入操作会因为操作返回读或写的字节数,而返回一个 Future<Integer>。
利用 Future 对象,当前线程可阻塞来等待结果:
AsynchronousSocketChannel worker = future.get();
此处,其阻塞超时时间为 10 秒:
AsynchronousSocketChannel worker = future.get(10, TimeUnit.SECONDS);
第三步:客户端设置
1:接下来,要通过打开并连接与服务器之间的 AsynchronousSocketChannel,来设置客户端:
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
client.connect(server.getLocalAddress()).get();
Socket
2:通过实现new AcceptCompletionHandler()中的
private class AcceptCompletionHandler implements
CompletionHandler<AsynchronousSocketChannel, Object> {
public void completed(AsynchronousSocketChannel channel,
Object attachment) {
-------------------------
Session session = new AsynchronousSessionImpl(channel,
configuration, sessionCount);
----------------------------
第四步:通过AsynchronousSocketChannel对象进行read、write操作;
新方法getOption 和 setOption:异步网络通道中查询并设置套接字选项;例如
channel.getOption(StandardSocketOption.SO_RCVBUF) 而不是 channel.socket().getReceiveBufferSize(); 来检索接收缓存大小。
private void initOptions() throws IOException {
Map<SocketOption<Object>, Object> socketOptionMap = configuration
.getAllSocketOptions();
Iterator<Entry<SocketOption<Object>, Object>> it = socketOptionMap
.entrySet().iterator();
while (it.hasNext()) {
Entry<SocketOption<Object>, Object> entry = it.next();
SocketOption<Object> option = entry.getKey();
listener.setOption(option, entry.getValue());
}
}
第五步:实现一个完成处理程序
1:封装了 “ something ” 的 CompletionHandler:扩展CompletionHandler接口,实现completed、failed方法:
private class AcceptCompletionHandler implements
CompletionHandler<AsynchronousSocketChannel, Object> {
public void completed(AsynchronousSocketChannel channel,
Object attachment) {
try {
logger.info("Connection accepted(Remote machine:"
+ channel.getRemoteAddress());
} catch (IOException ex) {
errLogger.error(ex.getMessage());
}
sessionCount++;
Session session = new AsynchronousSessionImpl(channel,
configuration, sessionCount);
sessionMap.put(session.getSessionId(), session);
try {
processorFilter.processRequest(session);
} catch (Exception ex) {
processorFilter.processException(session, ex);
}
listener.accept(null, this);
}
public void failed(Throwable ex, Object attachment) {
errLogger.error("Error occured when accepting connection:");
errLogger.error(ex.getMessage());
try {
stop();
} catch (IOException e) {
errLogger.error(ex.getMessage());
}
}
}
第六步:异步通道组
java.nio.channels.AsynchronousChannelGroup 中的三个实用方法提供了创建新通道组的方法:
.withCachedThreadPool()---缓存池
And for a cached pool you need:
ExecutorService executor = Executors.newCachedThreadPool();
AsynchronousChannelGroup group =AsynchronousChannelGroup.withCachedThreadPool(executor, 4);
.withFixedThreadPool()---固定池
ExecutorService executor = Executors.newFixedThreadPool(8);
AsynchronousChannelGroup group =AsynchronousChannelGroup.withFixedThreadPool(executor, 8);
.withThreadPool()
ExecutorService executor = // whatever executor type
you want / fixed
cached etc...
AsynchronousChannelGroup group =AsynchronousChannelGroup.withThreadPool(executor);
相单于
ExecutorService executor = Executors.newCachedThreadPool();
AsynchronousChannelGroup group =AsynchronousChannelGroup.withCachedThreadPool(executor, 0);
如 java.util.concurrent.ExecutorService,或者是 java.util.concurrent.ThreadFactory。
如,以下调用创建了具有线程池的新的通道组,该线程池包含 10 个线程,其中每个都构造为来之Executors 类的线程工厂:
AsynchronousChannelGroup threadGroup =
AsynchronousChannelGroup.withFixedThreadPool(threadPoolSize,Executors.defaultThreadFactory());
当有异步操作请求时,此调用告诉 channel 使用 tenThreadGroup 而不是默认通道组来获取线程:
AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(threadGroup);