zoukankan      html  css  js  c++  java
  • NIO Channel SocketChannel ServerSocketChannel

    ServerSocketChannel:

      ServerSocketChannel是一个基于通道的socket监听器。它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它增加了通道语义,因此能够在非阻塞模式下运行。用静态的open( )工厂方法创建一个新的ServerSocketChannel对象,将会返回同一个未绑定的java.net.ServerSocket关联的通道。该对等ServerSocket可以通过在返回的ServerSocketChannel上调用socket( )方法来获取。作为ServerSocketChannel的对等体被创建的ServerSocket对象依赖通道实现。这些socket关联的SocketImpl能识别通道。通道不能被封装在随意的socket对象外面。由于ServerSocketChannel没有bind( )方法,因此有必要取出对等的socket并使用它来绑定到一个端口以开始监听连接。我们也是使用对等ServerSocket的API来根据需要设置其他的socket选项。

    核心Api:

      同它的对等体java.net.ServerSocket一样,ServerSocketChannel也有accept( )方法。一旦您创建了一个ServerSocketChannel并用对等socket绑定了它,然后您就可以在其中一个上调用accept( )。如果您选择在ServerSocket上调用accept( )方法,那么它会同任何其他的ServerSocket表现一样的行为:总是阻塞并返回一个java.net.Socket对象。如果您选择在ServerSocketChannel上调用accept( )方法则会返回SocketChannel类型的对象,返回的对象能够在非阻塞模式下运行 默认为阻塞状态。假设系统已经有一个安全管理器(security manager),两种形式的方法调用都执行相同的安全检查。如果以非阻塞模式被调用,当没有传入连接在等待时,ServerSocketChannel.accept( )会立即返回null。正是这种检查连接而不阻塞的能力实现了可伸缩性并降低了复杂性。可选择性也因此得到实现。我们可以使用一个选择器实例来注册一个ServerSocketChannel对象以实现新连接到达时自动通知的功能。即只有Channel类型的对象才能实现非阻塞操作。

    代码示例如下:

    /**
    * configureBlocking Test
    * @throws Exception
    */
    @Test
    public void serverSocketChannelTest() throws Exception {
    ServerSocketChannel ssc = ServerSocketChannel.open();
    ssc.socket().bind(new InetSocketAddress(8080));
    ssc.configureBlocking(false);
    assert (ssc.validOps()==16);//return SelectionKey.OP_ACCEPT;
    SocketChannel socketChannel = ssc.accept();
    assert (socketChannel==null);
    //ServerSocket socket =ssc.socket();
    //socket.accept();//抛出异常,IllegalBlockingModeException,ssc.configureBlocking(false)之后方可执行
    Thread socketThread = new Thread(()->{
    while (true){
    try {
    SocketChannel socketChannel1 = ssc.accept();
    if (socketChannel1!=null){
    assert (socketChannel1.isBlocking());
    break;
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    });
    socketThread.start();
    SocketChannel socket = SocketChannel.open();
    socket.configureBlocking(false);
    socket.connect(new InetSocketAddress("localhost",8080));
    socketThread.join();
    }

    SocketChannel:

      Socket和SocketChannel类封装点对点、有序的网络连接,类似于我们所熟知并喜爱的TCP/IP网络连接。SocketChannel扮演客户端发起同一个监听服务器的连接。直到连接成功,它才能收到数据并且只会从连接到的地址接收。

    对应方法如下:

      在SocketChannel上并没有一种connect( )方法可以让您指定超时(timeout)值,当connect( )方法在非阻塞模式下被调用时SocketChannel提供并发连接:它发起对请求地址的连接并且立即返回值。如果返回值是true,说明连接立即建立了(这可能是本地环回连接);如果连接不能立即建立,connect( )方法会返回false且并发地继续连接建立过程。

      面向流的的socket建立连接状态需要一定的时间,因为两个待连接系统之间必须进行包对话以建立维护流socket所需的状态信息。跨越开放互联网连接到远程系统会特别耗时。假如某个SocketChannel上当前正由一个并发连接,isConnectPending( )方法就会返回true值。

      Socket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程,不过任何时候都只有一个读操作和一个写操作在进行中(保证数据不丢失而不保证维持数据分组)。请记住,sockets是面向流的而非包导向的。它们可以保证发送的字节会按照顺序到达但无法承诺维持字节分组。某个发送器可能给一个socket写入了20个字节而接收器调用read( )方法时却只收到了其中的3个字节。剩下的17个字节还是传输中。由于这个原因,让多个不配合的线程共享某个流socket的同一侧绝非一个好的设计选择。

      调用finishConnect( )方法来完成连接过程(非阻塞模式下必须调用,否则非阻塞模式下isConnected( )永远返回false),该方法任何时候都可以安全地进行调用。假如在一个非阻塞模式的SocketChannel对象上调用finishConnect( )方法,将可能出现下列情形之一:
       connect( )方法尚未被调用。那么将产生NoConnectionPendingException异常。
       连接建立过程正在进行,尚未完成。那么什么都不会发生,finishConnect( )方法会立即返回false值。
       在非阻塞模式下调用connect( )方法之后,SocketChannel又被切换回了阻塞模式。那么如果有必要的话,调用线程会阻塞直到连接建立完成,finishConnect( )方法接着就会返回true值。
       在初次调用connect( )或最后一次调用finishConnect( )之后,连接建立过程已经完成。那么SocketChannel对象的内部状态将被更新到已连接状态,finishConnect( )方法会返回true值,然后SocketChannel对象就可以被用来传输数据了。
       连接已经建立。那么什么都不会发生,finishConnect( )方法会返回true值。
    当通道处于中间的连接等待(connection-pending)状态时,您只可以调用finishConnect( )、isConnectPending( )或isConnected( )方法。一旦连接建立过程成功完成,isConnected( )将返回true值。

    示例代码如下:

        /**
         * configureBlocking Test
         * @throws Exception
         */
        @Test
        public void serverSocketChannelTest() throws Exception {
            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(8080));
            ssc.configureBlocking(false);
            assert (ssc.validOps()==16);//return SelectionKey.OP_ACCEPT;
            SocketChannel socketChannel = ssc.accept();
            assert (socketChannel==null);
            //ServerSocket socket  =ssc.socket();
            //socket.accept();//抛出异常,IllegalBlockingModeException,ssc.configureBlocking(false)之后方可执行
            Thread socketThread = new Thread(()->{
                while (true){
                    try {
                        SocketChannel socketChannel1 = ssc.accept();
                        if (socketChannel1!=null){
                            assert (socketChannel1.isBlocking());
                            ByteBuffer [] buffers = NIOUtils.getByteBuffers("hello","world");
                            long size = socketChannel1.write(buffers);
                            System.out.println(size);
                            //socketChannel1.close();
                            break;
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
            });
            socketThread.start();
            SocketChannel socket = SocketChannel.open();
            socket.configureBlocking(false);
            socket.connect(new InetSocketAddress("localhost",8080));
            assert (socket.validOps()==13);
                /*public final int validOps() {
                    return (SelectionKey.OP_READ
                        | SelectionKey.OP_WRITE
                        | SelectionKey.OP_CONNECT);
                }*/
            assert (!socket.isBlocking());
    
            ByteBuffer[] readableBuffers = NIOUtils.getReadableByteBuffers(3);
            assert (!socket.isConnected());
            assert (socket.isConnectionPending());
            while (true){
                //TimeUnit.SECONDS.sleep(1);
                assert (socket.finishConnect());//本地情况直接返回true
                if (socket.isConnected()){
                    long size = socket.read(readableBuffers);
                    if (size!=0){
                        break;
                    }
                }
            }
            socketThread.join();
            System.out.println(readableBuffers[0]);
            ByteBuffer buffer = ByteBuffer.allocate(5);
            buffer.put("hello".getBytes());
            assert (buffer.equals(readableBuffers[0]));
        }
  • 相关阅读:
    mvc+dwz准备工作
    C# action,delegate,func的用法和区别
    mvc+dwz第二天
    mvc+dwz第一天
    H5文件上传2
    H5文件上传1
    vs2010 nuget 基础连接已经关闭:发送时发生错误
    redis分布式锁
    C# 并发队列ConcurrentQueue
    正则表达式入门
  • 原文地址:https://www.cnblogs.com/heapStark/p/8177621.html
Copyright © 2011-2022 走看看