java aio 的一个demo
声明:本人小白一枚,如有不对的地方,欢迎一起讨论
aio 就是nio2.0,相对于nio1.0,系统帮我们做了更多的东西。让我们能够更多的注重业务代码实现。
服务端的实现
直接上代码,里面有注释
public static AsynchronousServerSocketChannel serverSocketChannel;//第二次接收的时候会使用到,因此作为一个属性
public static void main(String[] args) {
//新建一个线程池,使得aio中的操作都使用这个线程池中的线程,而且,还传入一个ThreadFactory对象,自己去定义线程
ExecutorService executorService = new ThreadPoolExecutor(10, 10, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
try {
//创建使用的公共线程池资源
AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executorService);
//创建AsynchronousServerSocketChannel对象
if(serverSocketChannel==null){
serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup);
}
//设定一些参数
//接收缓冲区的大小
serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);
//是否重用本地地址
serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
//绑定监听的端口号
serverSocketChannel.bind(new InetSocketAddress(Const.PORT));
//开始接收请求,第一个参数是根据自己的需求出入对应的对象
//第二个参数CompletionHandler的子对象
serverSocketChannel.accept(new AioServer(), new MyCompletion());
System.out.println("服务启动...");
//保持程序不停止
waitRevicer();
} catch (IOException e) {
e.printStackTrace();
}
}
accept 方法中第二个参数的说明
这里对MyCompletion
进行说明,它是CompletionHandler的实现类,实现了父类的completed
方法和failed
方法。
completed 方法是接收客户端的数据并进行处理。
failed 方法是程序发生了错误,对错误信息进行处理,本demo只是进行错误信息打印,故不进行解释说明。
completed
是接收完一个请求,对请求进行处理。有两个参数,第一个是客户端请求的对象的实例,第二个参数是我们在accept
方法中传入的对象。 通过客户端对象的read方法,我们能够获取客户端发送的数据。下面直接上代码,下面涉及到了一些ByteBuffer
类的知识,不会的同学,请移步aio系列文档(2)----图解bytebuffer,一个不错的文章。
public void completed(AsynchronousSocketChannel result, AioServer attachment) {
System.out.println("completed");
//用来缓存数据
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
try {
//读取客户端数据,存放到ByteBuffer对象中
result.read(byteBuffer).get();
//重新设置position和limit的值,为读取值做准备
byteBuffer.flip();
//根据值的长度创建对象,并将ByteBuffer中的数据存入,打印输出
byte[] input = new byte[byteBuffer.remaining()];
byteBuffer.get(input);
System.out.println(new String(input));
//重新设置position的值,并将客户端发送的值返回给客户端
byteBuffer.position(0);
result.write(byteBuffer);
// String sayHello = new String("你好啊,客户端"+result.getRemoteAddress().toString());
// System.out.println("sayHello:"+sayHello);
// result.write(ByteBuffer.wrap(sayHello.getBytes("UTF-8")));
attachment.serverSocketChannel.accept(attachment, this);//不重新设置接收的话就只能接收一次了
} catch (Exception e) {
e.printStackTrace();
}
}
需要注意的是在读取客户端数据的时候,因为ByteBuffer
的长度是1024,所以最多只能读取1024个字节的数据,没有把所有的数据取完,下面客户端的代码有这个实现,可以参考下。
客户端的实现
上代码
//获取AsynchronousSocketChannel的实例,这里可以跟服务器端一样传入一个AsynchronousChannelGroup的对象
AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
//连接服务器
Future<Void> future = socketChannel.connect(new InetSocketAddress(Const.SERVER_IP,Const.PORT));
//注意,这个get是一个阻塞的方法,只有当连接上了之后才会往下走
//如果不执行get方法,等程序没有连接成功时进行发送数据的操作会发生错误
future.get();
//拼接发送给服务器的数据
Random rom = new Random();
StringBuffer writeBuf = new StringBuffer();
writeBuf.append("this is client").append(rom.nextInt(1000));
System.out.println(writeBuf.toString());
ByteBuffer byteBuffer = ByteBuffer.wrap(writeBuf.toString().getBytes());
//发送数据
socketChannel.write(byteBuffer);
//读取服务器的返回的数据
read(socketChannel);
读取数据的方法基本同服务端是一致的,只是加了一个循环,直到取出所有的数据,不过多解释
private void read(AsynchronousSocketChannel socketChannel){
ByteBuffer byteBufer = ByteBuffer.allocate(10);
try {
StringBuffer strBuf = new StringBuffer("客户端:");
boolean hasData = true;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while(hasData){
socketChannel.read(byteBufer).get();
if(byteBufer.capacity()>byteBufer.position()){//当容器大小大于容器里面的数量的时候,认为读取完毕
hasData = false;
}
byteBufer.flip();
byte[] buf = new byte[byteBufer.remaining()];
byteBufer.get(buf);
if(hasData){
System.out.println("数据没有读取完毕继续读取");
}else{
System.out.println("数据读取完毕");
}
out.write(buf);
byteBufer.clear();
}
strBuf.append(new String(out.toByteArray(),"UTF-8"));
System.out.println(strBuf);
read(socketChannel);
} catch (Exception e) {
e.printStackTrace();
}
}
完整的代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* aio 服务端
* @author zxr
* 2017年8月10日 下午4:23:02
*/
public class AioServer {
public static AsynchronousServerSocketChannel serverSocketChannel;//第二次接收的时候会使用到,因此作为一个属性
public static void main(String[] args) {
//新建一个线程池,使得aio中的操作都使用这个线程池中的线程,而且,还传入一个ThreadFactory对象,自己去定义线程
ExecutorService executorService = new ThreadPoolExecutor(10, 10, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
try {
//创建使用的公共线程池资源
AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executorService);
//创建AsynchronousServerSocketChannel对象
if(serverSocketChannel==null){
serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup);
}
//设定一些参数
//接收缓冲区的大小
serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);
//是否重用本地地址
serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
//绑定监听的端口号
serverSocketChannel.bind(new InetSocketAddress(Const.PORT));
//开始接收请求,第一个参数是根据自己的需求出入对应的对象
//第二个参数CompletionHandler的子对象
serverSocketChannel.accept(new AioServer(), new MyCompletion());
System.out.println("服务启动...");
//保持程序不停止
waitRevicer();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void waitRevicer(){
new Thread(new Runnable() {
@Override
public void run() {
while(true){
System.out.println("保持程序运行不停止...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
class MyCompletion implements CompletionHandler<AsynchronousSocketChannel,AioServer>{
@Override
public void completed(AsynchronousSocketChannel result, AioServer attachment) {
System.out.println("completed");
//用来缓存数据
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
try {
//读取客户端数据,存放到ByteBuffer对象中
result.read(byteBuffer).get();
//重新设置position和limit的值,为读取值做准备
byteBuffer.flip();
//根据值的长度创建对象,并将ByteBuffer中的数据存入,打印输出
byte[] input = new byte[byteBuffer.remaining()];
byteBuffer.get(input);
System.out.println(new String(input));
//重新设置position的值,并将客户端发送的值返回给客户端
byteBuffer.position(0);
result.write(byteBuffer);
// String sayHello = new String("你好啊,客户端"+result.getRemoteAddress().toString());
// System.out.println("sayHello:"+sayHello);
// result.write(ByteBuffer.wrap(sayHello.getBytes("UTF-8")));
attachment.serverSocketChannel.accept(attachment, this);//不重新设置接收的话就只能接收一次了
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, AioServer attachment) {
System.out.println("failed");
System.out.println(attachment);
System.out.println(exc);
}
}
import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class AioClient {
public static void main(String[] args) throws InterruptedException, ExecutionException {
new AioClientThread().start();
new AioClientThread().start();
new AioClientThread().start();
}
}
class AioClientThread extends Thread{
@Override
public void run() {
super.run();
try {
//获取AsynchronousSocketChannel的实例,这里可以跟服务器端一样传入一个AsynchronousChannelGroup的对象
AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
//连接服务器
Future<Void> future = socketChannel.connect(new InetSocketAddress(Const.SERVER_IP,Const.PORT));
//注意,这个get是一个阻塞的方法,只有当连接上了之后才会往下走
//如果不执行get方法,等程序没有连接成功时进行发送数据的操作会发生错误
future.get();
//拼接发送给服务器的数据
Random rom = new Random();
StringBuffer writeBuf = new StringBuffer();
writeBuf.append("this is client").append(rom.nextInt(1000));
System.out.println(writeBuf.toString());
ByteBuffer byteBuffer = ByteBuffer.wrap(writeBuf.toString().getBytes());
//发送数据
socketChannel.write(byteBuffer);
//读取服务器的返回的数据
read(socketChannel);
} catch (Exception e) {
e.printStackTrace();
}
}
private void read(AsynchronousSocketChannel socketChannel){
ByteBuffer byteBufer = ByteBuffer.allocate(10);
try {
StringBuffer strBuf = new StringBuffer("客户端:");
boolean hasData = true;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while(hasData){
socketChannel.read(byteBufer).get();
if(byteBufer.capacity()>byteBufer.position()){//当容器大小大于容器里面的数量的时候,认为读取完毕
hasData = false;
}
byteBufer.flip();
byte[] buf = new byte[byteBufer.remaining()];
byteBufer.get(buf);
if(hasData){
System.out.println("数据没有读取完毕继续读取");
}else{
System.out.println("数据读取完毕");
}
out.write(buf);
byteBufer.clear();
}
strBuf.append(new String(out.toByteArray(),"UTF-8"));
System.out.println(strBuf);
read(socketChannel);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Const {
public static final int PORT = 6987;
public static final String SERVER_IP = "127.0.0.1";
}