JAVA -NIO实现(一)

来源:互联网 发布:unity3d 中国象棋 编辑:程序博客网 时间:2024/05/22 23:26
package com.liu.server;

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;
import java.util.Set;


/*
 * 自定义服务器
 */
public class NIOServer {
    
    private static int SERVER_PORT = 9000;
    
    private static String SERVER_URI = "127.0.0.1";
    
    private final static int BLOCK = 4096;
    
    private static ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
    
    private static ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
    
    private ServerSocketChannel serverSocketChannel = null;
    
    private Selector selector = null;
    
    public static void main(String[] args) {
        NIOServer server = new NIOServer();
        server.start();
    }
    
    private void start(){
        try {
            this.initServer();
            this.initService();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void initServer(){
        try {
            serverSocketChannel  = ServerSocketChannel.open();
            
            //静态方法 实例化selector
            selector = Selector.open();
            
            //设置为非阻塞方式,如果为true 那么就为传统的阻塞方式
            serverSocketChannel.configureBlocking(false);
            
            /*
             * 通过这个选项,可以使多个Socket对象绑定在同一个端口上。其实这样做并没有多大意义,但当使用close方法关闭Socket连接后,
             * Socket对象所绑定的端口并不一定马上释放;系统有时在Socket连接关闭才会再确认一下是否有因为延迟面未到达的数据包,
             * 这完全是在底层处理的,也就是说对用户是透明的;因此,在使用Socket类时完全不会感觉到。
               * 这种处理机制对于随机绑定端口的Socket对象没有什么影响,
             * 但对于绑定在固定端口的Socket对象就可能会抛出“Address already in use: JVM_Bind”例外。
             * 因此,使用这个选项可以避免个例外的发生。
             */
            serverSocketChannel.socket().setReuseAddress(true);  
            
            //绑定端口
            serverSocketChannel.socket().bind(new InetSocketAddress(SERVER_URI,SERVER_PORT));
            
            /*
             * 设置服务处于可接受信息的状态,即在服务中注册KEY,告诉服务 现在以经处于属于接受状态
             */
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            
            System.out.println("NIOServer is starting at " + SERVER_PORT + "......");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void initService() throws IOException{
        
        while(selector.select()>0){
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            
            Iterator<SelectionKey> it = selectionKeys.iterator();
            
            System.out.println("目前已经接受的key的 size : " + selectionKeys.size());
            
            while(it.hasNext()){
                 SelectionKey selectionKey = it.next();
                 it.remove();
                
                 //处理传过来的数据
                 handleData(selectionKey);  
            }
        }
    }
    
    private void handleData(SelectionKey key) throws IOException{
        
        if(key.isAcceptable()){
             System.out.println("Accepting......");
             SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();
             channel.configureBlocking(false);
             channel.register(selector, SelectionKey.OP_READ);
        }else if(key.isReadable()){
            System.out.println("Reading......");
            SocketChannel channel = (SocketChannel) key.channel();
            receiveBuffer.clear();
            int count = channel.read(receiveBuffer);   
            if(count>0){
                String receiveText = new String(receiveBuffer.array(),0,count);
                System.out.println("客户端传递的内容:"+receiveText);
                channel.register(selector, SelectionKey.OP_WRITE);
            }
        }else if(key.isWritable()){
            System.out.println("Writting......");
            SocketChannel channel = (SocketChannel) key.channel();
            sendBuffer.clear();
            sendBuffer.put(new String("这是测试数据").getBytes());
            
            //将缓冲区各标志复位,因为向里面put了数据,标志被改变,复位到起始位置
            sendBuffer.flip();
            channel.write(sendBuffer);
            channel.close();
        }
    }

}


测试结果如下:



原创粉丝点击