NIO基本原理和实现通信-1

一.NIO中的缓冲区Buffer的内部原理

  缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如果我们使用get()方法从缓冲区获取数据或者使用put()方法把数据写入缓冲区,都会引起缓冲区状态的变化。

在缓冲区中,最重要的属性有下面三个:positionlimitcapacity。其中postion主要是定位接下来要操作元素的角标,limit定位最后一个元素的位置,往往元素是由position和limit共同决定,调用flip()方法的时候就是把当前position赋值给limit,并把position设置为0。具体细节在此不赘述。

二.实现服务端和客户端通信(主要用到选择器selector绑定事件)

服务端代码如下:

 

package cn.test.nio;
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;
import java.io.IOException;
public class NIOServer {

    private Selector selector;
    private ByteBuffer buff = ByteBuffer.allocate(1024);
    public void init(int port) throws IOException{
        selector = Selector.open();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        
        //通道对应的ServerSocket绑定到对应的端口上
        ServerSocket  serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));
        
        //把通道绑定到通道管理器上,服务端接受客户端的连接事件时候触发
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }
    public void listen() throws IOException {
        System.out.println("服务端启动成功。。");
        
        //循环监听选择器上是否有对应事件
        while (true) {
            selector.select();
            Set<SelectionKey> selectedKyes = selector.selectedKeys();
            Iterator<SelectionKey> it = selectedKyes.iterator();
            while(it.hasNext()){
                SelectionKey key = (SelectionKey)it.next();
                it.remove();
                /**
                 * 当遇到客户端连接事件后,开启读事件。当捕捉到读事件后,把信息写回客户端
                 */
                if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){
                    ServerSocketChannel server  = (ServerSocketChannel) key.channel();
                    SocketChannel  channel = server.accept();
                    channel.configureBlocking(false);
                    channel.register(this.selector, SelectionKey.OP_READ);
                }else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ){//把信息写回客户端
                    SocketChannel channel =  (SocketChannel) key.channel();
                    while(true){
                        /**
                         * 重置buff,postion=0;limit=capacity
                         */
                        buff.clear();
                        int r = channel.read(buff);
                        if(r<=0){
                            break;
                        }
                        /**1.把limit设置为当前position,把position位置置0
                         * 2.把数据写入通道前,对数据进行定位,取postion->limit之间的数据
                         */
                        buff.flip();
                        channel.write(buff);
                    }
                    byte[] data = buff.array();
                    System.out.println("服务端接受并返回信息:::"+new String(data).trim());
                }
            }
        }
    }
    public static void main(String[] args) throws IOException {
        NIOServer n = new NIOServer();
        n.init(8002);
        n.listen();
    }
}

 

 

 

客户端代码如下:

 

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 Selector selector;
    public void init(String ip,int port) throws IOException{
        selector = Selector.open();
        SocketChannel channel = SocketChannel.open();
        
        channel.configureBlocking(false);
        channel.connect(new InetSocketAddress(ip, port));
        channel.register(selector,SelectionKey.OP_CONNECT);
    }
    public void listen() throws IOException {

        //循环监听选择器上是否有对应事件
        while (true) {
            selector.select();
            Set<SelectionKey> selectedKyes = selector.selectedKeys();
            Iterator<SelectionKey> it = selectedKyes.iterator();
            while(it.hasNext()){
                SelectionKey key = it.next();
                it.remove();
                //开启连接服务端的兴趣事件
                if((key.readyOps()&SelectionKey.OP_CONNECT)==SelectionKey.OP_CONNECT){
                    SocketChannel channel =  (SocketChannel) key.channel();
                    if(channel.isConnectionPending()){
                        channel.finishConnect();
                    }
                    channel.configureBlocking(false);
            //注册写事件 channel.register(
this.selector, SelectionKey.OP_WRITE); }else if((key.readyOps()&SelectionKey.OP_WRITE)==SelectionKey.OP_WRITE){ SocketChannel channel = (SocketChannel) key.channel(); String msg = new String("Hello! nice to meet u"); channel.write(ByteBuffer.wrap(msg.getBytes()));
            //注册读事件 channel.register(
this.selector, SelectionKey.OP_READ); System.out.println("客户端发送信息::::"+msg); }else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ){ SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer buff = ByteBuffer.allocate(1024); while(true){ buff.clear(); int r = channel.read(buff); if(r<=0){ break; } } byte[] data = buff.array(); System.out.println("客户端收到信息::"+new String(data).trim()); } } } } public static void main(String[] args) throws IOException { NIOClient n = new NIOClient(); n.init("localhost", 8002); n.listen(); } }

 

posted on 2017-11-08 20:39  时人已不觉  阅读(207)  评论(0编辑  收藏  举报