java NIO相关知识点 (1)

1 篇文章 0 订阅

目录

 

NIO中的几个重要概念

 1 通道 Channel

2 缓冲区

3 选择器


NIO中的几个重要概念

通道,缓冲区,选择器

 1 通道 Channel

类似于流,但是通道是双向的,而流是单向的

通道支持异步读写数据,流只能同步读写

通道的数据总是要先读到一个buffer或者从一个buffer写入.

常用的通道有4种

FileChannel 从文件中读写

DatagramChannel   从UDP中读写网络中的数据

SocketChannel  能通过TCP读写网络中的数据

ServerSocketChannel   可以监听新进来的TCP连接

 

 

2 缓冲区 (buffer)

buffer主要负责与通道进行交互,本质上是一块可以存储数据的内存,被封装buffer对象,这块内存被封装成NIO Buffer 对象,并提供了一组方法,用来方便的访问zhek这块内存. Buffer有7个子类,用来存储不同的数据类型的数据,分别是:

ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer ,都是针对基本数据类型,没有针对布尔型的

缓冲区有4个最主要的属性: capacity ,limit,position.mark

capacity缓冲区可容纳的最大数据量,在创建缓冲区是已确定,不能更改
limit限制,limit之后的内容无法进行读写操作
position指的是下一个进行读/写的索引
mark标记,mark()设置mark=position,再调用reset() 恢复到标记位置,使得position=mark

一般从buffer中读写数据需要经历以下步骤

1 将数据写入缓冲区

2 调用flip()   ,flip的作用是对缓冲区中的数据部分进行操作

附上flip()的源代码  

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

3 从缓冲区中拿到数据

4 调用clear()  clear的作用是把可以把当前的缓冲区当做一个新的缓冲区来使用

clear()源代码

  public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

 

3 选择器(selector)

Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。 
仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。selector在使用时通道必须处于非阻塞状态,所以不能与FileChannel一起使用,因为fileChannel不能切换到非阻塞状态,

 

实例1 缓冲区的使用(buffer)

public static void byteBufferTest() {
        
//        为缓冲区分配空间
        ByteBuffer buffer =ByteBuffer.allocate(30);

        buffer.put("hero_孙".getBytes());
//        System.out.println(buffer);//java.nio.HeapByteBuffer[pos=8 lim=30 cap=30]
        buffer.flip();
//        System.out.println(buffer); //java.nio.HeapByteBuffer[pos=0 lim=8 cap=30]
        System.out.println(new String(buffer.array(),0,buffer.limit()));
        buffer.clear();
//    System.out.println(buffer); //java.nio.HeapByteBuffer[pos=0 lim=30 cap=30]
    
    }

 

实例2 FileChannel的使用(文件读写)

public static void  NIOFileReadAndWrite(String inName , String outName) throws Exception{
        
        FileInputStream fis=new FileInputStream(new File(inName));
//        创建通道
            FileChannel fisChannel=fis.getChannel();
            
        FileOutputStream fos=new FileOutputStream(new File(outName));
//        创建通道
        FileChannel foschannel=fos.getChannel();
//        创建缓冲区
        ByteBuffer buffer =ByteBuffer.allocate(1024);
    
        while( fisChannel.read(buffer)!=-1) {
            buffer.flip();
             while(foschannel.write(buffer)!=0) {
                 
             }
             buffer.clear();
        }
        
        if(fis!=null) {
            fis.close();
        }
        if(fos!=null) {
            fos.close();
        }
        if(fisChannel!=null) {
            fisChannel.close();
        }
        if(foschannel!=null) {
            foschannel.close();
        }
    }

 

实例3 客户端,服务器的使用(TCP)

服务器代码

package com.shj.nio;

import java.net.InetSocketAddress;
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.Date;
import java.util.Iterator;

/**
 * 服务端
 *@Description:
 *@author shj
 *@ClassName:     NIOServer.java
 *@Date           2018年7月19日 上午10:50:57 
 *
 */
public class NIOServer {

    public static void main(String[] args)  throws Exception{

//        开放通道
        ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
         serverSocketChannel.socket().setReuseAddress(true);
//        绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(888));
        
//        设置非阻塞
        serverSocketChannel.configureBlocking(false);
//        选择器
        Selector selector =Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器等待连接...");
        while(true) {
            
            if(selector.select()==0) {
                continue;
            }
        
            Iterator<SelectionKey> ite=selector.selectedKeys().iterator();
            
            while(ite.hasNext()) {
                SelectionKey selectionKey =ite.next();
                
                   //如果满足Acceptable条件,则必定是一个ServerSocketChannel
                if(selectionKey.isAcceptable()){
                    ServerSocketChannel sscTemp = (ServerSocketChannel) selectionKey.channel();
                    //得到一个连接好的SocketChannel,并把它注册到Selector上,兴趣操作为READ
                    SocketChannel socketChannel = sscTemp.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);

                }
                
                //如果满足Readable条件,则必定是一个SocketChannel
                if(selectionKey.isReadable()) {
//                获取到通道
                    SocketChannel sockerChannel=(SocketChannel) selectionKey.channel();
                    if(sockerChannel!=null) {
                        System.out.println("已有客户端连接上来");
                        ByteBuffer buffer=ByteBuffer.allocate(100);
                        
                        while(sockerChannel.read(buffer)!=-1) {
//                            
                            buffer.flip();
                            System.out.println("服务器接收到数据-->"+new String(buffer.array(),0,buffer.limit()));
                            buffer.clear();
                            Thread.sleep(1000);
//                            向客户端回复内容
                            buffer.put((new Date()+"服务器").getBytes());
                            
                            buffer.flip();
                            sockerChannel.write(buffer);
                            buffer.clear();
                        }
                        
                    }
                    
                    
                }
                
                
                ite.remove();
            }
            
        }
    
    
    

    }

}
 

客户端代码

package com.shj.nio;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
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.Date;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

/**
 * 客户端
 *@Description:
 *@author shj
 *@ClassName:     NIOClient.java
 *@Date           2018年7月19日 上午10:51:12 
 *
 */
public class NIOClient {

    
    public static void main(String[] args) throws Exception{
        
        SocketChannel socketChannel =SocketChannel.open();
//        设置非阻塞
        socketChannel.configureBlocking(false);
//        请求连接
        socketChannel.connect(new InetSocketAddress("127.0.0.1",888));
        
          while (!socketChannel.finishConnect()) {
              TimeUnit.MILLISECONDS.sleep(100);
          }
        
          while(true) {
              ByteBuffer buffer=ByteBuffer.allocate(100);
              System.out.println("已连接到服务器");
              
              while(socketChannel.read(buffer)!=-1) {
                  buffer.flip();
                  System.out.println("客户端收到的信息-->"+new String(buffer.array(),0,buffer.limit()));
                  buffer.clear();
                  
                  Thread.sleep(1000);                  
//                  回复数据
                  buffer.put((new Date()+"客户端1").getBytes());
                  buffer.flip();
                  socketChannel.write(buffer);
                  buffer.clear();
                  
              }
              
          }
        
    }
}
 

 



 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hero_孙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值