java - 使用 java NIO 选择器发送文件

标签 java file client nio server

我尝试使用 java NIO 选择器键从服务器发送文件,但是当我关闭服务器时,我从客户端收到整个文件。

服务器端代码

    public static int DEFAULT_PORT = 1234;

public static void main(String[] args) {
    String fileName = "10mb.txt";
    int port;

    try {
        port = Integer.parseInt(args[0]);
    } catch (Exception ex) {
        port = DEFAULT_PORT;
    }
    System.out.println("Listening for connections on port " + port);

    ServerSocketChannel serverChannel;
    Selector selector;
    try {
        serverChannel = ServerSocketChannel.open();
        ServerSocket ss = serverChannel.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        ss.bind(address);
        serverChannel.configureBlocking(false);
        selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    } catch (IOException ex) {
        ex.printStackTrace();
        return;
    }

    while (true) {

        try {
            selector.select();
        } catch (IOException ex) {
            ex.printStackTrace();
            break;
        }

        Set readyKeys = selector.selectedKeys();
        Iterator iterator = readyKeys.iterator();
        while (iterator.hasNext()) {

            SelectionKey key = (SelectionKey) iterator.next();

            try {

                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel client = server.accept();
                    System.out.println("Accepted connection from " + client);
                    client.configureBlocking(false);
                    SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);

                    String filePath = (fileName);
                    File file = new File(filePath);
                    int fileSize = (int) file.length();
                    System.out.println("File size =" + fileSize);
                    FileInputStream fis;
                    ByteBuffer buffer = null;

                    try {
                        fis = new FileInputStream(file);
                        FileChannel fc = fis.getChannel();
                        buffer = ByteBuffer.allocate(fileSize);
                        try {
                            fc.read(buffer);
                        } catch (IOException ex) {
                            System.out.println("IO EX :" + ex);
                        }
                    } catch (FileNotFoundException ex) {
                        System.out.println("FileNotFoundEx :" + ex);
                    }

                    buffer.flip();
                    key2.attach(buffer);

                } else if (key.isWritable()) {

                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer out = (ByteBuffer) key.attachment();

                    client.write(out);
                }

            } catch (IOException ex) {
                System.out.println("IO Exeption :" + ex);
                key.cancel();
                try {
                    key.channel().close();
                } catch (IOException cex) {
                    System.out.println(cex);
                }
            }
            iterator.remove();

        }

    }

}

客户端代码

public static void main(String[] args) throws IOException {
    String fileName = "10mb.txt";
    int bufferSize = 2048;
    int n = 0;
    int read = 0;

    SocketChannel socket = SocketChannel.open(new InetSocketAddress(1234));
    String filePath = (fileName);

    FileOutputStream out = new FileOutputStream(filePath);
    FileChannel file = out.getChannel();
    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);

    long startTime = System.currentTimeMillis();


    while ((read = socket.read(buffer)) > 0) {
        buffer.flip();

        file.write(buffer);

        n = n + read;

        buffer.clear();

        System.out.println(n);
    }
    long endTime = System.currentTimeMillis();
    long difference = endTime - startTime;
    System.out.println("File with " + n + " bytes downloaded in " + difference + " ms");
    socket.close();

    file.close();

    out.close();
}

感谢您的帮助。

最佳答案

您假设 fc.read() 填充缓冲区,而 sc.write() 清空缓冲区。这两种假设都无效。 Java中 channel 间复制的正确方法如下:

while (in.read(buffer) > 0 || buffer.position() > 0)
{
    buffer.flip();
    out.write(buffer);
    buffer.compact();
}

当您在非阻塞模式下输出到 SocketChannel 时,您需要针对 write() 返回零的情况进行修改:如果发生这种情况,您需要为 OP_WRITE 注册 channel ,返回到 select() 循环,并在 OP_WRITE 触发时恢复此循环:这一次,如果 write() 返回非零,取消注册 OP_WRITE

关于java - 使用 java NIO 选择器发送文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27347596/

相关文章:

java - 是否值得在方法中使用位运算符?

java - 安卓:基频

Sharepoint Web部件上传文件而不使用 "runat server"

javascript - 返回属性的服务器方法无法正常工作 Meteor JavaScript

java - 如何使用非 void 方法打印字符串数组?

Python正则表达式搜索并替换所有打印语句

c - 打印特定行

用于浏览非 TortoiseSVN 的 SVN 存储库的 Windows 软件?

java - Netty 客户端到服务器消息

java - Hibernate/JPA 单向 OneToMany 与源表中常量值的连接条件