Java Socket NIO入门

Java Socket、SocketServer的读写、连接事件监听,都是阻塞式的。Java提供了另外一种非阻塞式读写、连接事件监听方式——NIO。本文简单的介绍一个NIO Socket入门例子,原理以及详细用法,参考后续文章

服务端代码

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;

/**
 * 
 * NIO Socket Server
 * @author coshaho
 */
public class NIOServer
{
    public static void main(String[] args) throws IOException
    {
        // 启动Socket Server Channel
        ServerSocketChannel server = ServerSocketChannel.open();
        server.bind(new InetSocketAddress(8001));
        server.configureBlocking(false);
        
        // 绑定选择器,注册连接监听事件
        Selector selector = Selector.open();
        server.register(selector, SelectionKey.OP_ACCEPT);
        
        SelectorHandler handler = new SelectorHandler();
        while(true)
        {
            // 非阻塞监听注册事件
            if(selector.select(2000) == 0)
            {
                System.out.println("No selection");
                continue;
            }
            
            // 发现注册事件,依次处理
            Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
            while(keyIter.hasNext())
            {
                SelectionKey key = keyIter.next();
                if(key.isAcceptable())
                {
                    handler.doAccept(key);
                }
                
                if(key.isReadable())
                {
                    handler.doRead(key);
                }
                
                if(key.isValid() && key.isWritable())
                {
                    handler.doWrite(key);
                }
                
                keyIter.remove();
            }
        }
    }
    
    /**
     * 事件处理器
     * @author h00219638
     */
    public static class SelectorHandler
    {
        // 连接请求处理
        public void doAccept(SelectionKey key) throws IOException
        {
            SocketChannel socket = ((ServerSocketChannel)key.channel()).accept();
            socket.configureBlocking(false);
            // 注册数据读取事件
            socket.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(1024));
        }
        
        public void doRead(SelectionKey key) throws IOException
        {
            SocketChannel socket = (SocketChannel)key.channel();
            
            // 也可以临时分配ByteBuffer
            ByteBuffer buf = (ByteBuffer) key.attachment();
            buf.clear();
            
            if(-1 == socket.read(buf))
            {
                socket.close();
            }
            else
            {
                System.out.println("Server received: " + new String(buf.array(), 0, buf.limit()));

                /**
                 * public static final int OP_READ = 1 << 0; 
                   public static final int OP_WRITE = 1 << 2; 
                   public static final int OP_CONNECT = 1 << 3; 
                   public static final int OP_ACCEPT = 1 << 4; 
                 */
                // 增加写事件,写事件会不断被触发,数据写完后必须取消写事件监听
                key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
            }
        }
        
        public void doWrite(SelectionKey key) throws IOException
        {
            SocketChannel socket = (SocketChannel)key.channel();
            ByteBuffer buf = (ByteBuffer) key.attachment();
            
            // 写数据之前注意调用flip方法,重置指针
            buf.flip();
            System.out.println("Write: " + new String(buf.array(), 0, buf.limit()));
            socket.write(buf);
            if(!buf.hasRemaining())
            {
                // 取消写事件监听
                key.interestOps(key.interestOps() &~  SelectionKey.OP_WRITE);
            }
            buf.compact();
        }
    }
    
}

 客户端代码

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

import org.drools.core.util.StringUtils;

/**
 * 
 * NIO Socket Client
 * @author coshaho
 */
public class NIOClient
{
    public static void main(String[] args) throws IOException
    {
        SocketChannel socket = SocketChannel.open();
        socket.configureBlocking(false);
        
        if(!socket.connect(new InetSocketAddress("localhost", 8001)))
        {
            System.out.println("Not connect");  
            // 正真的连接
            while(!socket.finishConnect())
            {
                System.out.println("Not finishConnect");  
            }
        }
        
        ByteBuffer wBuf = ByteBuffer.wrap("Hello, server".getBytes());
        while(wBuf.hasRemaining())
        {
            socket.write(wBuf);
        }
        
        ByteBuffer rBuf = ByteBuffer.allocate(8);
        StringBuffer sBuf = new StringBuffer();
        while(-1 != (socket.read(rBuf)))
        {
            rBuf.flip();
            String s = new String(rBuf.array(), 0, rBuf.limit());
            sBuf.append(s);
            rBuf.clear();
            if(StringUtils.isEmpty(s))
            {
                break;
            }
            
        }
        
        System.out.println("Client received: " + sBuf.toString());
        socket.close();
    }
}

 

posted @ 2017-12-21 20:34  coshaho  阅读(1532)  评论(0编辑  收藏  举报