java nio文件傳輸例子

jopen 9年前發布 | 2K 次閱讀 Java

使用nio傳輸文件需要注意的是會出現粘包和服務器端緩沖區滿的情況。第一種情況,客戶端發送30次數據,而服務器端只接收到18次的情況,這種情況出現 主要是服務器端是以流的方式接收數據,它并不知道每次客戶端傳輸數據的大小而造成的。第二種情況是服務器端緩沖區滿,導致客戶端數據傳輸失敗,這種情況 下,需要判斷傳輸int send = client.write(sendBuffer)的send值,如果send值為0,則服務器端的數據緩沖區可能滿了。

客戶端實現代碼:

import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Set;

public class FileClient { private int port = 8000; / 發送數據緩沖區 / private static ByteBuffer sendBuffer = ByteBuffer.allocate(1024); / 接受數據緩沖區 / private static ByteBuffer revBuffer = ByteBuffer.allocate(1024); private InetSocketAddress SERVER; private static Selector selector; private static SocketChannel client;

public FileClient(){
    try{
        SERVER = new InetSocketAddress("localhost", port);
        init();
    }
    catch(Exception e){
        e.printStackTrace();
    }

}
private void init(){
    try {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
        socketChannel.connect(SERVER);
        while (true) {
            selector.select();
            Set<SelectionKey> keySet = selector.selectedKeys();
            for (final SelectionKey key : keySet) {
                if(key.isConnectable()){
                    client = (SocketChannel)key.channel();
                    client.finishConnect();
                    client.register(selector, SelectionKey.OP_WRITE);

                }
                else if(key.isWritable()){
                    sendFile(client);
                }
            }
            keySet.clear();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void sendFile(SocketChannel client) {
    FileInputStream fis = null;
    FileChannel channel = null;
    try {

// fis = new FileInputStream("E:\1.txt"); // fis = new FileInputStream("E:\1.rar"); fis = new FileInputStream("G:\3.rar"); channel = fis.getChannel(); int i = 1; int count = 0; while((count = channel.read(sendBuffer)) != -1) { sendBuffer.flip(); int send = client.write(sendBuffer); System.out.println("i===========" + (i++) + " count:" + count + " send:" + send); // 服務器端可能因為緩存區滿,而導致數據傳輸失敗,需要重新發送 while(send == 0){ Thread.sleep(10); send = client.write(sendBuffer); System.out.println("i重新傳輸====" + i + " count:" + count + " send:" + send); } sendBuffer.clear(); } } catch (Exception e) { e.printStackTrace(); } finally { try { channel.close(); fis.close(); client.close(); } catch (Exception e) { e.printStackTrace(); }

    }
}


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

}</pre>
服務器端

import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;

public class FileServer { private int port = 8000; / 發送數據緩沖區 / private static ByteBuffer revBuffer = ByteBuffer.allocate(1024); private static Selector selector; private static FileOutputStream fout; private static FileChannel ch; public FileServer(){ try{ init(); } catch(Exception e){ e.printStackTrace(); } } private void init() throws Exception{ ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); ServerSocket serverSocket = serverSocketChannel.socket(); serverSocket.bind(new InetSocketAddress(port)); selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("server start on port:" + port); while (true) { try { selector.select();// 返回值為本次觸發的事件數 Set<SelectionKey> selectionKeys = selector.selectedKeys();

            for (SelectionKey key : selectionKeys) {
                ServerSocketChannel server = null;
                SocketChannel client = null;
                int count = 0;
                if (key.isAcceptable()) {
                    server = (ServerSocketChannel) key.channel();
                    System.out.println("有客戶端連接進入=============)");
                    client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                    fout = new FileOutputStream("G:\\" + client.hashCode() + ".rar");
                    ch = fout.getChannel();
                } else if (key.isReadable()) {
                    client = (SocketChannel) key.channel();
                    revBuffer.clear();
                    count = client.read(revBuffer);
                    int k = 0;
                    // 循環讀取緩存區的數據,
                    while(count > 0){
                        System.out.println("k=" + (k++) + " 讀取到數據量:" + count);
                        revBuffer.flip();
                        ch.write(revBuffer);
                        fout.flush();
                        revBuffer.clear();
                        count = client.read(revBuffer);
                    }
                    if(count == -1){
                        client.close();
                        ch.close();
                        fout.close();
                    }
                }
                else if (key.isWritable()) {
                    System.out.println("selectionKey.isWritable()");

                }
            }
            System.out.println("=======selectionKeys.clear()");
            selectionKeys.clear();
        } catch (Exception e) {
            e.printStackTrace();
            break;
        }

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

}</pre>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!