Java NIO(7) - 非阻塞式网络通信应用

104 阅读2分钟

4.5 SocketChannel

Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。

操作步骤:

  • 打开 SocketChannel
  • 读写数据
  • 关闭 SocketChannel 1. 客户端
    @Test
    public void client() {
        SocketChannel socketChannel = null;
        try {
            //1.获取通道
            socketChannel = 
                    SocketChannel.open(new InetSocketAddress(6666));

            //2.切换非阻塞模式
            socketChannel.configureBlocking(false);

            //3.分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);

            //4.发送数据给服务器
            Scanner scanner = new Scanner(System.in);

            while (scanner.hasNext()) {
                String str = scanner.next();
                buf.put((new Date().toString() + "\n" + str).getBytes());
                buf.flip();
                socketChannel.write(buf);
                buf.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socketChannel != null) {
                try {
                    socketChannel.close();
                } catch (IOException ie) {
                    ie.printStackTrace();

                }
            }
        }
    }
 

4.6 ServerSocketChannel

Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道,就像标准IO中的ServerSocket一样

    @Test
    public void service() {
        ServerSocketChannel socketChannel = null;
        SocketChannel sc = null;
        try {
            //1.获取通道
            socketChannel = ServerSocketChannel.open();

            //2.切换非阻塞模式
            socketChannel.configureBlocking(false);

            //3.绑定连接
            socketChannel.bind(new InetSocketAddress(6666));

            //4. 获取选择器
            Selector selector = Selector.open();

            //5.将通道注册到选择器上, 并且指定"监听接受事件"
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);

            //6.轮询式获取选择器上已经"准备就绪"的事件
            while (selector.select() > 0) {

                //7.获取当前选择器中所有注册的"选择键(已就绪的监听事件)"
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();

                while (it.hasNext()) {
                    //8. 获取准备"就绪"的是事件
                    SelectionKey sk = it.next();

                    //9. 判断具体是什么事件就绪
                    //接受事件是否就绪
                    if (sk.isAcceptable()) {
                        //10. 若"接受就绪", 获取客户端连接
                        sc = socketChannel.accept();

                        //11. 切换非阻塞模式
                        sc.configureBlocking(false);

                        //12. 将通道注册到选择器上
                        sc.register(selector, SelectionKey.OP_READ);
                    } else if (sk.isReadable()) {
                        //13. 获取当前选择器上"读就绪"状态的通道
                        sc = (SocketChannel) sk.channel();

                        //14.读取
                        ByteBuffer buf = ByteBuffer.allocate(1024);

                        int len = 0;
                        while ((len = sc.read(buf)) > 0) {
                            buf.flip();
                            System.out.println(new String(buf.array(), 0, len));
                            buf.clear();
                        }
                    }
                }
                it.remove();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socketChannel != null) {
                try {
                    socketChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

4.7 DatagramChannel

Java NIO中的DatagramChannel是一个能收发UDP包的通道。 操作步骤:

  • 打开 DatagramChannel
  • 接收/发送数据
	
	@Test
	public void send() throws IOException{
		DatagramChannel dc = DatagramChannel.open();
		
		dc.configureBlocking(false);
		
		ByteBuffer buf = ByteBuffer.allocate(1024);
		
		Scanner scan = new Scanner(System.in);
		
		while(scan.hasNext()){
			String str = scan.next();
			buf.put((new Date().toString() + ":\n" + str).getBytes());
			buf.flip();
			dc.send(buf, new InetSocketAddress("127.0.0.1", 9898));
			buf.clear();
		}
		
		dc.close();
	}
	
	@Test
	public void receive() throws IOException{
		DatagramChannel dc = DatagramChannel.open();
		
		dc.configureBlocking(false);
		
		dc.bind(new InetSocketAddress(9898));
		
		Selector selector = Selector.open();
		
		dc.register(selector, SelectionKey.OP_READ);
		
		while(selector.select() > 0){
			Iterator<SelectionKey> it = selector.selectedKeys().iterator();
			
			while(it.hasNext()){
				SelectionKey sk = it.next();
				
				if(sk.isReadable()){
					ByteBuffer buf = ByteBuffer.allocate(1024);
					
					dc.receive(buf);
					buf.flip();
					System.out.println(new String(buf.array(), 0, buf.limit()));
					buf.clear();
				}
			}
			
			it.remove();
		}
	}