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

为何要用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();
				// 获取连接完成后返回的AsynchronousSocketChannel
				AsynchronousSocketChannel 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);
		// 以指定线程池来创建一个AsynchronousChannelGroup
		AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup
			.withThreadPool(executor);
		// 以指定线程池来创建一个AsynchronousServerSocketChannel
		AsynchronousServerSocketChannel 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 implements
	CompletionHandler<AsynchronousSocketChannel, Object>
{
	private AsynchronousServerSocketChannel serverChannel; 
	public AcceptHandler(AsynchronousServerSocketChannel sc)
	{
		this.serverChannel = sc;
	}
	// 定义一个ByteBuffer准备读取数据
	ByteBuffer buff = ByteBuffer.allocate(1024); 
	// 当有客户端连接上的时候触发该方法,将客户端的AsynchronousSocketChannel传入,以便发送数据
	@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>()  //② 读取客户端的数据,数据在buff里
		{
			@Override
			public 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);
			}
			@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);
	}
}
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;
	// 与服务器端通信的异步Channel
	AsynchronousSocketChannel 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);
		// 以指定线程池来创建一个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");
		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");
				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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值