【问题标题】:Transferring files through Java NIO APIs通过 Java NIO API 传输文件
【发布时间】:2016-02-01 02:25:03
【问题描述】:

我正在尝试使用 Java NIO API 将 mp3 文件从服务器传输到客户端。

特别是,我正在尝试使用 transferTo 和 transferFrom 方法。

我已经检查过服务器是否正确识别文件并传输到 FileChannel。

但是,从客户端的角度来看,它认为连接到服务器的FileChannel的大小为0,可以解释为客户端没有从该通道接收到任何文件。

这是服务器和客户端控制台上的结果。

[服务器]

Server is started...

java.nio.channels.SocketChannel[connected local=/127.0.0.1:7777 remote=/127.0.0.1:60430]Here comes a new client!

!!write activated!!

Channel size : 3622994
filename : C:\Users\InhoKim\Music\5 O'clock - Black Nut.mp3
java.nio.channels.SocketChannel[connected local=/127.0.0.1:7777 remote=/127.0.0.1:60430]The number of files transferred :  1

[客户]

!!read activated!!
Channel size : 0

我该如何解决这个问题?

这是服务器和客户端的完整代码

[服务器]

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

public class MusicServer {
    private Selector selector = null;
    private ServerSocketChannel serverSocketChannel = null;
    private ServerSocket serverSocket = null;
    File dir = new File("C:\\Users\\InhoKim\\Music\\");
    boolean test = true;

    public static void main(String[] args) {
        MusicServer ms = new MusicServer();
        ms.initServer();
        ms.startServer();
    }

    public void initServer() {
        try {

            selector = Selector.open();
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false); 
            serverSocket = serverSocketChannel.socket();
            InetSocketAddress isa = new InetSocketAddress("localhost", 7777);
            serverSocket.bind(isa); 
            serverSocketChannel.register(selector,  SelectionKey.OP_ACCEPT); 

        } catch(Exception e) {e.printStackTrace();}

    }

    public void startServer() {

        System.out.println("Server is started...");

        try {
            while (true) {
                selector.select();

                Set<SelectionKey> keys = selector.selectedKeys();
                for (SelectionKey key : keys) {

                    SelectableChannel channel = key.channel();

                    if (channel instanceof ServerSocketChannel) {
                        if (key.isAcceptable())
                            accept(key);
                    } else {
                        if (key.isWritable()) {
                            if(test)
                                write(key);
                        }

                    }
                }   
            }
        } catch(Exception e) {e.printStackTrace();}

    }

    private void accept(SelectionKey key) { 
        ServerSocketChannel server = (ServerSocketChannel) key.channel();

        try {
            SocketChannel sc = server.accept();
            if (sc == null) return;
            sc.configureBlocking(false);
            sc.register(selector, SelectionKey.OP_WRITE); 
            System.out.println(sc.toString() + "Here comes a new client!");

        } catch(Exception e) {e.printStackTrace();}

    }
    private void write(SelectionKey key) {
        if(test)
        System.out.println("!!write activated!!");
        test = false;

        SocketChannel sc = (SocketChannel) key.channel();
        try {

            File[] files = dir.listFiles();

            int count = 0;
            for (File file : files) {
                count++;
                FileInputStream fis = new FileInputStream(file);
                FileChannel inChannel = fis.getChannel();
                System.out.println("Channel size : " + (int)inChannel.size());
                System.out.println("filename : " + file);

                inChannel.transferTo(0, (int)inChannel.size(), sc);

                fis.close();
                break;
            }
            System.out.println(sc.toString() + "The number of files transferred :  " + count);

        } catch(Exception e) {e.printStackTrace();} 
    }   
}

[客户]

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

public class MusicClient {
    private Selector selector = null;
    private SocketChannel sc = null;
    int count = 0;

    public static void main(String[] args) {
        MusicClient mc = new MusicClient();
        mc.startServer();
    }

    public void initServer() {

        try {
            selector = Selector.open();
            sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 7777)); 
            sc.configureBlocking(false);
            sc.register(selector, SelectionKey.OP_READ);

        } catch(Exception e) {e.printStackTrace();}
    }

    public void startServer() {
        initServer();
        startReader();
    }

    public void startReader() {
        try {
            while (true) {
                selector.select();

                Set<SelectionKey> keys = selector.selectedKeys();

                for (SelectionKey key : keys) {
                    if (key.isReadable()) {
                        read(key);
                        System.exit(0);

                    }
                }
            }

        } catch(Exception e) {e.printStackTrace();}
    }

    private void read(SelectionKey key) {
        System.out.println("!!read activated!!");
        SocketChannel sc = (SocketChannel) key.channel();
        try {

        File dir = new File("D:\\Target2\\");
        FileOutputStream fos = new FileOutputStream(dir + "\\" + count + ".mp3"); // file name has been set as a number
        count++;
        FileChannel outChannel = fos.getChannel();
        System.out.println("Channel size : " + (int)outChannel.size());
        outChannel.transferFrom(sc, 0, (int)outChannel.size());
        fos.close();    

        } catch(Exception e) {e.printStackTrace();}
    }
}

【问题讨论】:

    标签: java networking io nio file-transfer


    【解决方案1】:

    从客户端来看,它认为连接服务器的FileChannel的大小为0

    没有“FileChannel 连接到服务器”之类的东西。文件通道连接到文件。你有一个FileChannel 连接到一个新的FileOutputStream,它刚刚创建了一个新文件,因此其大小为零。

    可以解释为客户端没有从频道收到任何文件。

    不,它可以解释为您告诉FileChannel 传输零字节,它正确地做到了。

    您无法获得SocketChannel 的大小,因为它没有任何意义(考虑一个只继续发送并且从不关闭连接的对等点)。所以在这种情况下,你必须使用Long.MAX_VALUE 作为大小。当没有更多字节要传输时,传输将完成,或者实际上之前,尤其是当您使用非阻塞模式时。

    编辑我看不出有任何理由在客户端中使用非阻塞模式。我会删除它,并且必须在一个循环中调用Selector. 和transferFrom(),该循环在返回零时终止。如果您必须在那里使用非阻塞模式,则在服务器中使用transferTo() 会更加复杂,因为您必须在返回零时注册OP_WRITE,并在获得它时重新选择并使用调整后的偏移量重新启动,然后取消注册OP_WRITE 如果它不返回零。

    【讨论】:

    • 我将客户端中的 'transferFrom' 方法修改为:outChannel.transferFrom(sc, 0, Long.MAX_VALUE);现在传输到客户端的文件包含一些信息,如标题、运行时间、艺术家等。但是,我不能播放超过 24 秒……它在 24 秒后关闭。我猜这个问题已经发生了,因为我没有在 transferFrom 和 transferTo 方法周围使用任何循环。那么......循环应该是什么样子?我的意思是...如何检查 SocketChannel 上是否有剩余数据?
    • 感谢您的回答!这对我帮助很大!因为我对阻塞和选择器没有足够的了解,所以我刚刚尝试在 transferFrom 和 To 方法周围添加一个循环。文件传输成功,我检查了它的文件大小、标题、艺术家和运行时间(大约 3 分 46 秒),但播放 24 秒后它仍然保持关闭......这个问题是否与 Blocking & Selector 的概念有关?如果是这样,我宁愿先研究更多关于 NIO 的知识……
    • 客户端很少使用非阻塞 I/O,除非您的客户端同时连接到数千台服务器,否则这不是其中之一。
    猜你喜欢
    • 2016-01-18
    • 1970-01-01
    • 2013-11-16
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 2010-10-22
    • 2018-11-14
    相关资源
    最近更新 更多