美文网首页Nio
NIO之八--SocketChannel

NIO之八--SocketChannel

作者: AlanKim | 来源:发表于2019-03-03 09:00 被阅读1次

    Java NIO SocketChannel

    A Java NIO SocketChannel is a channel that is connected to a TCP network socket. It is Java NIO's equivalent of Java Networking's Sockets. There are two ways a SocketChannel can be created:

    1. You open a SocketChannel and connect to a server somewhere on the internet.
    2. A SocketChannel can be created when an incoming connection arrives at a ServerSocketChannel.

    Opening a SocketChannel

    Here is how you open a SocketChannel:

    SocketChannel socketChannel = SocketChannel.open();
    socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80)); // http:// 需要去掉
    

    Closing a SocketChannel

    You close a SocketChannel after use by calling the SocketChannel.close() method. Here is how that is done:

    socketChannel.close();    
    

    Reading from a SocketChannel

    To read data from a SocketChannel you call one of the read() methods. Here is an example:

    ByteBuffer buf = ByteBuffer.allocate(48);
    
    int bytesRead = socketChannel.read(buf);
    

    First a Buffer is allocated. The data read from the SocketChannel is read into the Buffer.

    Second the SocketChannel.read() method is called. This method reads data from the SocketChannel into the Buffer. The int returned by the read() method tells how many bytes were witten into the Buffer. If -1 is returned, the end-of-stream is reached (the connection is closed).

    每次读取buffer 最大读到buffer.capacity的数据,int值返回的是读到的实际字节数。

    如果返回的是-1,那么说明到了channel的尾部,连接已关闭

    Writing to a SocketChannel

    Writing data to a SocketChannel is done using the SocketChannel.write() method, which takes a Bufferas parameter. Here is an example:

    String newData = "New String to write to file..." + System.currentTimeMillis();
    
    ByteBuffer buf = ByteBuffer.allocate(48);
    buf.clear();
    buf.put(newData.getBytes());
    
    buf.flip();
    
    while(buf.hasRemaining()) {
        channel.write(buf);
    }
    

    Notice how the SocketChannel.write() method is called inside a while-loop. There is no guarantee of how many bytes the write() method writes to the SocketChannel. Therefore we repeat the write() call until the Buffer has no further bytes to write.

    Non-blocking Mode

    You can set a SocketChannel into non-blocking mode. When you do so, you can call connect(), read() and write() in asynchronous mode.

    connect()

    If the SocketChannel is in non-blocking mode, and you call connect(), the method may return before a connection is established. To determine whether the connection is established, you can call the finishConnect() method, like this:

    socketChannel.configureBlocking(false);
    socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
    
    while(! socketChannel.finishConnect() ){
        //wait, or do something else...    
    }
    

    write()

    In non-blocking mode the write() method may return without having written anything. Therefore you need to call the write() method in a loop. But, since this is already being done in the previous write examples, no need to do anything differently here.

    read()

    In non-blocking mode the read() method may return without having read any data at all. Therefore you need to pay attention to the returned int, which tells how many bytes were read.

    Non-blocking Mode with Selectors

    The non-blocking mode of SocketChannel's works much better with Selector's. By registering one or more SocketChannel's with a Selector, you can ask the Selector for channels that are ready for reading, writing etc. How to use Selector's with SocketChannel's is explained in more detail in a later text in this tutorial.

    写了个大致的代码,不过无法从远程server中读取到数据:

    {
    
        public static void main(String[] args) throws IOException {
    
            SocketChannel socketChannel = SocketChannel.open(); // 创建
            socketChannel.configureBlocking(false); // 异步
            socketChannel.connect(new InetSocketAddress("www.vip.com", 80)); // 连接
            // socketChannel.connect(new InetSocketAddress(9999));就可以连接到下一章节的ServerSocketChannel,并且做信息交换
    
            System.out.println(socketChannel.isConnected());
    
            Selector selector = Selector.open();
    
            socketChannel.register(selector, SelectionKey.OP_CONNECT); // 注册到Selector
    
            // 循环处理
            while (true) {
    
                int count = selector.select(2000); // select,判断有多少个readyChannel
    
                System.out.println("count=" + count);
    
                if (0 == count) continue;
    
                Set<SelectionKey> selectionKeys = selector.selectedKeys(); // 获取SelectionKey
    
                Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
    
                while (keyIterator.hasNext()) {  // 遍历
    
                    SelectionKey key = keyIterator.next();
    
                    if (key.isConnectable()) {
                        SocketChannel socketChannel1 = (SocketChannel) key.channel();  // 获取socketChannel
    
                        System.out.println(socketChannel.equals(socketChannel1));  // true 同一个socketChannel
                        System.out.println(socketChannel1.isConnected());
    
                        // 从socketChannel中读取数据
                        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
    
                        int readBytesSize = 0;
                        // 如果不用finishConnect,这里会报异常 Exception in thread "main" java.nio.channels.NotYetConnectedException
                        // 但是这样总是取不出来数据,不确定是不是server的问题
                        while (socketChannel1.finishConnect()) {
                            readBytesSize = socketChannel1.read(byteBuffer);
                            while (readBytesSize != -1) { // 读取的数据放入byteBuffer中
    
                                System.out.println(readBytesSize);
                                byteBuffer.flip();
                                while (byteBuffer.hasRemaining()) {
                                    System.out.print((char) byteBuffer.get());
                                }
    
                                byteBuffer.clear();
    
                                // 写数据进去
                                String newData = "New String to write to file..." + System.currentTimeMillis();
    
                                byteBuffer.put(newData.getBytes());
    
                                byteBuffer.flip();
    
                                while(byteBuffer.hasRemaining()) {
                                    socketChannel1.write(byteBuffer);
                                }
    
                            }
                        }
    
                        socketChannel1.close();  // 处理结束后 close
                    }
    
                    keyIterator.remove();
                }
            }
    
        }
    

    相关文章

      网友评论

        本文标题:NIO之八--SocketChannel

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