jdk提供的NIO使用:
博主抄写了网上的demo,略作修改与调整,原文链接:
1、服务端代码:
package com.test3; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.util.Iterator; /** * NIO服务端代码 * @author http:// * @author ZX * 监听客户端连接,接收、发送消息 * */ public class AServer { public static void main(String[]args)throws Exception{ System.out.println("================="); //创建选择器 Selector selector = Selector.open(); //创建打开服务端的监听 ServerSocketChannel sChannel = ServerSocketChannel.open(); //绑定本地地址 sChannel.socket().bind(new InetSocketAddress(9999)); //设置非阻塞模式 sChannel.configureBlocking(false); //将通道绑定到选择器,非阻塞通道才能注册到选择器,第二个参数好像是方式或者操作吧 sChannel.register(selector, SelectionKey.OP_ACCEPT); TcpProtocal protocol = new TcpProtocal(); //循环监听等待 while (true){ // if(selector.select(3000)==0){ System.out.println("继续等待"); continue; } //间听到的可操作集合 Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator(); while (keyIter.hasNext()){ SelectionKey key = keyIter.next(); //这是干嘛的?获取下下个?一点用没有啊??? /* SelectionKey key1; if(keyIter.hasNext()){ key1 = keyIter.next(); }*/ try { //如果有客户端连接请求 if(key.isAcceptable()){ protocol.handleAccept(key); } //如果有数据发送 if(key.isReadable()){ protocol.handleRead(key); protocol.handleWrite(key); } //是否有效,是否可发送给客户端 if(key.isValid()&&key.isWritable()){ //protocol.handleWriteMsg(key,"我服务端在这里说点事情"); } }catch (IOException e){ keyIter.remove(); e.printStackTrace(); continue; } //删除处理过的键 keyIter.remove(); } } } }
2、协议:
package com.test3; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; /** * 定义一个协议传输信息 */ public class TcpProtocal { private int bufferSize=1024; /** 接受一个SocketChannel处理*/ public void handleAccept(SelectionKey key) throws Exception{ //返回创建此键的通道,接收客户端建立连接的请求,并返回socketChannel对象 SocketChannel clientChannel=((ServerSocketChannel)key.channel()).accept(); //设置非阻塞 clientChannel.configureBlocking(false); //注册到selector clientChannel.register(key.selector(),SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize)); } /** 从一个一个SocketChannel读取信息*/ public void handleRead(SelectionKey key) throws Exception{ //获得与客户端通信的通道 SocketChannel clientChannel=(SocketChannel)key.channel(); //得到并清空缓冲区并清空缓冲区 ByteBuffer buffer= (ByteBuffer)key.attachment(); buffer.clear(); //读取信息获得的字节数 int byteRead = clientChannel.read(buffer); if(byteRead==-1){ clientChannel.close(); }else{ //将缓冲区准备为数据传状态 buffer.flip(); //将字节转换为UTF-16 String receivedStr = Charset.forName("UTF-8").newDecoder().decode(buffer).toString(); System.out.println("接收到来自"+clientChannel.socket().getRemoteSocketAddress()+"信息"+receivedStr); key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE); /*String sendStr ="已收到信息"; buffer=ByteBuffer.wrap(sendStr.getBytes("UTF-8")); clientChannel.write(buffer); //设置为下依稀读取写入做准备 key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);*/ } } /** 向一个一个SocketChannel写入信息*/ public void handleWrite(SelectionKey key) throws Exception{ handleWriteMsg(key,null); } /** 向一个一个SocketChannel写入信息*/ public void handleWriteMsg(SelectionKey key,String msg) throws Exception{ if(msg==null||"".equals(msg)){ msg="服务器主动说:已收到建立请求消息"; } //获得与客户端通信的通道 SocketChannel clientChannel=(SocketChannel)key.channel(); //得到并清空缓冲区并清空缓冲区 ByteBuffer buffer= (ByteBuffer)key.attachment(); buffer.clear(); String sendStr =msg; buffer=ByteBuffer.wrap(sendStr.getBytes("UTF-8")); clientChannel.write(buffer); //设置为下依稀读取写入做准备 key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE); } }
3、客户端处理类:
package com.test3; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; public class TcpClientReadThread implements Runnable{ private Selector selector; public TcpClientReadThread(Selector selector){ this.selector=selector; new Thread(this).start(); } public void run() { try { //select()方法只能使用一次,用过之后就会删除,每个连接到服务器的选择器都是独立的 while (selector.select()>0){ //遍历所有可以IO操作做的Channel对应的selectionKey for(SelectionKey sk:selector.selectedKeys()){ //如果数据可读 if(sk.isReadable()){ //使用NIO读取Channel中可读数据 //获取通道信息 SocketChannel sc = (SocketChannel)sk.channel(); //创建缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); //读取数据到缓冲区 sc.read(buffer); //吊用此方法为读取写入做准备 buffer.flip(); String receiveStr = Charset.forName("UTF-8").newDecoder().decode(buffer).toString(); System.out.println("收到服务器"+sc.socket().getRemoteSocketAddress()+"信息"+receiveStr); //为下一次读取做准备 sk.interestOps(SelectionKey.OP_READ); //删除正在处理的selectionKey selector.selectedKeys().remove(sk); } } } }catch (Exception e){ e.printStackTrace(); } } }
4、客户端代码:
package com.test3; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Scanner; public class AClient { private Selector selector; private SocketChannel socketChannel; private String hostIp; private int hostPort; public AClient(String hostIp,int hostPort)throws Exception{ this.hostIp=hostIp; this.hostPort=hostPort; init(); } public void init()throws Exception{ socketChannel=SocketChannel.open(new InetSocketAddress(hostIp,hostPort)); socketChannel.configureBlocking(false); //打开并注册选择器信道、 selector= Selector.open(); socketChannel.register(selector,SelectionKey.OP_READ); //启动读取线程 new TcpClientReadThread(selector); } /** *发送字符串到服务器 */ public void sendMsg(String msgg)throws Exception{ ByteBuffer writeBuffer = ByteBuffer.wrap(msgg.getBytes("UTF-8")); socketChannel.write(writeBuffer); } static AClient aClient; static boolean mFlag=true; public static void main(String[]args)throws Exception{ aClient=new AClient("127.0.0.1",9999); new Thread(){ @Override public void run() { try { aClient.sendMsg("客户端======"); while (mFlag){ Scanner sc = new Scanner(System.in); String next = sc.next(); aClient.sendMsg(next); } }catch (Exception e){ mFlag=false; e.printStackTrace(); } } }.start(); } }