1. 程式人生 > >java nio之 channel通道(二)

java nio之 channel通道(二)

java nio


java nio 通道上一篇文章裏就講述過,channel總是寫數據的時候,要先把數據寫入到bytebuffer,讀數據的時候總是要先從channel中讀入到bytebuffer。如下圖,這個圖是好多知名博客常用的圖,很好理解這個channel。

技術分享


channel分為一下幾種:

  1. FileChannel

  2. SocketChannel

  3. ServerSocketChannel

  4. DatagramChannel


FileChannel:

經常說的FileChannel都是拿下面的例子說事

代碼如下:

package com.nio.basic;

import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * Created by sdc on 2017/8/13.
 */
public class RandomAccessFileTest {

    public static void main(String[] args) {
        readFile();
    }

    /**
     * 讀取文件
     * @throws Exception
     */
    public static void readFile(){
        String fileName = "C:\\Users\\sdc\\Desktop\\gc (2).log";
        RandomAccessFile randomAccessFile = null;
        try{
            randomAccessFile = new RandomAccessFile(fileName, "r");
            long fileLength = randomAccessFile.length();
            System.out.print("length" + fileLength);

            int start = 100;
            randomAccessFile.seek(start);
            byte[] bytes = new byte[20];
            int read = 0;
            while ((read = randomAccessFile.read(bytes)) != -1) {
                System.out.println(new String(bytes, "UTF-8"));
            }

            System.out.println(bytes.length);
            System.out.println(new String(bytes, "UTF-8"));

        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (randomAccessFile != null) {
                try {
                    randomAccessFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}


還有這樣的例子:

FileInputStream is = new FileInputStream(new File(src));
FileChannel channelFrom = is.getChannel();

其實這兩個是用到了nio的channel,不妨自己寫一個例子試試。


SocketChannel和ServerSocketChannel一般是兩個集合起來說的,一個用於客戶端連接,一個用於服務端連接。

package com.nio.basic;

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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * nio 服務端
 * Created by sdc on 2017/8/13.
 */
public class NIoServer {

    ByteBuffer buffer = ByteBuffer.allocate(1024);

    public static void main(String[] args) throws IOException {
        System.out.println("server started...");
        try {
            new NIoServer().run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void run () throws  Exception {
        //打開服務器端的套接字通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //服務器端設置為非阻塞
        serverSocketChannel.configureBlocking(false);
        //服務端進行綁定
        serverSocketChannel.bind(new InetSocketAddress("localhost", 8000));

        //註冊感興趣的事件
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            int selectCount = selector.select();
            if( selectCount ==0 ) {
                continue;
            }

            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            //獲取叠代器
            Iterator<SelectionKey> keyIterator = keys.iterator();

            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                if (!key.isValid()) {
                    continue;
                }
                if (key.isAcceptable()) {
                    ServerSocketChannel  sscTemp = (ServerSocketChannel) key.channel();
                    //得到一個連接好的SocketChannel,並把它註冊到Selector上,興趣操作為READ
                    SocketChannel socketChannel = sscTemp.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("REGISTER CHANNEL , CHANNEL NUMBER IS:" + selector.keys().size());
                } else if (key.isReadable()) {
                    //讀取通道中的數據
                    SocketChannel channel = (SocketChannel) key.channel();
                    read(channel);
                }
                keyIterator.remove(); //該事件已經處理,可以丟棄
            }
        }
    }

    private void read(SocketChannel channel) throws IOException {
        int count ;
        buffer.clear();
        try {
            while ((count = channel.read(buffer)) > 0) {
                buffer.flip();
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);
                System.out.println("READ FROM CLIENT:" + new String(bytes));
            }
            if (count < 0) {
                channel.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
package com.nio.basic;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * nio 客戶端
 * Created by sdc on 2017/8/13.
 */
public class NioClient {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Client("nio-client-1"));
        executorService.submit(new Client("nio-client-2"));
        executorService.submit(new Client("nio-client-3"));
        executorService.shutdown();
    }

    static class Client extends Thread {

        private String clientThreadName;

        ByteBuffer buffer = ByteBuffer.allocate(1024);

        Random random = new Random(20);

        Client(String clientThreadName) {
            this.clientThreadName = clientThreadName;
        }

        @Override
        public void run() {
            SocketChannel channel = null;
            try {
                channel = SocketChannel.open();
                channel.configureBlocking(false);
                channel.connect(new InetSocketAddress("localhost", 8000));
                while (!channel.finishConnect()) {
                    TimeUnit.MICROSECONDS.sleep(100);
                }

                for (int i=0; i<5; i++) {
                    TimeUnit.MICROSECONDS.sleep(100 * random.nextInt());
                    String message = "send message " + i + " from" + clientThreadName;
                    buffer.put(message.getBytes());
                    buffer.flip();

                    //buffer先把數據讀入到buffer,然後channel先把buffer中的數據寫入到channel,
                    channel.write(buffer);

                    buffer.clear();
                }

            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }


}




本文出自 “不積跬步無以至千裏” 博客,請務必保留此出處http://shangdc.blog.51cto.com/10093778/1955874

java nio之 channel通道(二)