蔚来挂机问题?

发布于 2024-12-15 07:19:58 字数 3267 浏览 6 评论 0原文

我在使用 NIO 框架通过主机和客户端之间的 SocketChannels 发送数据时遇到问题。

我以前从来没有真正费心去学习 NIO,但是随着 java.nio.files 包的引入和其他各种改进,我想我应该尝试一下。

我能够使 SocketChannel 和 ServerSocketChannel 正常连接,但实际的数据传输行为非常奇怪。它永远不会在客户端正确完成,总是在最终读取后挂起。此外,它有时会读取不正确的数据量(太多或太少),甚至导致 Windows 资源管理器变得疯狂并分配所有系统内存,从而导致计算机崩溃。

这是我现在拥有的代码(这是测试代码):

package bg.jdk7.io;

import static java.nio.file.StandardOpenOption.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class NetIO {

static volatile long filesize;

public static void main(String[] args) {
    new Thread(new Client()).start();
    try {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(5555));
        SocketChannel sc = ssc.accept();
        if(sc.isConnected()) {
            ByteBuffer buff = ByteBuffer.allocate(10240);
            Path fp = Paths.get(System.getProperty("user.home")+"\\Documents\\clip0025.avi");
            if(Files.exists(fp)) {
                FileChannel fc = (FileChannel) Files.newByteChannel(fp, StandardOpenOption.READ);
                long tot = Files.size(fp);
                long run = 0;
                int read = 0;
                int prog = 0;
                while((read = fc.read(buff))>0) {
                    buff.rewind();
                    sc.write(buff);
                    run+=buff.position();
                    int last = prog;
                    prog = (int)(((double)run/tot)*100);
                    if(prog !=last) {
                        System.out.println(prog + "%");
                    }
                    buff.flip();
                }
                fc.close();
                System.out.println("Sending completed");
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

static class Client implements Runnable {

    public void run() {
        try {
            SocketChannel sc = SocketChannel.open();
            sc.connect(new InetSocketAddress("localhost",5555));
            if(sc.isConnected()) {
                Path dpf = Paths.get("\\NIO_TESTING\\");
                Path dp = Paths.get(dpf+"\\clip.avi");
                Files.createDirectories(dpf);
                FileChannel fc = (FileChannel)  Files.newByteChannel(dp, CREATE, WRITE, TRUNCATE_EXISTING);
                ByteBuffer buff = ByteBuffer.allocate(10240);
                int read;
                int total = 0;
                while((read = sc.read(buff))>0) {
                    total+=read;
                    buff.rewind();
                    fc.write(buff);
                    System.out.println(fc.size());
                    buff.flip();
                    if(total == filesize) System.out.println("File data received successfully...");
                }
                System.out.println("Completed successfully");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

I'm having problems with sending data over SocketChannels between a Host and Client using the NIO framework.

I've never really bothered to learn NIO before now, but with the introduction of the java.nio.files package and other various improvements I thought I would give it a try.

I'm able to get the SocketChannel and ServerSocketChannel to connect fine, but the actual data transfer is acting very weird. It NEVER finishes correctly on the Client side, always hanging up after the final read. Furthermore, it sometimes reads the incorrect amount of data (too much or too little) and has even caused Windows Explorer to go crazy and allocate literally ALL of the system's memory, crashing the computer.

Here is the code (it is test code) I have right now:

package bg.jdk7.io;

import static java.nio.file.StandardOpenOption.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class NetIO {

static volatile long filesize;

public static void main(String[] args) {
    new Thread(new Client()).start();
    try {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(5555));
        SocketChannel sc = ssc.accept();
        if(sc.isConnected()) {
            ByteBuffer buff = ByteBuffer.allocate(10240);
            Path fp = Paths.get(System.getProperty("user.home")+"\\Documents\\clip0025.avi");
            if(Files.exists(fp)) {
                FileChannel fc = (FileChannel) Files.newByteChannel(fp, StandardOpenOption.READ);
                long tot = Files.size(fp);
                long run = 0;
                int read = 0;
                int prog = 0;
                while((read = fc.read(buff))>0) {
                    buff.rewind();
                    sc.write(buff);
                    run+=buff.position();
                    int last = prog;
                    prog = (int)(((double)run/tot)*100);
                    if(prog !=last) {
                        System.out.println(prog + "%");
                    }
                    buff.flip();
                }
                fc.close();
                System.out.println("Sending completed");
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

static class Client implements Runnable {

    public void run() {
        try {
            SocketChannel sc = SocketChannel.open();
            sc.connect(new InetSocketAddress("localhost",5555));
            if(sc.isConnected()) {
                Path dpf = Paths.get("\\NIO_TESTING\\");
                Path dp = Paths.get(dpf+"\\clip.avi");
                Files.createDirectories(dpf);
                FileChannel fc = (FileChannel)  Files.newByteChannel(dp, CREATE, WRITE, TRUNCATE_EXISTING);
                ByteBuffer buff = ByteBuffer.allocate(10240);
                int read;
                int total = 0;
                while((read = sc.read(buff))>0) {
                    total+=read;
                    buff.rewind();
                    fc.write(buff);
                    System.out.println(fc.size());
                    buff.flip();
                    if(total == filesize) System.out.println("File data received successfully...");
                }
                System.out.println("Completed successfully");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

瘫痪情歌 2024-12-22 07:19:58

ServerSocketChannel.accept() 生成的 SocketChannel 已连接。不可能是这样。 isConnected() 测试毫无意义。

您的服务器 I/O 代码不正确。通道写入必须在 buffer.flip() 之前,然后是 buffer.compact()。 从一个通道复制到另一个通道的规范方法如下(请注意,即使缓冲区中仍有挂起的数据,这在 EOS 上也能正确运行):

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

与我的第一段类似,由 SocketChannel.open() 产生的 SocketChannel ,后跟SocketChannel.connect() 已连接:同样,测试毫无意义。如果未连接,connect() 调用上就会出现 ConnectException

您的客户端 I/O 代码与服务器 I/O 代码存在相同的问题。

您不会关闭服务器中的 SocketChannel,因此客户端永远不会停止从连接中读取数据。

您也没有关闭客户端中的SocketChannel

File.exists() 测试毫无意义。如果文件不存在,下面的行将抛出异常,并且您无论如何都必须处理该异常,那么为什么还要再次执行呢?

A SocketChannel resulting from ServerSocketChannel.accept() is connected. There is no way it can't be. The isConnected() test is pointless.

Your server I/O code is incorrect. Channel writes must be preceded by buffer.flip() and followed by buffer.compact(). The canonical way to copy from one channel to another is as follows (note that this behaves correctly at EOS even when there is pending data still in the buffer):

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

Similarly to my first paragraph, a SocketChannel resulting from SocketChannel.open() followed by SocketChannel.connect() is connected: again, the test is pointless. If it wasn't connected there would have been a ConnectException on the connect() call.

Your client I/O code has the same problems as your server I/O code.

You aren't closing the SocketChannel in the server, so the client will never stop reading from the connection.

You aren't closing the SocketChannel in the client either.

The File.exists() test is pointless. The following line will throw an exception if the file isn't there, and you have to handle that exception anyway, so why do it all again?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文