使用Java7的AIO实现非阻塞通信

来源:互联网 发布:fifo淘汰算法 编辑:程序博客网 时间:2024/06/02 00:18

为何要用AIO呢?效率更高。

AsynchronousServerSocketChannel用于服务器端,只要三步

1.调用open()静态方法创建AsynchronousServerSocketChannel。

2.调用AsynchronousServerSocketChannel的bind()方法让它在指定的IP地址,指定端口监听。

3.调用AsynchronousServerSocketChannel的accept()方法接受请求。

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


AsynchronousSocketChannel用于客户端,它的用法分三步

1.调用open静态方法创建AsynchronousSocketChannel。

2.调用AsynchronousSocketChannel的connect()方法连接到指定的IP地址,指定端口的服务器

3.调用read() , write()方法。

SimpleAIOClient.java

import java.net.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;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");try(// ①创建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);}}}

再使用AIO开发聊天室

AIOServer.java

import java.net.*;import java.io.*;import java.util.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;import java.util.concurrent.*;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);// 以指定线程池来创建一个AsynchronousChannelGroupAsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);// 以指定线程池来创建一个AsynchronousServerSocketChannelAsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(channelGroup)// 指定监听本机的PORT端口.bind(new InetSocketAddress(PORT));// 使用CompletionHandler接受来自客户端的连接请求serverChannel.accept(null, new AcceptHandler(serverChannel));  //①}   public static void main(String[] args)throws Exception{AIOServer server = new AIOServer();server.startListen();}}// 实现自己的CompletionHandler类class AcceptHandler implementsCompletionHandler<AsynchronousSocketChannel, Object>{private AsynchronousServerSocketChannel serverChannel; public AcceptHandler(AsynchronousServerSocketChannel sc){this.serverChannel = sc;}// 定义一个ByteBuffer准备读取数据ByteBuffer buff = ByteBuffer.allocate(1024); // 当有客户端连接上的时候触发该方法,将客户端的AsynchronousSocketChannel传入,以便发送数据@Overridepublic void completed(final AsynchronousSocketChannel sc, Object attachment){// 记录新连接的进来的ChannelAIOServer.channelList.add(sc);// 准备接受客户端的下一次连接serverChannel.accept(null , this);sc.read(buff , null , new CompletionHandler<Integer,Object>()  //② 读取客户端的数据,数据在buff里{@Overridepublic void completed(Integer result   //这里表示当客户端AsynchronousSocketChannel完成一次IO,调用此方法, 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);}@Overridepublic void failed(Throwable ex, Object attachment){System.out.println("读取数据失败: " + ex);// 从该Channel读取数据失败,就将该Channel删除AIOServer.channelList.remove(sc);}});}@Overridepublic void failed(Throwable ex, Object attachment){System.out.println("连接失败: " + ex);}}
AIOClient.java

import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.net.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;import java.util.concurrent.*;/** * Description: * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>  * <br/>Copyright (C), 2001-2012, Yeeku.H.Lee * <br/>This program is protected by copyright laws. * <br/>Program Name: * <br/>Date: * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */public class AIOClient{final static String UTF_8 = "utf-8";final static int PORT = 30000;// 与服务器端通信的异步ChannelAsynchronousSocketChannel clientChannel;JFrame mainWin = new JFrame("多人聊天");JTextArea jta = new JTextArea(16 , 48);JTextField jtf = new JTextField(40);JButton sendBn = new JButton("发送");public void init(){mainWin.setLayout(new BorderLayout());jta.setEditable(false);mainWin.add(new JScrollPane(jta), BorderLayout.CENTER);JPanel jp = new JPanel();jp.add(jtf);jp.add(sendBn);//发送消息的Action,Action是ActionListener的子接口Action sendAction = new AbstractAction(){public void actionPerformed(ActionEvent e){String content = jtf.getText();if (content.trim().length() > 0){try{// 将content内容写入Channel中clientChannel.write(ByteBuffer.wrap(content.trim().getBytes(UTF_8))).get();    //①}catch (Exception ex){ex.printStackTrace();}}// 清空输入框jtf.setText("");}};sendBn.addActionListener(sendAction);//将Ctrl+Enter键和"send"关联jtf.getInputMap().put(KeyStroke.getKeyStroke('\n', java.awt.event.InputEvent.CTRL_MASK) , "send");//将"send"和sendAction关联jtf.getActionMap().put("send", sendAction);mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);mainWin.add(jp , BorderLayout.SOUTH);mainWin.pack();mainWin.setVisible(true);}public void connect()throws Exception{// 定义一个ByteBuffer准备读取数据final ByteBuffer buff = ByteBuffer.allocate(1024);// 创建一个线程池ExecutorService executor = Executors.newFixedThreadPool(80);// 以指定线程池来创建一个AsynchronousChannelGroupAsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);// 以channelGroup作为组管理器来创建AsynchronousSocketChannelclientChannel = AsynchronousSocketChannel.open(channelGroup);// 让AsynchronousSocketChannel连接到指定IP、指定端口clientChannel.connect(new InetSocketAddress("127.0.0.1", PORT)).get(); jta.append("---与服务器连接成功---\n");buff.clear();clientChannel.read(buff, null, new CompletionHandler<Integer,Object>()   //②{@Overridepublic void completed(Integer result, Object attachment){buff.flip();// 将buff中内容转换为字符串String content = StandardCharsets.UTF_8.decode(buff).toString();// 显示从服务器端读取的数据jta.append("某人说:" + content + "\n");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.init();client.connect();}}





0 0
原创粉丝点击