AIO实现非阻塞Socket通信

1.demo 

 

public class SimpleAIOServer {
	static final int PORT = 30000;

	public static void main(String[] args) throws Exception {
		// ①创建AsynchronousServerSocketChannel对象。
		AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
		// ②指定在指定地址、端口监听。
		serverChannel.bind(new InetSocketAddress(PORT));
		while (true) {
			// ③采用循环接受来自客户端的连接
			Future<AsynchronousSocketChannel> future = serverChannel.accept();
			// 获取连接完成后返回的AsynchronousSocketChannel
			AsynchronousSocketChannel socketChannel = future.get();
			// 执行输出。
			socketChannel.write(ByteBuffer.wrap("欢迎你来自AIO的世界!".getBytes("UTF-8"))).get();
		}
	}
}

public class SimpleAIOClient {
	static final int PORT = 30000;

	public static void main(String[] args) throws Exception {
		// 用于读取数据的ByteBuffer。
		ByteBuffer buff = ByteBuffer.allocate(1024);
		Charset utf = Charset.forName("utf-8");
		// ①创建AsynchronousSocketChannel对象
		AsynchronousSocketChannel clientChannel = AsynchronousSocketChannel.open();
		// ②连接远程服务器
		clientChannel.connect(new InetSocketAddress("127.0.0.1", PORT)).get(); // ④
		buff.clear();
		// ③从clientChannel中读取数据
		clientChannel.read(buff).get(); // ⑤
		buff.flip();
		// 将buff中内容转换为字符串
		String content = utf.decode(buff).toString();
		System.out.println("服务器信息:" + content);
	}
}

2.AIO版聊天程序

 

要注意的是要在服务端的completed方法中加if(result>0),否则客户端断开时会无限循环输出。
public class AIOServer {
	static final int PORT = 30000;
	final static String UTF_8 = "utf-8";
	static List<AsynchronousSocketChannel> channelList = new ArrayList<>();

	public void startListen() throws InterruptedException, Exception {
		// 创建一个线程池
		ExecutorService executor = Executors.newFixedThreadPool(20);
		// 以指定线程池来创建一个AsynchronousChannelGroup
		AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);
		// 以指定线程池来创建一个AsynchronousServerSocketChannel
		AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(channelGroup)
				// 指定监听本机的PORT端口
				.bind(new InetSocketAddress(PORT));
		// 使用CompletionHandler接受来自客户端的连接请求
		serverChannel.accept(null, new AcceptHandler(serverChannel)); // ①
		Thread.sleep(15000);
	}

	public static void main(String[] args) throws Exception {
		AIOServer server = new AIOServer();
		server.startListen();
	}
}

// 实现自己的CompletionHandler类
class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, Object> {
	private AsynchronousServerSocketChannel serverChannel;

	public AcceptHandler(AsynchronousServerSocketChannel sc) {
		this.serverChannel = sc;
	}

	// 定义一个ByteBuffer准备读取数据
	ByteBuffer buff = ByteBuffer.allocate(1024);

	// 当实际IO操作完成时候触发该方法
	@Override
	public void completed(final AsynchronousSocketChannel sc, Object attachment) {
		// 记录新连接的进来的Channel
		AIOServer.channelList.add(sc);
		// 准备接受客户端的下一次连接
		serverChannel.accept(null, this);
		sc.read(buff, null, new CompletionHandler<Integer, Object>() // ②
		{
			@Override
			public void completed(Integer result, Object attachment) {
				buff.flip();
				// 将buff中内容转换为字符串
				String content = StandardCharsets.UTF_8.decode(buff).toString();
				// 遍历每个Channel,将收到的信息写入各Channel中
				for (AsynchronousSocketChannel c : AIOServer.channelList) {
					try {
						c.write(ByteBuffer.wrap(content.getBytes(AIOServer.UTF_8))).get();
					} catch (Exception ex) {
						ex.printStackTrace();
					}
				}
				buff.clear();
				// 读取下一次数据
				sc.read(buff, null, this);
			}

			@Override
			public void failed(Throwable ex, Object attachment) {
				System.out.println("读取数据失败: " + ex);
				// 从该Channel读取数据失败,就将该Channel删除
				AIOServer.channelList.remove(sc);
			}
		});
	}

	@Override
	public void failed(Throwable ex, Object attachment) {
		System.out.println("连接失败: " + ex);
	}
}

public class AIOClient {
	final static String UTF_8 = "utf-8";
	final static int PORT = 30000;
	// 与服务器端通信的异步Channel
	AsynchronousSocketChannel clientChannel;

	public void init() throws Exception {
		Scanner scan = new Scanner(System.in);
		while (scan.hasNextLine()) {
			clientChannel.write(ByteBuffer.wrap(scan.nextLine().getBytes(UTF_8))).get(); // ①
		}
	}

	public void connect() throws Exception {
		// 定义一个ByteBuffer准备读取数据
		final ByteBuffer buff = ByteBuffer.allocate(1024);
		// 创建一个线程池
		ExecutorService executor = Executors.newFixedThreadPool(80);
		// 以指定线程池来创建一个AsynchronousChannelGroup
		AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);
		// 以channelGroup作为组管理器来创建AsynchronousSocketChannel
		clientChannel = AsynchronousSocketChannel.open(channelGroup);
		// 让AsynchronousSocketChannel连接到指定IP、指定端口
		clientChannel.connect(new InetSocketAddress("127.0.0.1", PORT)).get();
		// jta.append("---与服务器连接成功---\n");
		System.out.println("---与服务器连接成功---");
		buff.clear();
		clientChannel.read(buff, null, new CompletionHandler<Integer, Object>() // ②
		{
			@Override
			public void completed(Integer result, Object attachment) {
				buff.flip();
				// 将buff中内容转换为字符串
				String content = StandardCharsets.UTF_8.decode(buff).toString();
				// 显示从服务器端读取的数据
				// jta.append("某人说:" + content + "\n");
				System.out.println("某人说:" + content);
				buff.clear();
				clientChannel.read(buff, null, this);
			}

			@Override
			public void failed(Throwable ex, Object attachment) {
				System.out.println("读取数据失败: " + ex);
			}
		});
	}

	public static void main(String[] args) throws Exception {
		AIOClient client = new AIOClient();

		client.connect();
		client.init();
	}
}

 

参考:

 

疯狂java讲义
 

posted @ 2017-04-06 22:24  john8169  阅读(547)  评论(0编辑  收藏  举报