欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java学习——NIO篇

程序员文章站 2022-04-24 10:50:41
...

Nio也就是继JDK1.4之后关于io的新特性的new Io,也就是传说中的无阻塞io。

Nio主要包括几个方面:
ByteBuffer:Channel:Selector:
原理部分下次再整理,本次主要是进行实例。
下面要实现就是使用nio进行简单的文本传递。

服务端:

public class MainServer {
    private static final int port = 19999;
    private static ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        ServerSocketChannel server = ServerSocketChannel.open();
        Selector sel = Selector.open();
        server.socket().bind(new InetSocketAddress(port));
        //无阻塞
        server.configureBlocking(false);
        //绑定连接事件。
        server.register(sel, SelectionKey.OP_ACCEPT);
        System.out.println("server start");
        while (true) {
            sel.select();
            Iterator iter = sel.selectedKeys().iterator();
            while (iter.hasNext()) {
                SelectionKey key = (SelectionKey) iter.next();
                iter.remove();
                // 判断是否有新的连接到达
                if (key.isAcceptable()) {
                    System.out.println("有新连接");
                    SocketChannel sc = server.accept();
                    sc.configureBlocking(false);
                    sc.register(sel, SelectionKey.OP_READ);
                }
                //判断是否可读取
                if (key.isReadable()) {
                    SocketChannel sc = (SocketChannel) key.channel();
                    sc.configureBlocking(false);
                    int count = sc.read(buffer);
                    if (count <= 0) {
                        System.out.println("客户端已经关闭了");
                        sc.close();
                    } else {
                        System.out.println("有数据过来了");
                        buffer.flip();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        String msg = new String(bytes);
                        System.out.println("收到信息>>" + msg);
                        buffer.clear();
                    }

                }
            }
        }
    }
}
 

客户端:

public class MainClient {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        SocketChannel client = SocketChannel.open();
        client.configureBlocking(false);
        Selector selector = Selector.open();
        client.register(selector, SelectionKey.OP_CONNECT);
        client.connect(new InetSocketAddress("localhost", 19999));

        String message = "client test";
        ByteBuffer bb = ByteBuffer.allocate(message.length());
        boolean flag = true;

        while (flag) {
            selector.select();
            Iterator it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = (SelectionKey) it.next();
                it.remove();
                if (key.isConnectable()) {
                    System.out.println("客户端连接上");
                    SocketChannel sc = (SocketChannel) key.channel();
                    if (sc.isConnectionPending())
                        sc.finishConnect();
                    sc.register(selector, SelectionKey.OP_WRITE);
                }
                if (key.isWritable()) {
                    System.out.println("客户端可以写");
                    SocketChannel sc = (SocketChannel) key.channel();
                    bb.clear();
                    bb.put(message.getBytes());
                    bb.flip();
                    sc.write(bb);
                    //发完一条信息,退出发送,关闭连接。
                    flag = false;
                }
            }
        }
        //关闭连接
        client.close();
    }
}
 

心得:
使用NIO进行传输的时候,也跟普通scoket差不多。其中使用ServerSocketChannel来作为服务端的channel,使用SocketChannel作为客户端的channel。其中channel可以理解为连接的通道。
sel.select();
Iterator iter = sel.selectedKeys().iterator();
chanel的selectedKeys可以理解为一次连接的实例了。每一个key可以调用其channel方法生成一个ScoketChannel。然后通过这个ScoketChannel来获取传输的内容,或者输入内容。

PS:
在服务端获取客户端传输过来的字符串时,使用ByteBuffer获得的方法是:
buffer.flip();
byte[] bytes=new byte[buffer.remaining()];
buffer.get(bytes);
String msg = new String(bytes);
通过该方法可以将客户端传送的字符byte组装为String。

在客户端传输的为一个固定的String,也可以将这个demo改写,改成控制台输入,作成一个简单的聊天程序。

另外,注意buffer.flip() 的运用。


相关标签: Java Socket