天天看點

java nio之channel

  一、通道(Channel):由 java.nio.channels 包定義的。Channel 表示 IO 源與目标打開的連接配接。Channel 類似于傳統的“流”。隻不過 Channel本身不能直接通路資料,Channel 隻能與Buffer 進行互動。

  二、Channel重要實作

  • FileChannel:操作檔案的讀寫
  • SocketChannel:通過TCP讀寫網絡資料
  • ServerSocketChannel:監聽TCP連接配接,你能利用它建立一個最簡單的Web伺服器
  • DatagramChannel:通過UDP讀寫網絡資料

  三、FileChannel 的檔案讀寫

  1)利用FileChannel 本身提供的transferTo進行資料的讀寫。

package com.troy.nio.application;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

public class Channel {

    public static void main(String[] args) throws Exception {
        //讀取檔案
        FileInputStream fileInputStream = new FileInputStream("d:/t.txt");
        //寫出檔案
        FileOutputStream fileOutputStream = new FileOutputStream("d:/e.txt");
        //擷取讀取通道
        FileChannel inChannel = fileInputStream.getChannel();
        //擷取寫入通道
        FileChannel outChannel = fileOutputStream.getChannel();
        //完成資料的寫入
        inChannel.transferTo(0,inChannel.size(),outChannel);
    }
}      

  2)利用FileChannel 提供的讀寫方法

package com.troy.nio.application;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Channel {

    public static void main(String[] args) throws Exception {
        //讀取檔案
        FileInputStream fileInputStream = new FileInputStream("d:/t.txt");
        //寫出檔案
        FileOutputStream fileOutputStream = new FileOutputStream("d:/e.txt");
        //擷取讀取通道
        FileChannel inChannel = fileInputStream.getChannel();
        //擷取寫入通道
        FileChannel outChannel = fileOutputStream.getChannel();
        //緩存
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //讀取資料
        while (inChannel.read(byteBuffer) != -1) {
            //轉換成可讀寫
            byteBuffer.flip();
            System.out.println(new String(byteBuffer.array(),"GBK").trim());
            //寫出資料,清楚緩存
            outChannel.write(byteBuffer);
            byteBuffer.clear();
        }
    }
}      

  四、SocketChannel和ServerSocketChannel在同時使用時,都是tcp協定進行傳輸的,在使用上面比較服務具體的協定控制

  具體的應用可以參考:

http://www.cnblogs.com/ll409546297/p/7929646.html

  五、DatagramChannel的方式

  1)用戶端

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class UDPClient {

    public static void main(String[] args) throws Exception {

        //擷取UDP通道
        DatagramChannel datagramChannel = DatagramChannel.open();
        //設定非阻塞
        datagramChannel.configureBlocking(false);
        //發送資料
        datagramChannel.send(ByteBuffer.wrap("hello server!".getBytes()),new InetSocketAddress("localhost",9000));
    }
}      

  2)服務端的2中寫法,阻塞和非阻塞

  1、阻塞

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class UDPServer {

    //UDP通道
    private static DatagramChannel datagramChannel;

    public static void main(String[] args) throws Exception {
        serverInit();
        listen();
    }

    //初始化
    private static void serverInit() throws IOException {
        //擷取UDP通道
        datagramChannel = DatagramChannel.open();
        //設定接收端口
        datagramChannel.socket().bind(new InetSocketAddress(9000));
    }

    //監聽
    private static void listen() throws IOException {
        while (true) {
            //接收的長度
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            //這裡會阻塞
            datagramChannel.receive(byteBuffer);
            byteBuffer.flip();
            System.out.println(new String(byteBuffer.array()).trim());
        }
    }
}      

  2、非阻塞,利用selector來進行資料選擇

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;

public class UDPServer {

    //選擇器
    private static Selector selector;
    //UDP通道
    private static DatagramChannel datagramChannel;

    public static void main(String[] args) throws Exception {
        serverInit();
        listen();
    }

    //初始化
    private static void serverInit() throws IOException {
        //擷取選擇器
        selector = Selector.open();
        //擷取UDP通道
        datagramChannel = DatagramChannel.open();
        //設定非阻塞
        datagramChannel.configureBlocking(false);
        //設定接收端口
        datagramChannel.socket().bind(new InetSocketAddress(9000));
        //注冊
        datagramChannel.register(selector, SelectionKey.OP_READ);
    }

    //監聽
    private static void listen() throws IOException {
        while (true) {
            selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                if (selectionKey.isReadable()) {
                    //接收的長度
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    //這裡不會阻塞
                    datagramChannel.receive(byteBuffer);
                    byteBuffer.flip();
                    System.out.println(new String(byteBuffer.array()).trim());
                }
            }
        }
    }
}      

  六、基本上channel的實作用法就這些了,但是裡面會涉及到很多細節的用法,這個需要自己進一步研究