java NIO socket编程简介

来源:互联网 发布:变性手术知乎 编辑:程序博客网 时间:2024/04/29 17:34

针对于BIO的弊端,在java后续版本中推出了NIO,在此之前,网络通信方面很少使用java的BIO,有更好的为何不用。N可以理解为new的意思,新的io,在NIO里面可以选择不阻塞,默认是阻塞的。NIO的三大 核心channel,buffer,selector,通道用于传输数据,类似于流,buffer存储数据的缓冲,selector选择器。对于它们的工作,我是这么认为的,channerl注册selector,channel可以注册读,写等多个,selector通过遍历里面的元素,获取数据,数据的都和 写通过buffer来实现,传输时通过channel,在遍历的时候,取出数据,或者存入数据,如果什么也没有或者什么也没有写入,那么就什么也没有,这样就可以实现一个线程控制多个socket。当然大型服务器是不可能只使用一个selector的,通常一个网段使用一个或者多个selector,所以说网络方面比较复杂,能够使用netty等框架,就不要自己去实现一个框架来实现自己的功能,当然大牛就是写框架的。用的少,不代表不要精通,这是通往大牛的一步,要带着理想学习。

客户端 仅是简单的发送

package com.wsdc.socket;import java.io.IOException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;import java.util.concurrent.TimeUnit;public class Client {    public static void main(String[] args) {        SocketChannel sc = null;        try {            sc = SocketChannel.open();            sc.configureBlocking(false);            sc.connect(new InetSocketAddress("127.0.0.1", 9999));            if(sc.finishConnect()){                ByteBuffer bb = ByteBuffer.allocate(1024);                String str = "少年壮志不言愁";                while(true){                    bb.clear();                    TimeUnit.SECONDS.sleep(1);                    bb.put(str.getBytes());                    bb.flip();                    sc.write(bb);                    System.out.println("发送数据");                }            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

服务端 java对于通信的操作均是socket,无论采取那种方式,均是可以 读取数据的,也就是说,用BIO的方式发送,用NIO的方式接收,这是完全没有问题的,只不过是面向socket的不同方向而已,本质均是从 socket中读取和写入数据

package com.wsdc.socket;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;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.concurrent.TimeUnit;/** *  * @author ASUS * 只要是socket通信  无论是使用io还是nio均可以使用 *  * io或者nio来接收  实现混合使用  当然这里指的是服务端和客户端可以使用不同 *  * 的策略  对于同一侧应该要使用同一种类型 *  * 底层实现的是TCP/IP,无论是io还是nio均为对底层操作 *  * 数据并不会发生改变  对于服务器而言通常需要使用nio  对付 *  * 客户端使用io或者nio   还有aio异步io */public class Server {    public static void main(String[] args) {        //oldMethod();        //newMethodBlock();        newMethodUnBlock();        //selector();    }    //阻塞的接收方法      public static void newMethodBlock(){        ServerSocketChannel ssc = null;        SocketChannel sc = null;        try {            ssc = ServerSocketChannel.open();            ssc.socket().bind(new InetSocketAddress(9999));            sc = ssc.accept();            ByteBuffer bb = ByteBuffer.allocate(1024);            while(true){                if(sc == null){                    continue;                }                sc.read(bb);                bb.flip();                System.out.println("接收数据");                System.out.println(new String(bb.array()));            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } finally{            if(sc != null){                try {                    sc.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            if(ssc != null){                try {                    ssc.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }    //nio非阻塞接收方法   即注册接收器    public static void newMethodUnBlock(){        ServerSocketChannel ssc = null;        Selector selector = null;        ByteArrayOutputStream bos = null;        try {            bos = new ByteArrayOutputStream();            ssc = ServerSocketChannel.open();            ssc.socket().bind(new InetSocketAddress(9999));            ssc.configureBlocking(false);            selector = selector.open();            ssc.register(selector, SelectionKey.OP_ACCEPT);            Iterator<SelectionKey> it = null;            SelectionKey key = null;            while(true){                if(selector.select(3000) == 0){                    System.out.println("尚未连接");                    continue;                }                it = selector.selectedKeys().iterator();                while(it.hasNext()){                    key = it.next();                    Thread.sleep(500);                    if(key.isAcceptable()){                        /**                         * 这里表示ssc处于可以连接状态                            *                          * ssc设置为非阻塞状态,一旦客户端处于连接 这里就会触发                         *                          * 一旦有新的客户端连接  这里的sc才会有返回值                         *                          * 否者会一直为空   即后面的代码就没有什么用处                         *                          * 注意这里不能注册Accept  只能注册read和write                         *                          * 可以注册多个   channel在关闭的时候会自动解除注册                         */                        ssc = (ServerSocketChannel) key.channel();                        SocketChannel sc = ssc.accept();                        sc.configureBlocking(false);                        sc.register(key.selector(), SelectionKey.OP_READ|SelectionKey.OP_WRITE,ByteBuffer.allocateDirect(1024));                    }                    //这里是针对于连接生成的sc具备的读状态                    if(key.isReadable()){                        SocketChannel sc1 = (SocketChannel) key.channel();                        ByteBuffer bb = (ByteBuffer) key.attachment();                        int len = sc1.read(bb);                        if(len == -1){                            sc1.close();                        }                        bb.flip();                        while(bb.hasRemaining()){                            bos.write(bb.get());                        }                        System.out.println(new String(bos.toByteArray(),0,len));                        bos.reset();                        bb.clear();                    }                    if(key.isWritable()){                        System.out.println("写状态");                    }                    if(key.isConnectable()){                        System.out.println("连接状态");                    }                    /**                     * 此处是将处理过的数据移除                     *                      * 下一次的循环会再次将注册的通道通道添加                     *                      * 但是不会自动移除  需要手动移除                     */                    it.remove();                }            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } finally {            if(ssc != null){                try {                    ssc.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            if(selector != null){                try {                    selector.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }    //io的接收方法        public static void oldMethod(){        ServerSocket ss = null;        Socket socket = null;        InputStream is = null;        try {            ss = new ServerSocket(9999);            socket = ss.accept();            is = socket.getInputStream();            int len = 0;            byte[] data = new byte[1024];            while((len = is.read(data)) != -1){                System.out.println(new String(data,0,len));            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

需要注意的是 如果没有设置不阻塞的话,也就是阻塞,是会在accept处阻塞,如果设置了不阻塞,会直接返回,如果没有连接,那么就返回null 坚决不会阻塞

0 0
原创粉丝点击