02_NIO简单实例

【一个用NIO实现的客户端向服务端单向通信的例子】

【服务端程序】

package com.nio.test;

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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * Created by cuixinjie on 2018/5/30.
 */
public class Server implements Runnable{

    //1.多路复用器(管理所有的Channel)
    private Selector selector;
    //2.建立缓冲区
    private ByteBuffer readBuffer = ByteBuffer.allocate(1024);

    public Server(int port){
        try {
            //1.打开多路复用器
            this.selector = Selector.open();
            //2.打开服务端通道Channel
            ServerSocketChannel ssc = ServerSocketChannel.open();
            //3.设置服务器通道为非阻塞模式
            ssc.configureBlocking(false);
            //4.绑定地址
            ssc.bind(new InetSocketAddress(port));
            //5.把服务器通道ssc注册到多路复用器selector上,并且监听阻塞事件
            ssc.register(this.selector, SelectionKey.OP_ACCEPT);

            System.out.println("服务端已启动,监听port:"+port);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true){
            try{
                //1.让多路复用器开始监听
                this.selector.select();
                //2.返回多路复用器已经选择的Key结果集
                Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();
                //3.进行遍历
                while (keys.hasNext()){
                    //4.获取一个选择的的元素
                    SelectionKey key = keys.next();
                    //5.直接从容器中移除
                    keys.remove();
                    //6.如果是有效的
                    if(key.isValid()){
                        //7.如果是阻塞状态
                        if(key.isAcceptable()){
                            this.accept(key);
                        }
                        //8.如果是可读状态
                        if(key.isReadable()){
                            this.read(key);
                        }
                    }
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    private void accept(SelectionKey key){
        try{
            //1.获取服务端通道
            ServerSocketChannel ssc  = (ServerSocketChannel)key.channel();
            //2.执行阻塞方法
            SocketChannel sc = ssc.accept();  //注意:这里会一直阻塞到客户端的请求过来!
            //3.设置阻塞模式
            sc.configureBlocking(false);
            //4.注册到多路复用器上,并设置读取标识
            sc.register(this.selector,SelectionKey.OP_READ);

        }catch (IOException e){
            e.printStackTrace();
        }
    }

    private void read(SelectionKey key ){
        try{
            //1.清空缓冲区旧的数据
            this.readBuffer.clear();
            //2.获取之前注册的Socket通道对象
            SocketChannel sc = (SocketChannel)key.channel();
            //3.读取数据
            int count = sc.read(this.readBuffer);
            //4.如果没有数据
            if(count== -1){
                key.channel().close();
                key.cancel();
                return;
            }
            //5.有数据则进行数据读取,读取之前需要进行复位方法(把position 和 limit进行复位)
            this.readBuffer.flip();
            //6.根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据
            byte[] bytes = new byte[this.readBuffer.remaining()];
            //7.接收缓冲区数据
            this.readBuffer.get(bytes);
            //8.打印结果
            String body = new String(bytes).trim();
            System.out.println("服务端收到客户端的内容为:"+body);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new Server(8765)).start();
    }
}

 

【客户端程序】

package com.nio.test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * Created by cuixinjie on 2018/5/30.
 */
public class Client {


    public static void main(String[] args) {
        //创建连接的地址
        InetSocketAddress address = new InetSocketAddress("127.0.0.1",8765);

        //声明连接通道
        SocketChannel sc = null;

        //建立缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        try{
            //打开通道
            sc = SocketChannel.open();
            //进行连接
            sc.connect(address);
            while(true){
                //定义一个字节数组,然后使用系统录入功能
                byte[] bytes = new byte[1024];
                System.out.print("客户端发送的数据为:");
                System.in.read(bytes);

                //把数据的数据放入缓冲区中
                buf.put(bytes);
                //对缓冲区进行复位
                buf.flip();
                //写出数据
                sc.write(buf);
                //清空缓冲区数据
                buf.clear();
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if(null!=sc){
                try{
                    sc.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

【运行结果】

1.先启动服务端

2.再启动客户端,并输入需要传输的数据

3.再查看服务端接受的数据

 

posted @ 2018-05-30 23:33  HigginCui  阅读(218)  评论(0编辑  收藏  举报