美文网首页Netty学习
SocketChannel 使用open或connect/fin

SocketChannel 使用open或connect/fin

作者: tracy_668 | 来源:发表于2021-03-01 09:33 被阅读0次

    使用connect效果

    首先给出一个通用的服务端代码:

    package NonBlocking;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    
    public class TestOpenAndConnectServer {
        static ServerSocketChannel serverSocketChannel = null;
        static Selector selector = null;
    
        public static void main(String[] args) throws IOException {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(8888));
    
            selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            int result = 0; int i = 1;
            while ((result = selector.select()) > 0) {
                System.out.println(String.format("selector %dth loop, ready event number is %d", i++, result));
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while(iterator.hasNext()){
                    SelectionKey sk = iterator.next();
    
                    if (sk.isAcceptable()) {
                        ServerSocketChannel ss = (ServerSocketChannel)sk.channel();
                        SocketChannel socketChannel = ss.accept();
                        socketChannel.configureBlocking(false);  //也切换非阻塞
                        socketChannel.register(selector, SelectionKey.OP_READ);  //注册read事件
                        System.out.println("接受到新的客户端连接");
                    } else if (sk.isReadable()) {
                        System.out.println("有数据可读");
                    }
    
                    iterator.remove();
                }
            }
        }
    }
    
    

    使用connect效果

    package NonBlocking;
    
    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.SocketChannel;
    import java.util.Date;
    import java.util.Iterator;
    import java.util.Scanner;
    
    public class TestOpenAndConnectClient {
        static SocketChannel socketChannel = null;
        static Selector selector = null;
    
        public static void main(String[] args) throws IOException {
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            boolean connected = socketChannel.connect(new InetSocketAddress("127.0.0.1",8888));
            System.out.println(connected);
            selector = Selector.open();
    
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            int result = 0; int i = 1;
            while((result = selector.select()) > 0) {
                System.out.println(String.format("selector %dth loop, ready event number is %d", i++, result));
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
    
                    if (sk.isConnectable()) {
                        SocketChannel sc = (SocketChannel)sk.channel();
                        if (sc.finishConnect()) {
                            System.out.println("与服务端建立连接成功");
                        } else {
                            System.out.println("与服务端建立连接失败");
                        }
                        sc.register(selector, SelectionKey.OP_READ);
                    } else if (sk.isReadable()) {
                        System.out.println("有数据可读");
                    }
    
                    iterator.remove();
                }
            }
        }
    }
    
    

    在服务端已经运行后,再运行客户端,效果如下:

    false
    selector 1th loop, ready event number is 1
    与服务端建立连接成功
    
    

    如果服务端没有运行,再运行客户端,效果如下:可见在执行sc.finishConnect()抛出了异常。

    false
    selector 1th loop, ready event number is 1
    Exception in thread "main" java.net.ConnectException: Connection refused: no further information
        at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
        at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
        at NonBlocking.TestOpenAndConnectClient.main(TestOpenAndConnectClient.java:34)
    
    

    正如connect的api文档所解释:

    If this channel is in non-blocking mode then an invocation of this method initiates a non-blocking connection operation. If the connection is established immediately, as can happen with a local connection, then this method returns true. Otherwise this method returns false and the connection operation must later be completed by invoking the finishConnect method.
    

    一个channel在非阻塞模式下执行connect后,如果连接能马上建立好则返回true,否则完成false。如果返回false,那么只能通过之后调用finishConnect来判断连接是否完成。

    finishConnect的api文档:

    If the connection operation failed then invoking this method will cause an appropriate IOException to be thrown.
    
    
    

    如果连接操作已经失败了,那么将会抛出异常。

    If this channel is in non-blocking mode then this method will return false if the connection process is not yet complete.
    
    
    

    如果连接操作还未完成好,那么将返回false。

    但由于我们是通过Selector来触发事件,所以connect事件到来时,这个连接要么已经成功,要么已经失败(抛出异常的形式告诉我们)。

    就算是目标地址不可连接 在connect不会抛异常,只会在fininshConnect抛异常

    相关文章

      网友评论

        本文标题:SocketChannel 使用open或connect/fin

        本文链接:https://www.haomeiwen.com/subject/kbvofltx.html