java nio实现非阻塞Socket通信实例
package com.java.xiong.Net17; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; public class NServer { // 用于检测所有的Channel状态的selector private Selector selector = null; static final int PORT = 30000; // 定义实现编码、解码的字符串集对象 private Charset charse = Charset.forName("GBK"); public void init() throws IOException { selector = Selector.open(); // 通过open方法来打开一个未绑定的ServerSocketChannel是咧 ServerSocketChannel server = ServerSocketChannel.open(); InetSocketAddress isa = new InetSocketAddress("127.0.0.1", PORT); // 将该ServerSocketChannel绑定到指定的IP地址 server.bind(isa); // 设置serverSocket已非阻塞方式工作 server.configureBlocking(false); // 将server注册到指定的selector对象 server.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { // 一次处理selector上的每个选择的SelectionKey for (SelectionKey sk : selector.selectedKeys()) { // 从selector上已选择的Kye集中删除正在处理的SelectionKey selector.selectedKeys().remove(sk); // 如果sk对应的Channel包含客户端的连接请求 if (sk.isAcceptable()) { // 调用accept方法接收连接,产生服务器段的SocketChennal SocketChannel sc = server.accept(); // 设置采用非阻塞模式 sc.configureBlocking(false); // 将该SocketChannel注册到selector sc.register(selector, SelectionKey.OP_READ); } // 如果sk对应的Channel有数据需要读取 if (sk.isReadable()) { // 获取该SelectionKey对银行的Channel,该Channel中有刻度的数据 SocketChannel sc = (SocketChannel) sk.channel(); // 定义备注执行读取数据源的ByteBuffer ByteBuffer buff = ByteBuffer.allocate(1024); String content = ""; // 开始读取数据 try { while (sc.read(buff) > 0) { buff.flip(); content += charse.decode(buff); } System.out.println("读取的数据:" + content); // 将sk对应的Channel设置成准备下一次读取 sk.interestOps(SelectionKey.OP_READ); } // 如果捕获到该sk对银行的Channel出现了异常,表明 // Channel对应的Client出现了问题,所以从Selector中取消 catch (IOException io) { // 从Selector中删除指定的SelectionKey sk.cancel(); if (sk.channel() != null) { sk.channel().close(); } } // 如果content的长度大于0,则连天信息不为空 if (content.length() > 0) { // 遍历selector里注册的所有SelectionKey for (SelectionKey key : selector.keys()) { // 获取该key对应的Channel Channel targerChannel = key.channel(); // 如果该Channel是SocketChannel对象 if (targerChannel instanceof SocketChannel) { // 将读取到的内容写入该Channel中 SocketChannel dest = (SocketChannel) targerChannel; dest.write(charse.encode(content)); } } } } } } } public static void main(String [] args) throws IOException{ new NServer().init(); } }
package com.java.xiong.Net17; import java.io.IOException; 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.nio.charset.Charset; import java.util.Scanner; public class NClient { //定义检测Sockethannel的Selector对象 private Selector selector=null; static final int PORT=30000; //定义处理编码的字符集 private Charset charset=Charset.forName("GBK"); //客户端SocketChannel private SocketChannel sc=null; public void init() throws IOException{ selector=Selector.open(); InetSocketAddress isa=new InetSocketAddress("127.0.0.1", PORT); //调用open的静态方法创建连接指定的主机的SocketChannel sc=SocketChannel.open(isa); //设置该sc已非阻塞的方式工作 sc.configureBlocking(false); //将SocketChannel对象注册到指定的Selector sc.register(selector, SelectionKey.OP_READ); //启动读取服务器数据端的线程 new ClientThread().start(); //创建键盘输入流 Scanner scan=new Scanner(System.in); while(scan.hasNextLine()){ //读取键盘的输入 String line=scan.nextLine(); //将键盘的内容输出到SocketChanenel中 sc.write(charset.encode(line)); } } //定义读取服务器端的数据的线程 private class ClientThread extends Thread{ @Override public void run() { try{ while(selector.select()>0){ //遍历每个有可能的IO操作的Channel对银行的SelectionKey for(SelectionKey sk:selector.selectedKeys()){ //删除正在处理的SelectionKey selector.selectedKeys().remove(sk); //如果该SelectionKey对应的Channel中有可读的数据 if(sk.isReadable()){ //使用NIO读取Channel中的数据 SocketChannel sc=(SocketChannel)sk.channel(); String content=""; ByteBuffer bff=ByteBuffer.allocate(1024); while(sc.read(bff)>0){ sc.read(bff); bff.flip(); content+=charset.decode(bff); } //打印读取的内容 System.out.println("聊天信息:"+content); sk.interestOps(SelectionKey.OP_READ); } } } }catch(IOException io){ io.printStackTrace(); } } } public static void main(String [] args) throws IOException{ new NClient().init(); } }
补充:软件开发 , Java ,