`

java nio过程

 
阅读更多

1、服务端:ServerSocketChannel进行监听,注册SelectionKey.OP_ACCEPT事件,服务器阻塞在selector.select()方法中,等待客户端连接。
2、客户端:SocketChannel创建连接,调用socketChannel.connect(SERVER_ADDRESS)连接服务器(此时服务器之前阻塞在selector.select()往下走,进入selectionKey.isAcceptable()逻辑,通过ServerSocketChannel的accept方法获得客户端SocketChannel,SocketChannel注册 SelectionKey.OP_READ事件,等待客户端输入流,此时又阻塞在selector.select()方法),客户端进入selectionKey.isConnectable(),如果client.isConnectionPending()==true,通过 client.finishConnect()强制连接,然后准备数据,通过client.write(sendbuffer)向服务器发送数据,此时,服务器之前阻塞在selector.select()往下走,进入selectionKey.isReadable()逻辑,通过缓冲区读取客户端输入流,然后调用client.register(selector, SelectionKey.OP_WRITE)注册写客户端流事件,进入selectionKey.isWritable()逻辑,准备写客户端的数据,通过client.write(sendbuffer)方法写给客户端,客户端之前write之后,会进行注册SelectionKey.OP_READ,等待服务器响应,阻塞在selector.select()中,由于这个时候服务器有了返回,就不阻塞了,进入selectionKey.isReadable()逻辑,得到服务器返回,如果需要再次发送数据给服务器,则注册write事件。刚才服务器write给客户端之后,如果想继续收到客户端数据,需要注册client.register(selector, SelectionKey.OP_READ)读事件,等待客户端再一次写入数据,阻塞在selector.select()方法

 

服务端:

package com.rb.socket.nio.server.n;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NIOServer {

	/*标识数字*/
	private int flag = 0;

	/*缓冲区大小*/
	private int BLOCK = 4096;

	/*接受数据缓冲区*/
	private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);

	/*发送数据缓冲区*/
	private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);

	private Selector selector;

	public NIOServer(int port) throws IOException {
		// 打开服务器套接字通道   
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		// 服务器配置为非阻塞   
		serverSocketChannel.configureBlocking(false);
		// 检索与此通道关联的服务器套接字   
		ServerSocket serverSocket = serverSocketChannel.socket();
		// 进行服务的绑定   
		serverSocket.bind(new InetSocketAddress(port));
		// 通过open()方法找到Selector   
		selector = Selector.open();
		// 注册到selector,等待连接   
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("Server Start----:" + port);
	}

	// 监听   
	private void listen() throws IOException {
		while (true) {
			// 选择一组键,并且相应的通道已经打开   
			selector.select();
			// 返回此选择器的已选择键集。   
			Set<SelectionKey> selectionKeys = selector.selectedKeys();
			Iterator<SelectionKey> iterator = selectionKeys.iterator();
			while (iterator.hasNext()) {
				SelectionKey selectionKey = iterator.next();
				iterator.remove();
				handleKey(selectionKey);
			}
		}
	}

	// 处理请求   
	private void handleKey(SelectionKey selectionKey) throws IOException {
		// 接受请求   
		ServerSocketChannel server = null;
		SocketChannel client = null;
		String receiveText;
		String sendText;
		int count = 0;
		// 测试此键的通道是否已准备好接受新的套接字连接。   
		if (selectionKey.isAcceptable()) {
			// 返回为之创建此键的通道。   
			server = (ServerSocketChannel) selectionKey.channel();
			// 接受到此通道套接字的连接。   
			// 此方法返回的套接字通道(如果有)将处于阻塞模式。   
			client = server.accept();
			// 配置为非阻塞   
			client.configureBlocking(false);
			// 注册到selector,等待连接   
			client.register(selector, SelectionKey.OP_READ);
		} else if (selectionKey.isReadable()) {
			// 返回为之创建此键的通道。   
			client = (SocketChannel) selectionKey.channel();
			//将缓冲区清空以备下次读取   
			receivebuffer.clear();
			//读取服务器发送来的数据到缓冲区中   
			count = client.read(receivebuffer);
			if (count > 0) {
				receiveText = new String(receivebuffer.array(), 0, count);
				System.out.println("服务器端接受客户端数据--:" + receiveText);
				client.register(selector, SelectionKey.OP_WRITE);
			}
		} else if (selectionKey.isWritable()) {
			//将缓冲区清空以备下次写入   
			sendbuffer.clear();
			// 返回为之创建此键的通道。   
			client = (SocketChannel) selectionKey.channel();
			sendText = "message from server--" + flag++;
			//向缓冲区中输入数据   
			sendbuffer.put(sendText.getBytes());
			//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位   
			sendbuffer.flip();
			//输出到通道   
			client.write(sendbuffer);
			System.out.println("服务器端向客户端发送数据--:" + sendText);
			client.register(selector, SelectionKey.OP_READ);
		}
	}

	/**  
	 * @param args  
	 * @throws IOException  
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub   
		int port = 8011;
		NIOServer server = new NIOServer(port);
		server.listen();
	}
}

 

客户端:

package com.rb.socket.nio.server.n;
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.util.Iterator;   
import java.util.Set;   
  
public class NIOClient {   
  
    /*标识数字*/  
    private static int flag = 0;   
    /*缓冲区大小*/  
    private static int BLOCK = 4096;   
    /*接受数据缓冲区*/  
    private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);   
    /*发送数据缓冲区*/  
    private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);   
    /*服务器端地址*/  
    private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress(   
            "localhost", 8011);   
  
    public static void main(String[] args) throws IOException {   
        // TODO Auto-generated method stub   
        // 打开socket通道   
        SocketChannel socketChannel = SocketChannel.open();   
        // 设置为非阻塞方式   
        socketChannel.configureBlocking(false);   
        // 打开选择器   
        Selector selector = Selector.open();   
        // 注册连接服务端socket动作   
        socketChannel.register(selector, SelectionKey.OP_CONNECT);   
        // 连接   
        socketChannel.connect(SERVER_ADDRESS);   
        // 分配缓冲区大小内存   
           
        Set<SelectionKey> selectionKeys;   
        Iterator<SelectionKey> iterator;   
        SelectionKey selectionKey;   
        SocketChannel client;   
        String receiveText;   
        String sendText;   
        int count=0;   
  
        while (true) {   
            //选择一组键,其相应的通道已为 I/O 操作准备就绪。   
            //此方法执行处于阻塞模式的选择操作。   
            selector.select();   
            //返回此选择器的已选择键集。   
            selectionKeys = selector.selectedKeys();   
            //System.out.println(selectionKeys.size());   
            iterator = selectionKeys.iterator();   
            while (iterator.hasNext()) {   
                selectionKey = iterator.next();   
                if (selectionKey.isConnectable()) {   
                    System.out.println("client connect");   
                    client = (SocketChannel) selectionKey.channel();   
                    // 判断此通道上是否正在进行连接操作。   
                    // 完成套接字通道的连接过程。   
                    if (client.isConnectionPending()) {   
                        client.finishConnect();   
                        System.out.println("完成连接!");   
                        sendbuffer.clear();   
                        sendbuffer.put("Hello,Server".getBytes());   
                        sendbuffer.flip();   
                        client.write(sendbuffer);   
                    }   
                    client.register(selector, SelectionKey.OP_READ);   
                } else if (selectionKey.isReadable()) {   
                    client = (SocketChannel) selectionKey.channel();   
                    //将缓冲区清空以备下次读取   
                    receivebuffer.clear();   
                    //读取服务器发送来的数据到缓冲区中   
                    count=client.read(receivebuffer);   
                    if(count>0){   
                        receiveText = new String( receivebuffer.array(),0,count);   
                        System.out.println("客户端接受服务器端数据--:"+receiveText);   
                        client.register(selector, SelectionKey.OP_WRITE);   
                    }   
  
                } else if (selectionKey.isWritable()) {   
                    sendbuffer.clear();   
                    client = (SocketChannel) selectionKey.channel();   
                    sendText = "message from client--" + (flag++);   
                    sendbuffer.put(sendText.getBytes());   
                     //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位   
                    sendbuffer.flip();   
                    client.write(sendbuffer);   
                    System.out.println("客户端向服务器端发送数据--:"+sendText);   
                    client.register(selector, SelectionKey.OP_READ);   
                }   
            }   
            selectionKeys.clear();   
        }   
    }   
}  

 

 

分享到:
评论

相关推荐

    java nio 包读取超大数据文件

    ### Java NIO 处理超大数据文件的知识点详解 #### 一、Java NIO简介 Java NIO(New IO)是Java平台上的新输入/输出流API,它提供了与传统IO(即Java IO)不同的数据处理方式。NIO在Java 1.4版本引入,并在后续版本...

    java NIO实例

    整个过程中,NIO通过非阻塞I/O避免了线程阻塞,提高了系统资源的利用率,尤其在处理大量并发连接时,其优势更为明显。 以上就是Java NIO的基本概念和工作流程,以及结合文件名推测的`NIOServer.java`和`NIOClient....

    java nio 实现socket

    ### Java NIO 实现Socket通信详解 #### 一、NIO与传统IO的区别及优势 在探讨如何使用Java NIO实现Socket通信之前,我们需要先理解NIO(Non-blocking I/O,非阻塞I/O)与传统阻塞I/O之间的区别。 **传统阻塞I/O...

    基于java NIO的socket通信demo

    在这个“基于java NIO的socket通信demo”中,我们将探讨如何使用NIO进行服务器和客户端的Socket通信,并解决通信过程中的字符集乱码问题。 首先,我们来看`NioServer.java`。这个文件中包含了一个基于NIO的服务器端...

    java nio示例代码

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一个新特性,旨在提供一...在学习过程中,你可以逐步深入,从基础的Buffer操作到复杂的Selector机制,掌握Java NIO的精髓。

    java nio im(server+client)

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,相对于传统的BIO( Blocking I/O)模型,NIO在处理高并发、大数据量的网络应用时表现出更高的效率和...

    Java NIO 英文文字版

    总之,《Java NIO》这本书详细地介绍了Java NIO的各种新特性,提供了一套完整的解决方案,帮助开发者在实际开发过程中更高效地运用这些特性,从而编写出更优的高性能Java应用程序。对于Java程序员而言,掌握这些知识...

    Java NIO系列教程(一) Java NIO 概述

    ### Java NIO 系列教程(一):Java NIO 概述 #### 一、引言 Java NIO(New IO)是Java SE 1.4版本引入的一个新的I/O处理框架,它...在未来的学习过程中,继续深入理解这些概念将有助于您更好地掌握Java NIO技术。

    NIO与零拷贝_javanio_nio和零拷贝_

    Java NIO(New IO)是Java 1.4引入的一个新特性,它是对传统IO模型的重大改进,提供了更高效的数据处理方式。NIO的核心概念包括通道(Channels)、缓冲区(Buffers)和选择器(Selectors)。它允许多个输入/输出操作...

    Java NIO详解及源码下载

    在Java的传统IO模型中,一切操作都是基于流(Stream)的,无论是输入流还是输出流,它们都是顺序读写的,且在读写过程中会阻塞线程,直到读写完成。例如,`FileInputStream`和`FileOutputStream`就是典型的阻塞IO流...

    JAVA nio的一个简单的例子

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种I/O模型,旨在提供一种更高效、更具弹性的I/O处理方式。相比于传统的BIO( Blocking I/O)模型,NIO在处理高并发和大...

    Java NIO实现多个客户端之间的消息互发,客户端与服务器完整代码

    Java NIO(Non-blocking Input/Output)是一种在Java中处理I/O操作的新方式,相比于传统的BIO(Blocking I/O),NIO提供了更高效的数据传输能力,尤其适合于高并发、低延迟的网络应用,如聊天服务器。在这个场景下,...

    Java NIO原理 图文分析及代码实现

    ### Java NIO原理 图文分析及代码实现 #### 前言 在深入探讨Java NIO之前,我们先简要回顾一下NIO的概念及其引入的原因。随着互联网的发展,越来越多的应用程序需要处理高并发的网络连接请求。传统的阻塞I/O模型在...

    Java NIO与IO性能对比分析.pdf

    Java IO模型是一种阻塞型I/O模型,在数据的读写过程中,如果线程在等待数据,将会一直被挂起。当数据准备就绪后,线程会从阻塞状态恢复并继续执行。这种模型在处理小量级并发连接时表现尚可,但在面对高并发场景时,...

    Java NIO通信框架在电信领域的实践

    本文将着重探讨电信业务应用软件的发展历程和技术变迁,特别是Java NIO框架在这一过程中所扮演的重要角色。 **1.2 华为电信软件的技术演进史** ##### 1.2.1 C和C++主导的第一代架构 在2005年以前,华为电信软件的...

    自己写的Java NIO 同步不阻塞IO操作

    Java NIO(New Input/Output)是Java标准库提供的一种I/O模型,它与传统的 Blocking I/O(阻塞式I/O)有所不同。在传统的IO模型中,读写操作会阻塞线程,直到数据准备好或者写入完成。而NIO则引入了非阻塞模式,使得...

    java io 与java nio区别

    ### Java IO 与 Java NIO 的区别 在深入探讨Java IO与Java NIO之间的区别之前,我们先简单回顾一下这两种I/O模型的基本概念。 #### 1. Java IO(Blocking IO) Java IO,也称为传统的阻塞式IO或同步阻塞式IO,是...

    Java NIO——Selector机制解析三(源码分析)

    Java NIO,全称为Non-blocking Input/Output,是Java在1.4版本引入的一个新特性,旨在提供一种更高效、更灵活的I/O操作方式。相比于传统的BIO(Blocking I/O),NIO允许我们以非阻塞的方式读写数据,提高了系统资源...

    java nio 尚硅谷 12讲 new

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新技术。尚硅谷的12讲Java NIO课程,旨在深入浅出地讲解这一重要概念,帮助开发者提升程序的性能和效率。...

Global site tag (gtag.js) - Google Analytics