`

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过程中总结的核心概念,里面包含了基本的知识点,详细知识点也可以查看我的博客:pcwl_java里的Java NIO篇

    Java NIO Buffer过程详解

    主要介绍了Java NIO Buffer过程详解,缓冲区在java nio中负责数据的存储。缓冲区就是数组。用于存储不同数据类型的数据。,需要的朋友可以参考下

    java IO NIO AIO.xmind

    涉及到java io, nio, aio相关知识点,学习过程中的一些总结,持续更新中,xmind 格式

    JAVA NIO学习笔记.docx

    IO 是主存和外部设备 ( 硬盘、终端和网络等 ) 拷贝数据的过程。 IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成。 所有语言运行时系统提供执行 I/O 较高级别的工具。 (c 的 printf scanf,java 的面向对象...

    mina:Java Nio Apache Mina Java Nio

    在以往的java的IO操作的过程中都是面向字节流操作,并且读写操作是单向的操作,而在java1.4添加nio包新的io不再像以前的标准的io操作一样面向流操作,而NIO是面向块的操作,并且有通道、缓冲区等重要的部分组成。...

    NIO(java)原生实现,没有用任何框架

    java nio 的服务端完整实现,应该可以商用,但我没有真实投入商用,就是一个学习过程的总结,代码应该算是很完整,对学习nio应该是很有帮助,而且没有使用任何框架,但借鉴了很多框架的核心代码。

    使用java NIO及高速缓冲区写入文件过程解析

    主要介绍了使用java NIO及高速缓冲区写入文件过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    Java NIO缓冲

    想要了解更多关于NIO通道的信息, 请阅读上一篇教程Java NIO通道。  NIO缓冲区特征  · Java NIO的基本组成模块是缓冲区。  · 缓冲区提供一个固定大小的容器来读取数据。  · 每个缓冲区都是可读的,但只有...

    Java高并发实战_java高并发_高并发_

    第5章介绍了并行程序设计中常见的 些设计模式以及 些典型的并行算法和使用方法,其中包括重要的JavaNIO和AIO的介绍。第6章介绍了 Java 8中为并行计算做的新的改进, 包括并行流、 CompletableFuture、 StampedLock...

    从NIO到Netty,编程实战出租车905协议-08172347.pdf

    第2章,介绍在Socket编程过程中一些基础知识,让大家建立起对这块知识内容的一个整体轮廓; 第3章,结合905.4-2014协议的基本内容,动手实现NIO长连接服务端的实现,以及协议内容的设计和实现思路; 第4章,实现长...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题31.jdbc调用存储过程.mp4 │ Java面试题32.简单说一下你对jdbc的理解.mp4 │ Java面试题33.写一个jdbc的访问oracle的列子.mp4 │ Java面试题34.jdbc中preparedStatement比Statement的好处.mp4 │ Java...

    Java后端面试问题整理.docx

    • 熟悉常用IO模型(BIO、NIO、AIO),熟悉JVM类加载过程与机制 • 了解JVM性能监控以及调优,会使用jps、jstack、jmap、jstat、jhat,了解内存泄露排查具体方法 • Java基础 • 熟练的使用Java语言进行面向对象程序...

    nioserver.zip

    在 [接受连接->读->业务处理->写 ->关闭连接 ]这个 过程中,触发器将触发相应事件,由事件处理器对相应事件分别响应,完成服务器端的业务处理。 下面我们就来详细看一下这个模型的各个组成部分。

    JAVA上百实例源码以及开源项目

     Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件,一步步的实现过程请下载本实例的Java源码,代码中包括丰富的注释,对学习有帮助。 Java实现的FTP连接与数据浏览程序 1个...

    JAVA上百实例源码以及开源项目源代码

     Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件,一步步的实现过程请下载本实例的Java源码,代码中包括丰富的注释,对学习有帮助。 Java实现的FTP连接与数据浏览程序 1个...

    2Java性能优化二.zip

    比方相同是文件读写的实现,使用Stream方式和使用JAVA NIO的方式,其系能可能又会是还有一个数量级. 因此,尽管与设计优化相比,笔者将代码优化成为在微观层面上的优化,但它却是对系统性能产生最直接影响的优化方法.

    Java开发基于多线程和NIO实现聊天室源码+项目说明(含服务端+客户端).zip

    Java开发基于多线程和NIO实现聊天室源码+项目说明(含服务端+客户端).zip 涉及到的技术点 - 线程池ThreadPoolExecutor - 阻塞队列BlockingQueue,生产者消费者模式 - Selector - Channel - ByteBuffer - ...

    JAVA高并发高性能高可用高扩展架构视频教程

    JAVANIO原理详解 高并发数据库(Mysql数据库性能优化) 软件质量管控 企业常用框架springMVC基于注解+xml配置方式实现链接 WEB服务器优化之Tomcat7性能调优 JVM概述 Java开发技术之(项目工程的日志管理) 数据库连接池...

    Java思维导图xmind文件+导出图片

    大型分布式架构演进过程 分布式架构设计 主流架构模型-SOA架构和微服务架构 领域驱动设计及业务驱动规划 分布式架构的基本理论CAP、BASE以及其应用 什么是分布式架构下的高可用设计 构架高性能的分布式架构 ...

    java 面试题 java基础部分

    Java面试基础部分,适用于Java开发,应对面试题的基本整理 Java基础 集合 多线程基础 CAS理论 http请求过程 类加载器 NIO理解与适用

Global site tag (gtag.js) - Google Analytics