java使用selector NIO socket

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012400305/article/details/78324621

使用NIO的socket时 一直测试状态是 服务端返回的信息所有客户端都能收到  一直很郁闷  后来发现 是服务端代码的问题 在接受到一个channel时 我的代码里是拿select又做了一次遍历 对所有的客户端进行返回 


下面给一个代码示例 

服务端

public class HansServer {
    // 用于检测所有Channel状态的Selector
    private Selector selector = null;

    public void init() throws IOException {
        selector = Selector.open();
        // 通过open方法来打开一个未绑定的ServerSocketChannel实例
        ServerSocketChannel server = ServerSocketChannel.open();
        InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000);
        // 将该ServerSocketChannel绑定到指定IP地址
        server.socket().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上的已选择Key集中删除正在处理的SelectionKey
                selector.selectedKeys().remove(sk);
                // 如果sk对应的通道包含客户端的连接请求
                if (sk.isAcceptable()) {
                    // 调用accept方法接受连接,产生服务器端对应的SocketChannel
                	ServerSocketChannel ssc =(ServerSocketChannel) sk.channel();
                    SocketChannel sc = ssc.accept();
//                    SocketChannel sc = server.accept();
                    // 设置采用非阻塞模式
                    sc.configureBlocking(false);
                    // 将该SocketChannel也注册到selector
                    sc.register(selector, SelectionKey.OP_READ);
                }
                // 如果sk对应的通道有数据需要读取
                if (sk.isReadable()) {
                    // 获取该SelectionKey对应的Channel,该Channel中有可读的数据
                    SocketChannel sc = (SocketChannel) sk.channel();
                    // 定义准备执行读取数据的ByteBuffer
                    ByteBuffer buff = ByteBuffer.allocate(1024);
                    String content = "";
                    byte[] receData =new byte[0];
                    byte[] temp =new byte[1];
                    // 开始读取数据
                    try {
     					while(sc.read(buff)> 0){
     						sc.read(buff);
     						buff.flip();
                        	int limit = buff.limit();
     						temp =new byte[limit];
                     		buff.get(temp,0,limit);
                     		byte[] and = new byte[temp.length+receData.length];
                     		System.arraycopy(receData, 0, and, 0, receData.length);
                     		System.arraycopy(temp, 0, and, receData.length, temp.length);
                     		receData=and;
                     		 
                     		buff.clear();
                     	}
     					content += StandardCharsets.UTF_8.decode(ByteBuffer.wrap(receData));
                        if(sc.read(buff)  == -1){
                            System.out.println("断开..." 
                                    + sc.socket().getRemoteSocketAddress());            
                            sk.cancel();
                            if (sk.channel() != null) {
                                sk.channel().close();
                                sc.close();
                            }
                        }else{
                        	// 打印从该sk对应的Channel里读取到的数据
                        	System.out.println("=====接收到客户端数据:" + content);
                        	if (content.length() > 0) {
                            	sc.write(StandardCharsets.UTF_8.encode("服务端发送:"+content+"---已收到!!!"));
                            }
                        }
                    }
                    // 如果捕捉到该sk对应的Channel出现了异常,即表明该Channel
                    // 对应的Client出现了问题,所以从Selector中取消sk的注册
                    catch (IOException ex) {
                        // 从Selector中删除指定的SelectionKey
                        sk.cancel();
                        if (sk.channel() != null) {
                            sk.channel().close();
                            sc.close();
                        }
                    }
                    // 如果content的长度大于0,即聊天信息不为空
//                    if (content.length() > 0) {
////                        // 遍历该selector里注册的所有SelectKey
////                        for (SelectionKey key : selector.keys()) {
////                            // 获取该key对应的Channel
////                            Channel targetChannel = key.channel();
////                            // 如果该channel是SocketChannel对象
////                            if (targetChannel instanceof SocketChannel) {
////                                // 将读到的内容写入该Channel中
////                                SocketChannel dest = (SocketChannel) targetChannel;
////                                dest.write(StandardCharsets.UTF_8.encode("服务端发送:"+content+"---已收到!!!"));
////                            }
////                        }
//                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new HansServer().init();
    }
}

客户端


public class HansClient {
    // 定义检测SocketChannel的Selector对象
    private Selector selector = null;
    // 客户端SocketChannel
    private SocketChannel sc = null;

    public void init() throws IOException {
        selector = Selector.open();
        InetSocketAddress isa = new InetSocketAddress("127.0.0.1", 30000);
        // 调用open静态方法创建连接到指定主机的SocketChannel
        sc = SocketChannel.open(isa);
        // 设置该sc以非阻塞方式工作
        sc.configureBlocking(false);
        // 将SocketChannel对象注册到指定Selector
        sc.register(selector, SelectionKey.OP_READ);
        // 创建键盘输入流
//        Scanner scan = new Scanner(System.in);
//        while (scan.hasNextLine()) {
        	// 读取键盘输入
        	int SendRes = new HansClient().S_SendData(sc);
        	System.out.println("发送数据返回值"+SendRes);
//        }
        // 启动读取服务器端数据的线程
//        new ClientThread().start();
        new HansClient().S_ResData(selector);
        	
        	 sc.close();
        	 selector.close();
    }

    public int S_SendData(SocketChannel sc ){
    	int sendRes =0;
    	String line = "6*7";
    	// 将键盘输入的内容输出到SocketChannel中
    	try {
			 sendRes = sc.write(StandardCharsets.UTF_8.encode(line));
		} catch (IOException e) {
			e.printStackTrace();
		}
    	return sendRes;
    }
    public void S_ResData(Selector sele){
    	 try {
             while (sele.select() > 0) {
                 // 遍历每个有可用IO操作Channel对应的SelectionKey
                 for (SelectionKey sk : sele.selectedKeys()) {
                     // 删除正在处理的SelectionKey
                	 sele.selectedKeys().remove(sk);
                     // 如果该SelectionKey对应的Channel中有可读的数据
                     if (sk.isReadable()) {
                         // 使用NIO读取Channel中的数据
                         SocketChannel sc = (SocketChannel) sk.channel();
                         ByteBuffer buff = ByteBuffer.allocate(5);
                         String content = "";
                         byte[] receData =new byte[0];
                     	byte[] temp =new byte[1];
     					while(sc.read(buff)> 0){
     						sc.read(buff);
                     		temp = buff.array();
                     		byte[] and = new byte[temp.length+receData.length];
                     		System.arraycopy(receData, 0, and, 0, receData.length);
                     		System.arraycopy(temp, 0, and, receData.length, temp.length);
                     		receData=and;
                     		 buff.flip();
                     		 buff.clear();
                     	}
     					content += StandardCharsets.UTF_8.decode(ByteBuffer.wrap(receData));
                         // 打印输出读取的内容
                         System.out.println("聊天信息:" + content);
                        break;
                     }
                 }
                 break;
             }
         } catch (IOException ex) {
             ex.printStackTrace();
         }
    }
 public static void main(String[] args) throws IOException {
        new HansClient().init();
    }
}


猜你喜欢

转载自blog.csdn.net/u012400305/article/details/78324621